summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md7
-rw-r--r--apps/files/lib/Controller/ApiController.php23
-rw-r--r--apps/files/tests/Controller/ApiControllerTest.php45
-rw-r--r--apps/files_sharing/ajax/publicpreview.php126
-rw-r--r--apps/files_sharing/appinfo/routes.php18
-rw-r--r--apps/files_sharing/lib/Controller/PublicPreviewController.php102
-rw-r--r--apps/files_sharing/tests/Controller/PublicPreviewControllerTest.php193
-rw-r--r--apps/files_trashbin/ajax/preview.php80
-rw-r--r--apps/files_trashbin/appinfo/routes.php12
-rw-r--r--apps/files_trashbin/lib/Controller/PreviewController.php119
-rw-r--r--apps/files_trashbin/tests/Controller/PreviewControllerTest.php181
-rw-r--r--apps/files_versions/ajax/preview.php66
-rw-r--r--apps/files_versions/appinfo/routes.php15
-rw-r--r--apps/files_versions/lib/Controller/PreviewController.php99
-rw-r--r--apps/files_versions/lib/Storage.php2
-rw-r--r--apps/files_versions/tests/Controller/PreviewControllerTest.php167
-rw-r--r--core/Controller/PreviewController.php132
-rw-r--r--core/ajax/preview.php67
-rw-r--r--core/routes.php6
-rw-r--r--lib/composer/composer/autoload_classmap.php5
-rw-r--r--lib/composer/composer/autoload_static.php5
-rw-r--r--lib/private/Preview.php2
-rw-r--r--lib/private/Preview/Generator.php338
-rw-r--r--lib/private/Preview/GeneratorHelper.php91
-rw-r--r--lib/private/Preview/Watcher.php98
-rw-r--r--lib/private/Preview/WatcherConnector.php72
-rw-r--r--lib/private/PreviewManager.php56
-rw-r--r--lib/private/Server.php16
-rw-r--r--lib/public/IPreview.php26
-rw-r--r--tests/Core/Controller/PreviewControllerTest.php226
-rw-r--r--tests/lib/Preview/GeneratorTest.php338
-rw-r--r--tests/lib/UrlGeneratorTest.php2
32 files changed, 2353 insertions, 382 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 04d71c6ffcb..c481b7cc110 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,3 +6,10 @@ NC 11 (????-??-??)
* PHP 5.4 and 5.5 no longer supported
* PHP 7.1 support
* OC_L10N removed use \OCP\IL10N (#1948)
+* Preview handling is improved by sharing previews:
+ * Preview sharing (shared files/external storages)
+ * Previews are stored in the AppData
+ * Previews are served faster by not first converting them to image objects
+* Core preview route changed:
+ * Route for the urlgenerator changed from 'core_ajax_preview' to 'core.Preview.getPreview'
+ * $urlGenerator->linkToRoute('core_ajax_preview', ...) => $urlGenerator->linkToRoute('core.Preview.getPreview', ...)
diff --git a/apps/files/lib/Controller/ApiController.php b/apps/files/lib/Controller/ApiController.php
index 138b68601cb..790da4a184a 100644
--- a/apps/files/lib/Controller/ApiController.php
+++ b/apps/files/lib/Controller/ApiController.php
@@ -31,11 +31,13 @@ namespace OCA\Files\Controller;
use OCP\AppFramework\Http;
use OCP\AppFramework\Controller;
+use OCP\Files\File;
use OCP\Files\Folder;
+use OCP\Files\NotFoundException;
use OCP\IConfig;
use OCP\IRequest;
use OCP\AppFramework\Http\DataResponse;
-use OCP\AppFramework\Http\DataDisplayResponse;
+use OCP\AppFramework\Http\FileDisplayResponse;
use OCP\AppFramework\Http\Response;
use OCA\Files\Service\TagService;
use OCP\IPreview;
@@ -101,18 +103,27 @@ class ApiController extends Controller {
* @param int $x
* @param int $y
* @param string $file URL-encoded filename
- * @return DataResponse|DataDisplayResponse
+ * @return DataResponse|FileDisplayResponse
*/
public function getThumbnail($x, $y, $file) {
if($x < 1 || $y < 1) {
return new DataResponse(['message' => 'Requested size must be numeric and a positive value.'], Http::STATUS_BAD_REQUEST);
}
- $preview = $this->previewManager->createPreview('files/'.$file, $x, $y, true);
- if ($preview->valid()) {
- return new DataDisplayResponse($preview->data(), Http::STATUS_OK, ['Content-Type' => 'image/png']);
- } else {
+ try {
+ $file = $this->userFolder->get($file);
+ if ($file instanceof Folder) {
+ throw new NotFoundException();
+ }
+
+ /** @var File $file */
+ $preview = $this->previewManager->getPreview($file, $x, $y, true);
+
+ return new FileDisplayResponse($preview, Http::STATUS_OK, ['Content-Type' => $preview->getMimeType()]);
+ } catch (NotFoundException $e) {
return new DataResponse(['message' => 'File not found.'], Http::STATUS_NOT_FOUND);
+ } catch (\Exception $e) {
+ return new DataResponse([], Http::STATUS_BAD_REQUEST);
}
}
diff --git a/apps/files/tests/Controller/ApiControllerTest.php b/apps/files/tests/Controller/ApiControllerTest.php
index 4b7bec065a0..56d0f6c8dee 100644
--- a/apps/files/tests/Controller/ApiControllerTest.php
+++ b/apps/files/tests/Controller/ApiControllerTest.php
@@ -28,11 +28,15 @@ namespace OCA\Files\Controller;
use OC\Files\FileInfo;
use OCP\AppFramework\Http;
+use OCP\Files\File;
+use OCP\Files\Folder;
use OCP\Files\NotFoundException;
+use OCP\Files\SimpleFS\ISimpleFile;
use OCP\Files\StorageNotAvailableException;
use OCP\IConfig;
use OCP\IUser;
use OCP\IUserSession;
+use OCP\Share\IManager;
use Test\TestCase;
use OCP\IRequest;
use OCA\Files\Service\TagService;
@@ -54,7 +58,7 @@ class ApiControllerTest extends TestCase {
private $request;
/** @var TagService */
private $tagService;
- /** @var IPreview */
+ /** @var IPreview|\PHPUnit_Framework_MockObject_MockObject */
private $preview;
/** @var ApiController */
private $apiController;
@@ -62,11 +66,13 @@ class ApiControllerTest extends TestCase {
private $shareManager;
/** @var \OCP\IConfig */
private $config;
- /** @var \OC\Files\Node\Folder */
+ /** @var Folder|\PHPUnit_Framework_MockObject_MockObject */
private $userFolder;
public function setUp() {
- $this->request = $this->getMockBuilder('\OCP\IRequest')
+ parent::setUp();
+
+ $this->request = $this->getMockBuilder(IRequest::class)
->disableOriginalConstructor()
->getMock();
$this->user = $this->createMock(IUser::class);
@@ -77,17 +83,17 @@ class ApiControllerTest extends TestCase {
$userSession->expects($this->any())
->method('getUser')
->will($this->returnValue($this->user));
- $this->tagService = $this->getMockBuilder('\OCA\Files\Service\TagService')
+ $this->tagService = $this->getMockBuilder(TagService::class)
->disableOriginalConstructor()
->getMock();
- $this->shareManager = $this->getMockBuilder('\OCP\Share\IManager')
+ $this->shareManager = $this->getMockBuilder(IManager::class)
->disableOriginalConstructor()
->getMock();
- $this->preview = $this->getMockBuilder('\OCP\IPreview')
+ $this->preview = $this->getMockBuilder(IPreview::class)
->disableOriginalConstructor()
->getMock();
$this->config = $this->createMock(IConfig::class);
- $this->userFolder = $this->getMockBuilder('\OC\Files\Node\Folder')
+ $this->userFolder = $this->getMockBuilder(Folder::class)
->disableOriginalConstructor()
->getMock();
@@ -153,28 +159,41 @@ class ApiControllerTest extends TestCase {
}
public function testGetThumbnailInvalidSize() {
+ $this->userFolder->method('get')
+ ->with($this->equalTo(''))
+ ->willThrowException(new NotFoundException());
$expected = new DataResponse(['message' => 'Requested size must be numeric and a positive value.'], Http::STATUS_BAD_REQUEST);
$this->assertEquals($expected, $this->apiController->getThumbnail(0, 0, ''));
}
public function testGetThumbnailInvaidImage() {
+ $file = $this->createMock(File::class);
+ $this->userFolder->method('get')
+ ->with($this->equalTo('unknown.jpg'))
+ ->willReturn($file);
$this->preview->expects($this->once())
- ->method('createPreview')
- ->with('files/unknown.jpg', 10, 10, true)
- ->willReturn(new Image);
+ ->method('getPreview')
+ ->with($file, 10, 10, true)
+ ->willThrowException(new NotFoundException());
$expected = new DataResponse(['message' => 'File not found.'], Http::STATUS_NOT_FOUND);
$this->assertEquals($expected, $this->apiController->getThumbnail(10, 10, 'unknown.jpg'));
}
public function testGetThumbnail() {
+ $file = $this->createMock(File::class);
+ $this->userFolder->method('get')
+ ->with($this->equalTo('known.jpg'))
+ ->willReturn($file);
+ $preview = $this->createMock(ISimpleFile::class);
$this->preview->expects($this->once())
- ->method('createPreview')
- ->with('files/known.jpg', 10, 10, true)
- ->willReturn(new Image(\OC::$SERVERROOT.'/tests/data/testimage.jpg'));
+ ->method('getPreview')
+ ->with($this->equalTo($file), 10, 10, true)
+ ->willReturn($preview);
$ret = $this->apiController->getThumbnail(10, 10, 'known.jpg');
$this->assertEquals(Http::STATUS_OK, $ret->getStatus());
+ $this->assertInstanceOf(Http\FileDisplayResponse::class, $ret);
}
public function testUpdateFileSorting() {
diff --git a/apps/files_sharing/ajax/publicpreview.php b/apps/files_sharing/ajax/publicpreview.php
deleted file mode 100644
index 4c60f9c20ca..00000000000
--- a/apps/files_sharing/ajax/publicpreview.php
+++ /dev/null
@@ -1,126 +0,0 @@
-<?php
-/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Björn Schießle <bjoern@schiessle.org>
- * @author Georg Ehrke <georg@owncloud.com>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- *
- * @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 <http://www.gnu.org/licenses/>
- *
- */
-
-OCP\JSON::checkAppEnabled('files_sharing');
-
-\OC_User::setIncognitoMode(true);
-
-$file = array_key_exists('file', $_GET) ? (string) $_GET['file'] : '';
-$maxX = array_key_exists('x', $_GET) ? (int) $_GET['x'] : '32';
-$maxY = array_key_exists('y', $_GET) ? (int) $_GET['y'] : '32';
-$scalingUp = array_key_exists('scalingup', $_GET) ? (bool) $_GET['scalingup'] : true;
-$token = array_key_exists('t', $_GET) ? (string) $_GET['t'] : '';
-$keepAspect = array_key_exists('a', $_GET) ? true : false;
-
-if($token === ''){
- \OC_Response::setStatus(\OC_Response::STATUS_BAD_REQUEST);
- \OCP\Util::writeLog('core-preview', 'No token parameter was passed', \OCP\Util::DEBUG);
- exit;
-}
-
-$linkedItem = \OCP\Share::getShareByToken($token);
-$shareManager = \OC::$server->getShareManager();
-$share = $shareManager->getShareByToken($token);
-if(!($share->getPermissions() & \OCP\Constants::PERMISSION_READ)) {
- OCP\JSON::error(array('data' => 'Share is not readable.'));
- exit();
-}
-
-if($linkedItem === false || ($linkedItem['item_type'] !== 'file' && $linkedItem['item_type'] !== 'folder')) {
- \OC_Response::setStatus(\OC_Response::STATUS_NOT_FOUND);
- \OCP\Util::writeLog('core-preview', 'Passed token parameter is not valid', \OCP\Util::DEBUG);
- exit;
-}
-
-if(!isset($linkedItem['uid_owner']) || !isset($linkedItem['file_source'])) {
- \OC_Response::setStatus(\OC_Response::STATUS_INTERNAL_SERVER_ERROR);
- \OCP\Util::writeLog('core-preview', 'Passed token seems to be valid, but it does not contain all necessary information . ("' . $token . '")', \OCP\Util::WARN);
- exit;
-}
-
-$rootLinkItem = OCP\Share::resolveReShare($linkedItem);
-$userId = $rootLinkItem['uid_owner'];
-
-OCP\JSON::checkUserExists($rootLinkItem['uid_owner']);
-\OC_Util::setupFS($userId);
-\OC\Files\Filesystem::initMountPoints($userId);
-$view = new \OC\Files\View('/' . $userId . '/files');
-
-$pathId = $linkedItem['file_source'];
-$path = $view->getPath($pathId);
-
-if($path === null) {
- \OC_Response::setStatus(\OC_Response::STATUS_NOT_FOUND);
- \OCP\Util::writeLog('core-preview', 'Could not resolve file for shared item', \OCP\Util::WARN);
- exit;
-}
-
-$pathInfo = $view->getFileInfo($path);
-$sharedFile = null;
-
-if($linkedItem['item_type'] === 'folder') {
- $isValid = \OC\Files\Filesystem::isValidPath($file);
- if(!$isValid) {
- \OC_Response::setStatus(\OC_Response::STATUS_BAD_REQUEST);
- \OCP\Util::writeLog('core-preview', 'Passed filename is not valid, might be malicious (file:"' . $file . '";ip:"' . \OC::$server->getRequest()->getRemoteAddress() . '")', \OCP\Util::WARN);
- exit;
- }
- $sharedFile = \OC\Files\Filesystem::normalizePath($file);
-}
-
-if($linkedItem['item_type'] === 'file') {
- $parent = $pathInfo['parent'];
- $path = $view->getPath($parent);
- $sharedFile = $pathInfo['name'];
-}
-
-$path = \OC\Files\Filesystem::normalizePath($path, false);
-if(substr($path, 0, 1) === '/') {
- $path = substr($path, 1);
-}
-
-if($maxX === 0 || $maxY === 0) {
- \OC_Response::setStatus(\OC_Response::STATUS_BAD_REQUEST);
- \OCP\Util::writeLog('core-preview', 'x and/or y set to 0', \OCP\Util::DEBUG);
- exit;
-}
-
-$root = 'files/' . $path;
-
-try{
- $preview = new \OC\Preview($userId, $root);
- $preview->setFile($sharedFile);
- $preview->setMaxX($maxX);
- $preview->setMaxY($maxY);
- $preview->setScalingUp($scalingUp);
- $preview->setKeepAspect($keepAspect);
-
- $preview->showPreview();
-} catch (\Exception $e) {
- \OC_Response::setStatus(\OC_Response::STATUS_INTERNAL_SERVER_ERROR);
- \OCP\Util::writeLog('core', $e->getmessage(), \OCP\Util::DEBUG);
-}
diff --git a/apps/files_sharing/appinfo/routes.php b/apps/files_sharing/appinfo/routes.php
index 267e53829da..439d46253d4 100644
--- a/apps/files_sharing/appinfo/routes.php
+++ b/apps/files_sharing/appinfo/routes.php
@@ -39,6 +39,17 @@ $application->registerRoutes($this, [
'url' => '/testremote',
'verb' => 'GET'
],
+ [
+ 'name' => 'PublicPreview#getPreview',
+ 'url' => '/publicpreview',
+ 'verb' => 'GET',
+ ],
+
+ [
+ 'name' => 'PublicPreview#getPreview',
+ 'url' => '/ajax/publicpreview.php',
+ 'verb' => 'GET',
+ ],
],
'ocs' => [
/*
@@ -114,15 +125,8 @@ $application->registerRoutes($this, [
]);
/** @var $this \OCP\Route\IRouter */
-$this->create('core_ajax_public_preview', '/publicpreview')->action(
- function() {
- require_once __DIR__ . '/../ajax/publicpreview.php';
- });
-
$this->create('files_sharing_ajax_list', 'ajax/list.php')
->actionInclude('files_sharing/ajax/list.php');
-$this->create('files_sharing_ajax_publicpreview', 'ajax/publicpreview.php')
- ->actionInclude('files_sharing/ajax/publicpreview.php');
$this->create('sharing_external_shareinfo', '/shareinfo')
->actionInclude('files_sharing/ajax/shareinfo.php');
diff --git a/apps/files_sharing/lib/Controller/PublicPreviewController.php b/apps/files_sharing/lib/Controller/PublicPreviewController.php
new file mode 100644
index 00000000000..b91b84c9c34
--- /dev/null
+++ b/apps/files_sharing/lib/Controller/PublicPreviewController.php
@@ -0,0 +1,102 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016, Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCA\Files_Sharing\Controller;
+
+use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\DataResponse;
+use OCP\AppFramework\Http\FileDisplayResponse;
+use OCP\Constants;
+use OCP\Files\Folder;
+use OCP\Files\NotFoundException;
+use OCP\IPreview;
+use OCP\IRequest;
+use OCP\Share\Exceptions\ShareNotFound;
+use OCP\Share\IManager as ShareManager;
+
+class PublicPreviewController extends Controller {
+
+ /** @var ShareManager */
+ private $shareManager;
+
+ /** @var IPreview */
+ private $previewManager;
+
+ public function __construct($appName,
+ IRequest $request,
+ ShareManager $shareManger,
+ IPreview $previewManager) {
+ parent::__construct($appName, $request);
+
+ $this->shareManager = $shareManger;
+ $this->previewManager = $previewManager;
+ }
+
+ /**
+ * @PublicPage
+ * @NoCSRFRequired
+ *
+ * @param string $file
+ * @param int $x
+ * @param int $y
+ * @param string $t
+ * @param bool $a
+ * @return DataResponse|FileDisplayResponse
+ */
+ public function getPreview(
+ $file = '',
+ $x = 32,
+ $y = 32,
+ $t = '',
+ $a = false
+ ) {
+
+ if ($t === '' || $x === 0 || $y === 0) {
+ return new DataResponse([], Http::STATUS_BAD_REQUEST);
+ }
+
+ try {
+ $share = $this->shareManager->getShareByToken($t);
+ } catch (ShareNotFound $e) {
+ return new DataResponse([], Http::STATUS_NOT_FOUND);
+ }
+
+ if (($share->getPermissions() & Constants::PERMISSION_READ) === 0) {
+ return new DataResponse([], Http::STATUS_FORBIDDEN);
+ }
+
+ try {
+ $node = $share->getNode();
+ if ($node instanceof Folder) {
+ $file = $node->get($file);
+ } else {
+ $file = $node;
+ }
+
+ $f = $this->previewManager->getPreview($file, $x, $y, !$a);
+ return new FileDisplayResponse($f, Http::STATUS_OK, ['Content-Type' => $f->getMimeType()]);
+ } catch (NotFoundException $e) {
+ return new DataResponse([], Http::STATUS_NOT_FOUND);
+ }
+ }
+}
diff --git a/apps/files_sharing/tests/Controller/PublicPreviewControllerTest.php b/apps/files_sharing/tests/Controller/PublicPreviewControllerTest.php
new file mode 100644
index 00000000000..174abbb6f60
--- /dev/null
+++ b/apps/files_sharing/tests/Controller/PublicPreviewControllerTest.php
@@ -0,0 +1,193 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016, Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCA\Files_Sharing\Tests\Controller;
+
+use OCA\Files_Sharing\Controller\PublicPreviewController;
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\DataResponse;
+use OCP\AppFramework\Http\FileDisplayResponse;
+use OCP\Constants;
+use OCP\Files\File;
+use OCP\Files\Folder;
+use OCP\Files\NotFoundException;
+use OCP\Files\SimpleFS\ISimpleFile;
+use OCP\IPreview;
+use OCP\IRequest;
+use OCP\Share\Exceptions\ShareNotFound;
+use OCP\Share\IManager;
+use OCP\Share\IShare;
+use Punic\Data;
+use Test\TestCase;
+
+class PublicPreviewControllerTest extends TestCase {
+
+ /** @var IPreview|\PHPUnit_Framework_MockObject_MockObject */
+ private $previewManager;
+
+ /** @var IManager|\PHPUnit_Framework_MockObject_MockObject */
+ private $shareManager;
+
+ /** @var PublicPreviewController */
+ private $controller;
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->previewManager = $this->createMock(IPreview::class);
+ $this->shareManager = $this->createMock(IManager::class);
+
+ $this->controller = new PublicPreviewController(
+ 'files_sharing',
+ $this->createMock(IRequest::class),
+ $this->shareManager,
+ $this->previewManager
+ );
+ }
+
+ public function testInvalidToken() {
+ $res = $this->controller->getPreview('file', 10, 10, '');
+ $expected = new DataResponse([], Http::STATUS_BAD_REQUEST);
+
+ $this->assertEquals($expected, $res);
+ }
+
+ public function testInvalidWidth() {
+ $res = $this->controller->getPreview('file', 0);
+ $expected = new DataResponse([], Http::STATUS_BAD_REQUEST);
+
+ $this->assertEquals($expected, $res);
+ }
+
+ public function testInvalidHeight() {
+ $res = $this->controller->getPreview('file', 10, 0);
+ $expected = new DataResponse([], Http::STATUS_BAD_REQUEST);
+
+ $this->assertEquals($expected, $res);
+ }
+
+ public function testInvalidShare() {
+ $this->shareManager->method('getShareByToken')
+ ->with($this->equalTo('token'))
+ ->willThrowException(new ShareNotFound());
+
+ $res = $this->controller->getPreview('file', 10, 10, 'token');
+ $expected = new DataResponse([], Http::STATUS_NOT_FOUND);
+
+ $this->assertEquals($expected, $res);
+ }
+
+ public function testShareNotAccessable() {
+ $share = $this->createMock(IShare::class);
+ $this->shareManager->method('getShareByToken')
+ ->with($this->equalTo('token'))
+ ->willReturn($share);
+
+ $share->method('getPermissions')
+ ->willReturn(0);
+
+ $res = $this->controller->getPreview('file', 10, 10, 'token');
+ $expected = new DataResponse([], Http::STATUS_FORBIDDEN);
+
+ $this->assertEquals($expected, $res);
+ }
+
+ public function testPreviewFile() {
+ $share = $this->createMock(IShare::class);
+ $this->shareManager->method('getShareByToken')
+ ->with($this->equalTo('token'))
+ ->willReturn($share);
+
+ $share->method('getPermissions')
+ ->willReturn(Constants::PERMISSION_READ);
+
+ $file = $this->createMock(File::class);
+ $share->method('getNode')
+ ->willReturn($file);
+
+ $preview = $this->createMock(ISimpleFile::class);
+ $this->previewManager->method('getPreview')
+ ->with($this->equalTo($file), 10, 10, false)
+ ->willReturn($preview);
+
+ $preview->method('getMimeType')
+ ->willReturn('myMime');
+
+ $res = $this->controller->getPreview('file', 10, 10, 'token', true);
+ $expected = new FileDisplayResponse($preview, Http::STATUS_OK, ['Content-Type' => 'myMime']);
+ $this->assertEquals($expected, $res);
+ }
+
+ public function testPreviewFolderInvalidFile() {
+ $share = $this->createMock(IShare::class);
+ $this->shareManager->method('getShareByToken')
+ ->with($this->equalTo('token'))
+ ->willReturn($share);
+
+ $share->method('getPermissions')
+ ->willReturn(Constants::PERMISSION_READ);
+
+ $folder = $this->createMock(Folder::class);
+ $share->method('getNode')
+ ->willReturn($folder);
+
+ $folder->method('get')
+ ->with($this->equalTo('file'))
+ ->willThrowException(new NotFoundException());
+
+ $res = $this->controller->getPreview('file', 10, 10, 'token', true);
+ $expected = new DataResponse([], Http::STATUS_NOT_FOUND);
+ $this->assertEquals($expected, $res);
+ }
+
+
+ public function testPreviewFolderValidFile() {
+ $share = $this->createMock(IShare::class);
+ $this->shareManager->method('getShareByToken')
+ ->with($this->equalTo('token'))
+ ->willReturn($share);
+
+ $share->method('getPermissions')
+ ->willReturn(Constants::PERMISSION_READ);
+
+ $folder = $this->createMock(Folder::class);
+ $share->method('getNode')
+ ->willReturn($folder);
+
+ $file = $this->createMock(File::class);
+ $folder->method('get')
+ ->with($this->equalTo('file'))
+ ->willReturn($file);
+
+ $preview = $this->createMock(ISimpleFile::class);
+ $this->previewManager->method('getPreview')
+ ->with($this->equalTo($file), 10, 10, false)
+ ->willReturn($preview);
+
+ $preview->method('getMimeType')
+ ->willReturn('myMime');
+
+ $res = $this->controller->getPreview('file', 10, 10, 'token', true);
+ $expected = new FileDisplayResponse($preview, Http::STATUS_OK, ['Content-Type' => 'myMime']);
+ $this->assertEquals($expected, $res);
+ }
+}
diff --git a/apps/files_trashbin/ajax/preview.php b/apps/files_trashbin/ajax/preview.php
deleted file mode 100644
index 3f895161f00..00000000000
--- a/apps/files_trashbin/ajax/preview.php
+++ /dev/null
@@ -1,80 +0,0 @@
-<?php
-/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Björn Schießle <bjoern@schiessle.org>
- * @author Georg Ehrke <georg@owncloud.com>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @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 <http://www.gnu.org/licenses/>
- *
- */
-\OC_Util::checkLoggedIn();
-\OC::$server->getSession()->close();
-
-if(!\OC_App::isEnabled('files_trashbin')){
- exit;
-}
-
-$file = array_key_exists('file', $_GET) ? (string) $_GET['file'] : '';
-$maxX = array_key_exists('x', $_GET) ? (int) $_GET['x'] : '44';
-$maxY = array_key_exists('y', $_GET) ? (int) $_GET['y'] : '44';
-$scalingUp = array_key_exists('scalingup', $_GET) ? (bool) $_GET['scalingup'] : true;
-
-if($file === '') {
- \OC_Response::setStatus(400); //400 Bad Request
- \OCP\Util::writeLog('core-preview', 'No file parameter was passed', \OCP\Util::DEBUG);
- exit;
-}
-
-if($maxX === 0 || $maxY === 0) {
- \OC_Response::setStatus(400); //400 Bad Request
- \OCP\Util::writeLog('core-preview', 'x and/or y set to 0', \OCP\Util::DEBUG);
- exit;
-}
-
-try{
- $preview = new \OC\Preview(\OC_User::getUser(), 'files_trashbin/files', $file);
- $view = new \OC\Files\View('/'.\OC_User::getUser(). '/files_trashbin/files');
- if ($view->is_dir($file)) {
- $mimetype = 'httpd/unix-directory';
- } else {
- $pathInfo = pathinfo(ltrim($file, '/'));
- $fileName = $pathInfo['basename'];
- // if in root dir
- if ($pathInfo['dirname'] === '.') {
- // cut off the .d* suffix
- $i = strrpos($fileName, '.');
- if ($i !== false) {
- $fileName = substr($fileName, 0, $i);
- }
- }
- $mimetype = \OC::$server->getMimeTypeDetector()->detectPath($fileName);
- }
- $preview->setMimetype($mimetype);
- $preview->setMaxX($maxX);
- $preview->setMaxY($maxY);
- $preview->setScalingUp($scalingUp);
-
- $preview->showPreview();
-} catch (\OC\PreviewNotAvailableException $e) {
- \OC_Response::setStatus(404);
-}catch(\Exception $e) {
- \OC_Response::setStatus(500);
- \OCP\Util::writeLog('core', $e->getmessage(), \OCP\Util::DEBUG);
-}
diff --git a/apps/files_trashbin/appinfo/routes.php b/apps/files_trashbin/appinfo/routes.php
index 2f4988c9dcc..5241bec742e 100644
--- a/apps/files_trashbin/appinfo/routes.php
+++ b/apps/files_trashbin/appinfo/routes.php
@@ -1,6 +1,7 @@
<?php
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, Roeland Jago Douma <roeland@famdouma.nl>
*
* @author Lukas Reschke <lukas@statuscode.ch>
* @author Roeland Jago Douma <roeland@famdouma.nl>
@@ -25,9 +26,16 @@
namespace OCA\Files_Trashbin\AppInfo;
$application = new Application();
+$application->registerRoutes($this, [
+ 'routes' => [
+ [
+ 'name' => 'Preview#getPreview',
+ 'url' => '/ajax/preview.php',
+ 'verb' => 'GET',
+ ],
+ ],
+]);
-$this->create('core_ajax_trashbin_preview', 'ajax/preview.php')
- ->actionInclude('files_trashbin/ajax/preview.php');
$this->create('files_trashbin_ajax_delete', 'ajax/delete.php')
->actionInclude('files_trashbin/ajax/delete.php');
$this->create('files_trashbin_ajax_isEmpty', 'ajax/isEmpty.php')
diff --git a/apps/files_trashbin/lib/Controller/PreviewController.php b/apps/files_trashbin/lib/Controller/PreviewController.php
new file mode 100644
index 00000000000..c73b1c17c16
--- /dev/null
+++ b/apps/files_trashbin/lib/Controller/PreviewController.php
@@ -0,0 +1,119 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016, Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCA\Files_Trashbin\Controller;
+
+use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\DataResponse;
+use OCP\Files\File;
+use OCP\Files\Folder;
+use OCP\Files\IMimeTypeDetector;
+use OCP\Files\IRootFolder;
+use OCP\Files\NotFoundException;
+use OCP\IPreview;
+use OCP\IRequest;
+
+class PreviewController extends Controller {
+
+ /** @var IRootFolder */
+ private $rootFolder;
+
+ /** @var string */
+ private $userId;
+
+ /** @var IMimeTypeDetector */
+ private $mimeTypeDetector;
+
+ /** @var IPreview */
+ private $previewManager;
+
+ /**
+ * @param string $appName
+ * @param IRequest $request
+ * @param IRootFolder $rootFolder
+ * @param $userId
+ * @param IMimeTypeDetector $mimeTypeDetector
+ * @param IPreview $previewManager
+ */
+ public function __construct($appName,
+ IRequest $request,
+ IRootFolder $rootFolder,
+ $userId,
+ IMimeTypeDetector $mimeTypeDetector,
+ IPreview $previewManager) {
+ parent::__construct($appName, $request);
+
+ $this->rootFolder = $rootFolder;
+ $this->userId = $userId;
+ $this->mimeTypeDetector = $mimeTypeDetector;
+ $this->previewManager = $previewManager;
+ }
+
+ /**
+ * @NoAdminRequired
+ * @NoCSRFRequired
+ *
+ * @param string $file
+ * @param int $x
+ * @param int $y
+ * @return DataResponse|Http\FileDisplayResponse
+ */
+ public function getPreview(
+ $file = '',
+ $x = 44,
+ $y = 44
+ ) {
+ if ($file === '') {
+ return new DataResponse([], Http::STATUS_BAD_REQUEST);
+ }
+
+ if ($x === 0 || $y === 0) {
+ return new DataResponse([], Http::STATUS_BAD_REQUEST);
+ }
+
+ try {
+ $userFolder = $this->rootFolder->getUserFolder($this->userId);
+ /** @var Folder $trash */
+ $trash = $userFolder->getParent()->get('files_trashbin/files');
+ $trashFile = $trash->get($file);
+
+ if ($trashFile instanceof Folder) {
+ return new DataResponse([], Http::STATUS_BAD_REQUEST);
+ }
+
+ /** @var File $trashFile */
+ $fileName = $trashFile->getName();
+ $i = strrpos($fileName, '.');
+ if ($i !== false) {
+ $fileName = substr($fileName, 0, $i);
+ }
+
+ $mimeType = $this->mimeTypeDetector->detectPath($fileName);
+
+ $f = $this->previewManager->getPreview($trashFile, $x, $y, true, IPreview::MODE_FILL, $mimeType);
+ return new Http\FileDisplayResponse($f, Http::STATUS_OK, ['Content-Type' => $f->getMimeType()]);
+ } catch (NotFoundException $e) {
+ return new DataResponse([], Http::STATUS_NOT_FOUND);
+ }
+ }
+}
diff --git a/apps/files_trashbin/tests/Controller/PreviewControllerTest.php b/apps/files_trashbin/tests/Controller/PreviewControllerTest.php
new file mode 100644
index 00000000000..685e4cebfd1
--- /dev/null
+++ b/apps/files_trashbin/tests/Controller/PreviewControllerTest.php
@@ -0,0 +1,181 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016, Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCA\Files_Trashbin\Tests\Controller;
+
+use OCA\Files_Trashbin\Controller\PreviewController;
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\DataResponse;
+use OCP\AppFramework\Http\FileDisplayResponse;
+use OCP\Files\File;
+use OCP\Files\Folder;
+use OCP\Files\IMimeTypeDetector;
+use OCP\Files\IRootFolder;
+use OCP\Files\NotFoundException;
+use OCP\Files\SimpleFS\ISimpleFile;
+use OCP\IPreview;
+use OCP\IRequest;
+use Test\TestCase;
+
+class PreviewControllerTest extends TestCase {
+
+ /** @var IRootFolder|\PHPUnit_Framework_MockObject_MockObject */
+ private $rootFolder;
+
+ /** @var string */
+ private $userId;
+
+ /** @var IMimeTypeDetector|\PHPUnit_Framework_MockObject_MockObject */
+ private $mimeTypeDetector;
+
+ /** @var IPreview|\PHPUnit_Framework_MockObject_MockObject */
+ private $previewManager;
+
+ /** @var PreviewController */
+ private $controller;
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->rootFolder = $this->createMock(IRootFolder::class);
+ $this->userId = 'user';
+ $this->mimeTypeDetector = $this->createMock(IMimeTypeDetector::class);
+ $this->previewManager = $this->createMock(IPreview::class);
+
+ $this->controller = new PreviewController(
+ 'files_versions',
+ $this->createMock(IRequest::class),
+ $this->rootFolder,
+ $this->userId,
+ $this->mimeTypeDetector,
+ $this->previewManager
+ );
+ }
+
+ public function testInvalidFile() {
+ $res = $this->controller->getPreview('');
+ $expected = new DataResponse([], Http::STATUS_BAD_REQUEST);
+
+ $this->assertEquals($expected, $res);
+ }
+
+ public function testInvalidWidth() {
+ $res = $this->controller->getPreview('file', 0);
+ $expected = new DataResponse([], Http::STATUS_BAD_REQUEST);
+
+ $this->assertEquals($expected, $res);
+ }
+
+ public function testInvalidHeight() {
+ $res = $this->controller->getPreview('file', 10, 0);
+ $expected = new DataResponse([], Http::STATUS_BAD_REQUEST);
+
+ $this->assertEquals($expected, $res);
+ }
+
+ public function testValidPreview() {
+ $userFolder = $this->createMock(Folder::class);
+ $userRoot = $this->createMock(Folder::class);
+ $trash = $this->createMock(Folder::class);
+
+ $this->rootFolder->method('getUserFolder')
+ ->with($this->userId)
+ ->willReturn($userFolder);
+ $userFolder->method('getParent')
+ ->willReturn($userRoot);
+ $userRoot->method('get')
+ ->with('files_trashbin/files')
+ ->willReturn($trash);
+
+ $this->mimeTypeDetector->method('detectPath')
+ ->with($this->equalTo('file'))
+ ->willReturn('myMime');
+
+ $file = $this->createMock(File::class);
+ $trash->method('get')
+ ->with($this->equalTo('file.1234'))
+ ->willReturn($file);
+ $file->method('getName')
+ ->willReturn('file.1234');
+
+ $preview = $this->createMock(ISimpleFile::class);
+ $this->previewManager->method('getPreview')
+ ->with($this->equalTo($file), 10, 10, true, IPreview::MODE_FILL, 'myMime')
+ ->willReturn($preview);
+ $preview->method('getMimeType')
+ ->willReturn('previewMime');
+
+ $res = $this->controller->getPreview('file.1234', 10, 10);
+ $expected = new FileDisplayResponse($preview, Http::STATUS_OK, ['Content-Type' => 'previewMime']);
+
+ $this->assertEquals($expected, $res);
+ }
+
+ public function testTrashFileNotFound() {
+ $userFolder = $this->createMock(Folder::class);
+ $userRoot = $this->createMock(Folder::class);
+ $trash = $this->createMock(Folder::class);
+
+ $this->rootFolder->method('getUserFolder')
+ ->with($this->userId)
+ ->willReturn($userFolder);
+ $userFolder->method('getParent')
+ ->willReturn($userRoot);
+ $userRoot->method('get')
+ ->with('files_trashbin/files')
+ ->willReturn($trash);
+
+ $trash->method('get')
+ ->with($this->equalTo('file.1234'))
+ ->willThrowException(new NotFoundException());
+
+ $res = $this->controller->getPreview('file.1234', 10, 10);
+ $expected = new DataResponse([], Http::STATUS_NOT_FOUND);
+
+ $this->assertEquals($expected, $res);
+ }
+
+ public function testTrashFolder() {
+ $userFolder = $this->createMock(Folder::class);
+ $userRoot = $this->createMock(Folder::class);
+ $trash = $this->createMock(Folder::class);
+
+ $this->rootFolder->method('getUserFolder')
+ ->with($this->userId)
+ ->willReturn($userFolder);
+ $userFolder->method('getParent')
+ ->willReturn($userRoot);
+ $userRoot->method('get')
+ ->with('files_trashbin/files')
+ ->willReturn($trash);
+
+ $folder = $this->createMock(Folder::class);
+ $trash->method('get')
+ ->with($this->equalTo('folder'))
+ ->willReturn($folder);
+
+ $res = $this->controller->getPreview('folder', 10, 10);
+ $expected = new DataResponse([], Http::STATUS_BAD_REQUEST);
+
+ $this->assertEquals($expected, $res);
+ }
+}
diff --git a/apps/files_versions/ajax/preview.php b/apps/files_versions/ajax/preview.php
deleted file mode 100644
index 78e830d7c8f..00000000000
--- a/apps/files_versions/ajax/preview.php
+++ /dev/null
@@ -1,66 +0,0 @@
-<?php
-/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Björn Schießle <bjoern@schiessle.org>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Roeland Jago Douma <roeland@famdouma.nl>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- * @author Vincent Petry <pvince81@owncloud.com>
- *
- * @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 <http://www.gnu.org/licenses/>
- *
- */
-\OC_Util::checkLoggedIn();
-
-if(!\OC_App::isEnabled('files_versions')){
- exit;
-}
-
-$file = array_key_exists('file', $_GET) ? (string) urldecode($_GET['file']) : '';
-$maxX = array_key_exists('x', $_GET) ? (int) $_GET['x'] : 44;
-$maxY = array_key_exists('y', $_GET) ? (int) $_GET['y'] : 44;
-$version = array_key_exists('version', $_GET) ? $_GET['version'] : '';
-$scalingUp = array_key_exists('scalingup', $_GET) ? (bool) $_GET['scalingup'] : true;
-
-if($file === '' && $version === '') {
- \OC_Response::setStatus(400); //400 Bad Request
- \OCP\Util::writeLog('versions-preview', 'No file parameter was passed', \OCP\Util::DEBUG);
- exit;
-}
-
-if($maxX === 0 || $maxY === 0) {
- \OC_Response::setStatus(400); //400 Bad Request
- \OCP\Util::writeLog('versions-preview', 'x and/or y set to 0', \OCP\Util::DEBUG);
- exit;
-}
-
-try {
- list($user, $file) = \OCA\Files_Versions\Storage::getUidAndFilename($file);
- $preview = new \OC\Preview($user, 'files_versions', $file.'.v'.$version);
- $mimetype = \OC::$server->getMimeTypeDetector()->detectPath($file);
- $preview->setMimetype($mimetype);
- $preview->setMaxX($maxX);
- $preview->setMaxY($maxY);
- $preview->setScalingUp($scalingUp);
-
- $preview->showPreview();
-} catch (\OCP\Files\NotFoundException $e) {
- \OC_Response::setStatus(404);
- \OCP\Util::writeLog('core', $e->getmessage(), \OCP\Util::DEBUG);
-} catch (\Exception $e) {
- \OC_Response::setStatus(500);
- \OCP\Util::writeLog('core', $e->getmessage(), \OCP\Util::DEBUG);
-}
diff --git a/apps/files_versions/appinfo/routes.php b/apps/files_versions/appinfo/routes.php
index c2b686c38f3..434ff9d26ac 100644
--- a/apps/files_versions/appinfo/routes.php
+++ b/apps/files_versions/appinfo/routes.php
@@ -1,6 +1,7 @@
<?php
/**
* @copyright Copyright (c) 2016, ownCloud, Inc.
+ * @copyright Copyright (c) 2016, Roeland Jago Douma <roeland@famdouma.nl>
*
* @author Björn Schießle <bjoern@schiessle.org>
* @author Jörn Friedrich Dreyer <jfd@butonic.de>
@@ -29,13 +30,17 @@
namespace OCA\Files_Versions\AppInfo;
$application = new Application();
+$application->registerRoutes($this, [
+ 'routes' => [
+ [
+ 'name' => 'Preview#getPreview',
+ 'url' => '/preview',
+ 'verb' => 'GET',
+ ],
+ ],
+]);
/** @var $this \OCP\Route\IRouter */
-$this->create('core_ajax_versions_preview', '/preview')->action(
-function() {
- require_once __DIR__ . '/../ajax/preview.php';
-});
-
$this->create('files_versions_download', 'download.php')
->actionInclude('files_versions/download.php');
$this->create('files_versions_ajax_getVersions', 'ajax/getVersions.php')
diff --git a/apps/files_versions/lib/Controller/PreviewController.php b/apps/files_versions/lib/Controller/PreviewController.php
new file mode 100644
index 00000000000..8d961f47ee6
--- /dev/null
+++ b/apps/files_versions/lib/Controller/PreviewController.php
@@ -0,0 +1,99 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016, Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCA\Files_Versions\Controller;
+
+use OCP\AppFramework\Controller;
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\DataResponse;
+use OCP\AppFramework\Http\FileDisplayResponse;
+use OCP\Files\File;
+use OCP\Files\Folder;
+use OCP\Files\IMimeTypeDetector;
+use OCP\Files\IRootFolder;
+use OCP\Files\NotFoundException;
+use OCP\IPreview;
+use OCP\IRequest;
+
+class PreviewController extends Controller {
+
+ /** @var IRootFolder */
+ private $rootFolder;
+
+ /** @var string */
+ private $userId;
+
+ /** @var IMimeTypeDetector */
+ private $mimeTypeDetector;
+
+ /** @var IPreview */
+ private $previewManager;
+
+ public function __construct($appName,
+ IRequest $request,
+ IRootFolder $rootFolder,
+ $userId,
+ IMimeTypeDetector $mimeTypeDetector,
+ IPreview $previewManager) {
+ parent::__construct($appName, $request);
+
+ $this->rootFolder = $rootFolder;
+ $this->userId = $userId;
+ $this->mimeTypeDetector = $mimeTypeDetector;
+ $this->previewManager = $previewManager;
+ }
+
+ /**
+ * @NoAdminRequired
+ * @NoCSRFRequired
+ *
+ * @param string $file
+ * @param int $x
+ * @param int $y
+ * @param string $version
+ * @return DataResponse|FileDisplayResponse
+ */
+ public function getPreview(
+ $file = '',
+ $x = 44,
+ $y = 44,
+ $version = ''
+ ) {
+ if($file === '' || $version === '' || $x === 0 || $y === 0) {
+ return new DataResponse([], Http::STATUS_BAD_REQUEST);
+ }
+
+ try {
+ $userFolder = $this->rootFolder->getUserFolder($this->userId);
+ /** @var Folder $versionFolder */
+ $versionFolder = $userFolder->getParent()->get('files_versions');
+ $mimeType = $this->mimeTypeDetector->detectPath($file);
+ $file = $versionFolder->get($file.'.v'.$version);
+
+ /** @var File $file */
+ $f = $this->previewManager->getPreview($file, $x, $y, true, IPreview::MODE_FILL, $mimeType);
+ return new FileDisplayResponse($f, Http::STATUS_OK, ['Content-Type' => $f->getMimeType()]);
+ } catch (NotFoundException $e) {
+ return new DataResponse([], Http::STATUS_NOT_FOUND);
+ }
+ }
+}
diff --git a/apps/files_versions/lib/Storage.php b/apps/files_versions/lib/Storage.php
index cf0e09f64ca..e7c2c8b7593 100644
--- a/apps/files_versions/lib/Storage.php
+++ b/apps/files_versions/lib/Storage.php
@@ -462,7 +462,7 @@ class Storage {
if (empty($userFullPath)) {
$versions[$key]['preview'] = '';
} else {
- $versions[$key]['preview'] = \OCP\Util::linkToRoute('core_ajax_versions_preview', array('file' => $userFullPath, 'version' => $timestamp));
+ $versions[$key]['preview'] = \OC::$server->getURLGenerator('files_version.Preview.getPreview', ['file' => $userFullPath, 'version' => $timestamp]);
}
$versions[$key]['path'] = Filesystem::normalizePath($pathinfo['dirname'] . '/' . $filename);
$versions[$key]['name'] = $versionedFile;
diff --git a/apps/files_versions/tests/Controller/PreviewControllerTest.php b/apps/files_versions/tests/Controller/PreviewControllerTest.php
new file mode 100644
index 00000000000..384f43cf495
--- /dev/null
+++ b/apps/files_versions/tests/Controller/PreviewControllerTest.php
@@ -0,0 +1,167 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016, Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OCA\Files_Versions\Tests\Controller;
+
+use OCA\Files_Versions\Controller\PreviewController;
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\DataResponse;
+use OCP\AppFramework\Http\FileDisplayResponse;
+use OCP\Files\File;
+use OCP\Files\Folder;
+use OCP\Files\IMimeTypeDetector;
+use OCP\Files\IRootFolder;
+use OCP\Files\NotFoundException;
+use OCP\Files\SimpleFS\ISimpleFile;
+use OCP\IPreview;
+use OCP\IRequest;
+use Test\TestCase;
+
+class PreviewControllerTest extends TestCase {
+
+ /** @var IRootFolder|\PHPUnit_Framework_MockObject_MockObject */
+ private $rootFolder;
+
+ /** @var string */
+ private $userId;
+
+ /** @var IMimeTypeDetector|\PHPUnit_Framework_MockObject_MockObject */
+ private $mimeTypeDetector;
+
+ /** @var IPreview|\PHPUnit_Framework_MockObject_MockObject */
+ private $previewManager;
+
+ /** @var PreviewController */
+ private $controller;
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->rootFolder = $this->createMock(IRootFolder::class);
+ $this->userId = 'user';
+ $this->mimeTypeDetector = $this->createMock(IMimeTypeDetector::class);
+ $this->previewManager = $this->createMock(IPreview::class);
+
+ $this->controller = new PreviewController(
+ 'files_versions',
+ $this->createMock(IRequest::class),
+ $this->rootFolder,
+ $this->userId,
+ $this->mimeTypeDetector,
+ $this->previewManager
+ );
+ }
+
+ public function testInvalidFile() {
+ $res = $this->controller->getPreview('');
+ $expected = new DataResponse([], Http::STATUS_BAD_REQUEST);
+
+ $this->assertEquals($expected, $res);
+ }
+
+ public function testInvalidWidth() {
+ $res = $this->controller->getPreview('file', 0);
+ $expected = new DataResponse([], Http::STATUS_BAD_REQUEST);
+
+ $this->assertEquals($expected, $res);
+ }
+
+ public function testInvalidHeight() {
+ $res = $this->controller->getPreview('file', 10, 0);
+ $expected = new DataResponse([], Http::STATUS_BAD_REQUEST);
+
+ $this->assertEquals($expected, $res);
+ }
+
+ public function testInvalidVersion() {
+ $res = $this->controller->getPreview('file', 10, 0);
+ $expected = new DataResponse([], Http::STATUS_BAD_REQUEST);
+
+ $this->assertEquals($expected, $res);
+ }
+
+ public function testValidPreview() {
+ $userFolder = $this->createMock(Folder::class);
+ $userRoot = $this->createMock(Folder::class);
+ $versions = $this->createMock(Folder::class);
+
+ $this->rootFolder->method('getUserFolder')
+ ->with($this->userId)
+ ->willReturn($userFolder);
+ $userFolder->method('getParent')
+ ->willReturn($userRoot);
+ $userRoot->method('get')
+ ->with('files_versions')
+ ->willReturn($versions);
+
+ $this->mimeTypeDetector->method('detectPath')
+ ->with($this->equalTo('file'))
+ ->willReturn('myMime');
+
+ $file = $this->createMock(File::class);
+ $versions->method('get')
+ ->with($this->equalTo('file.v42'))
+ ->willReturn($file);
+
+ $preview = $this->createMock(ISimpleFile::class);
+ $this->previewManager->method('getPreview')
+ ->with($this->equalTo($file), 10, 10, true, IPreview::MODE_FILL, 'myMime')
+ ->willReturn($preview);
+ $preview->method('getMimeType')
+ ->willReturn('previewMime');
+
+ $res = $this->controller->getPreview('file', 10, 10, '42');
+ $expected = new FileDisplayResponse($preview, Http::STATUS_OK, ['Content-Type' => 'previewMime']);
+
+ $this->assertEquals($expected, $res);
+ }
+
+ public function testVersionNotFound() {
+ $userFolder = $this->createMock(Folder::class);
+ $userRoot = $this->createMock(Folder::class);
+ $versions = $this->createMock(Folder::class);
+
+ $this->rootFolder->method('getUserFolder')
+ ->with($this->userId)
+ ->willReturn($userFolder);
+ $userFolder->method('getParent')
+ ->willReturn($userRoot);
+ $userRoot->method('get')
+ ->with('files_versions')
+ ->willReturn($versions);
+
+ $this->mimeTypeDetector->method('detectPath')
+ ->with($this->equalTo('file'))
+ ->willReturn('myMime');
+
+ $file = $this->createMock(File::class);
+ $versions->method('get')
+ ->with($this->equalTo('file.v42'))
+ ->willThrowException(new NotFoundException());
+
+ $res = $this->controller->getPreview('file', 10, 10, '42');
+ $expected = new DataResponse([], Http::STATUS_NOT_FOUND);
+
+ $this->assertEquals($expected, $res);
+ }
+
+}
diff --git a/core/Controller/PreviewController.php b/core/Controller/PreviewController.php
new file mode 100644
index 00000000000..4b9ba8b60d4
--- /dev/null
+++ b/core/Controller/PreviewController.php
@@ -0,0 +1,132 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016, Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OC\Core\Controller;
+
+use OCP\AppFramework\Controller;
+use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\Files\File;
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\DataResponse;
+use OCP\AppFramework\Http\FileDisplayResponse;
+use OCP\Files\IRootFolder;
+use OCP\Files\NotFoundException;
+use OCP\IPreview;
+use OCP\IRequest;
+
+class PreviewController extends Controller {
+
+ /** @var string */
+ private $userId;
+
+ /** @var IRootFolder */
+ private $root;
+
+ /** @var IPreview */
+ private $preview;
+
+ /** @var ITimeFactory */
+ private $timeFactory;
+
+ /**
+ * PreviewController constructor.
+ *
+ * @param string $appName
+ * @param IRequest $request
+ * @param IPreview $preview
+ * @param IRootFolder $root
+ * @param string $userId
+ */
+ public function __construct($appName,
+ IRequest $request,
+ IPreview $preview,
+ IRootFolder $root,
+ $userId,
+ ITimeFactory $timeFactory
+ ) {
+ parent::__construct($appName, $request);
+
+ $this->preview = $preview;
+ $this->root = $root;
+ $this->userId = $userId;
+ $this->timeFactory = $timeFactory;
+ }
+
+ /**
+ * @NoAdminRequired
+ * @NoCSRFRequired
+ *
+ * @param string $file
+ * @param int $x
+ * @param int $y
+ * @param bool $a
+ * @param bool $forceIcon
+ * @param string $mode
+ * @return DataResponse|Http\FileDisplayResponse
+ */
+ public function getPreview(
+ $file = '',
+ $x = 32,
+ $y = 32,
+ $a = false,
+ $forceIcon = true,
+ $mode = 'fill') {
+
+ if ($file === '' || $x === 0 || $y === 0) {
+ return new DataResponse([], Http::STATUS_BAD_REQUEST);
+ }
+
+ try {
+ $userFolder = $this->root->getUserFolder($this->userId);
+ $file = $userFolder->get($file);
+ } catch (NotFoundException $e) {
+ return new DataResponse([], Http::STATUS_NOT_FOUND);
+ }
+
+ if (!($file instanceof File) || (!$forceIcon && !$this->preview->isAvailable($file))) {
+ return new DataResponse([], Http::STATUS_NOT_FOUND);
+ } else if (!$file->isReadable()) {
+ return new DataResponse([], Http::STATUS_FORBIDDEN);
+ }
+
+ try {
+ $f = $this->preview->getPreview($file, $x, $y, !$a, $mode);
+ $response = new FileDisplayResponse($f, Http::STATUS_OK, ['Content-Type' => $f->getMimeType()]);
+
+ // Let cache this!
+ $response->addHeader('Pragma', 'public');
+
+ // Cache previews for 24H
+ $response->cacheFor(3600 * 24);
+ $expires = new \DateTime();
+ $expires->setTimestamp($this->timeFactory->getTime());
+ $expires->add(new \DateInterval('P1D'));
+ $response->addHeader('Expires', $expires->format(\DateTime::RFC2822));
+
+ return $response;
+ } catch (NotFoundException $e) {
+ return new DataResponse([], Http::STATUS_NOT_FOUND);
+ }
+
+ }
+}
diff --git a/core/ajax/preview.php b/core/ajax/preview.php
deleted file mode 100644
index 6cfba6aef30..00000000000
--- a/core/ajax/preview.php
+++ /dev/null
@@ -1,67 +0,0 @@
-<?php
-/**
- * @copyright Copyright (c) 2016, ownCloud, Inc.
- *
- * @author Georg Ehrke <georg@owncloud.com>
- * @author Joas Schilling <coding@schilljs.com>
- * @author Lukas Reschke <lukas@statuscode.ch>
- * @author Morris Jobke <hey@morrisjobke.de>
- * @author Robin Appelman <robin@icewind.nl>
- * @author Thomas Müller <thomas.mueller@tmit.eu>
- *
- * @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 <http://www.gnu.org/licenses/>
- *
- */
-\OC_Util::checkLoggedIn();
-\OC::$server->getSession()->close();
-
-$file = array_key_exists('file', $_GET) ? (string)$_GET['file'] : '';
-$maxX = array_key_exists('x', $_GET) ? (int)$_GET['x'] : '32';
-$maxY = array_key_exists('y', $_GET) ? (int)$_GET['y'] : '32';
-$scalingUp = array_key_exists('scalingup', $_GET) ? (bool)$_GET['scalingup'] : true;
-$keepAspect = array_key_exists('a', $_GET) ? true : false;
-$always = array_key_exists('forceIcon', $_GET) ? (bool)$_GET['forceIcon'] : true;
-$mode = array_key_exists('mode', $_GET) ? $_GET['mode'] : 'fill';
-
-if ($file === '') {
- //400 Bad Request
- \OC_Response::setStatus(400);
- \OCP\Util::writeLog('core-preview', 'No file parameter was passed', \OCP\Util::DEBUG);
- exit;
-}
-
-if ($maxX === 0 || $maxY === 0) {
- //400 Bad Request
- \OC_Response::setStatus(400);
- \OCP\Util::writeLog('core-preview', 'x and/or y set to 0', \OCP\Util::DEBUG);
- exit;
-}
-
-$info = \OC\Files\Filesystem::getFileInfo($file);
-
-if (!$info instanceof OCP\Files\FileInfo || !$always && !\OC::$server->getPreviewManager()->isAvailable($info)) {
- \OC_Response::setStatus(404);
-} else if (!$info->isReadable()) {
- \OC_Response::setStatus(403);
-} else {
- $preview = new \OC\Preview(\OC_User::getUser(), 'files');
- $preview->setFile($file, $info);
- $preview->setMaxX($maxX);
- $preview->setMaxY($maxY);
- $preview->setScalingUp($scalingUp);
- $preview->setMode($mode);
- $preview->setKeepAspect($keepAspect);
- $preview->showPreview();
-}
diff --git a/core/routes.php b/core/routes.php
index 7978001af7d..c890d232cfe 100644
--- a/core/routes.php
+++ b/core/routes.php
@@ -52,6 +52,8 @@ $application->registerRoutes($this, [
['name' => 'TwoFactorChallenge#showChallenge', 'url' => '/login/challenge/{challengeProviderId}', 'verb' => 'GET'],
['name' => 'TwoFactorChallenge#solveChallenge', 'url' => '/login/challenge/{challengeProviderId}', 'verb' => 'POST'],
['name' => 'OCJS#getConfig', 'url' => '/core/js/oc.js', 'verb' => 'GET'],
+ ['name' => 'Preview#getPreview', 'url' => '/core/preview', 'verb' => 'GET'],
+ ['name' => 'Preview#getPreview', 'url' => '/core/preview.png', 'verb' => 'GET'],
],
'ocs' => [
['root' => '/cloud', 'name' => 'OCS#getCapabilities', 'url' => '/capabilities', 'verb' => 'GET'],
@@ -68,10 +70,6 @@ $application->registerRoutes($this, [
$this->create('search_ajax_search', '/core/search')
->actionInclude('core/search/ajax/search.php');
// Routing
-$this->create('core_ajax_preview', '/core/preview')
- ->actionInclude('core/ajax/preview.php');
-$this->create('core_ajax_preview', '/core/preview.png')
- ->actionInclude('core/ajax/preview.php');
$this->create('core_ajax_update', '/core/ajax/update.php')
->actionInclude('core/ajax/update.php');
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php
index ddd531868d4..42cfb8c45e1 100644
--- a/lib/composer/composer/autoload_classmap.php
+++ b/lib/composer/composer/autoload_classmap.php
@@ -411,6 +411,7 @@ return array(
'OC\\Core\\Controller\\LostController' => $baseDir . '/core/Controller/LostController.php',
'OC\\Core\\Controller\\OCJSController' => $baseDir . '/core/Controller/OCJSController.php',
'OC\\Core\\Controller\\OCSController' => $baseDir . '/core/Controller/OCSController.php',
+ 'OC\\Core\\Controller\\PreviewController' => $baseDir . '/core/Controller/PreviewController.php',
'OC\\Core\\Controller\\SetupController' => $baseDir . '/core/Controller/SetupController.php',
'OC\\Core\\Controller\\TwoFactorChallengeController' => $baseDir . '/core/Controller/TwoFactorChallengeController.php',
'OC\\Core\\Controller\\UserController' => $baseDir . '/core/Controller/UserController.php',
@@ -620,6 +621,8 @@ return array(
'OC\\Preview\\Bitmap' => $baseDir . '/lib/private/Preview/Bitmap.php',
'OC\\Preview\\Font' => $baseDir . '/lib/private/Preview/Font.php',
'OC\\Preview\\GIF' => $baseDir . '/lib/private/Preview/GIF.php',
+ 'OC\\Preview\\Generator' => $baseDir . '/lib/private/Preview/Generator.php',
+ 'OC\\Preview\\GeneratorHelper' => $baseDir . '/lib/private/Preview/GeneratorHelper.php',
'OC\\Preview\\Illustrator' => $baseDir . '/lib/private/Preview/Illustrator.php',
'OC\\Preview\\Image' => $baseDir . '/lib/private/Preview/Image.php',
'OC\\Preview\\JPEG' => $baseDir . '/lib/private/Preview/JPEG.php',
@@ -640,6 +643,8 @@ return array(
'OC\\Preview\\StarOffice' => $baseDir . '/lib/private/Preview/StarOffice.php',
'OC\\Preview\\TIFF' => $baseDir . '/lib/private/Preview/TIFF.php',
'OC\\Preview\\TXT' => $baseDir . '/lib/private/Preview/TXT.php',
+ 'OC\\Preview\\Watcher' => $baseDir . '/lib/private/Preview/Watcher.php',
+ 'OC\\Preview\\WatcherConnector' => $baseDir . '/lib/private/Preview/WatcherConnector.php',
'OC\\Preview\\XBitmap' => $baseDir . '/lib/private/Preview/XBitmap.php',
'OC\\RedisFactory' => $baseDir . '/lib/private/RedisFactory.php',
'OC\\Repair' => $baseDir . '/lib/private/Repair.php',
diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php
index 99a3c3d540e..d7e937577f2 100644
--- a/lib/composer/composer/autoload_static.php
+++ b/lib/composer/composer/autoload_static.php
@@ -441,6 +441,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\Core\\Controller\\LostController' => __DIR__ . '/../../..' . '/core/Controller/LostController.php',
'OC\\Core\\Controller\\OCJSController' => __DIR__ . '/../../..' . '/core/Controller/OCJSController.php',
'OC\\Core\\Controller\\OCSController' => __DIR__ . '/../../..' . '/core/Controller/OCSController.php',
+ 'OC\\Core\\Controller\\PreviewController' => __DIR__ . '/../../..' . '/core/Controller/PreviewController.php',
'OC\\Core\\Controller\\SetupController' => __DIR__ . '/../../..' . '/core/Controller/SetupController.php',
'OC\\Core\\Controller\\TwoFactorChallengeController' => __DIR__ . '/../../..' . '/core/Controller/TwoFactorChallengeController.php',
'OC\\Core\\Controller\\UserController' => __DIR__ . '/../../..' . '/core/Controller/UserController.php',
@@ -650,6 +651,8 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\Preview\\Bitmap' => __DIR__ . '/../../..' . '/lib/private/Preview/Bitmap.php',
'OC\\Preview\\Font' => __DIR__ . '/../../..' . '/lib/private/Preview/Font.php',
'OC\\Preview\\GIF' => __DIR__ . '/../../..' . '/lib/private/Preview/GIF.php',
+ 'OC\\Preview\\Generator' => __DIR__ . '/../../..' . '/lib/private/Preview/Generator.php',
+ 'OC\\Preview\\GeneratorHelper' => __DIR__ . '/../../..' . '/lib/private/Preview/GeneratorHelper.php',
'OC\\Preview\\Illustrator' => __DIR__ . '/../../..' . '/lib/private/Preview/Illustrator.php',
'OC\\Preview\\Image' => __DIR__ . '/../../..' . '/lib/private/Preview/Image.php',
'OC\\Preview\\JPEG' => __DIR__ . '/../../..' . '/lib/private/Preview/JPEG.php',
@@ -670,6 +673,8 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\Preview\\StarOffice' => __DIR__ . '/../../..' . '/lib/private/Preview/StarOffice.php',
'OC\\Preview\\TIFF' => __DIR__ . '/../../..' . '/lib/private/Preview/TIFF.php',
'OC\\Preview\\TXT' => __DIR__ . '/../../..' . '/lib/private/Preview/TXT.php',
+ 'OC\\Preview\\Watcher' => __DIR__ . '/../../..' . '/lib/private/Preview/Watcher.php',
+ 'OC\\Preview\\WatcherConnector' => __DIR__ . '/../../..' . '/lib/private/Preview/WatcherConnector.php',
'OC\\Preview\\XBitmap' => __DIR__ . '/../../..' . '/lib/private/Preview/XBitmap.php',
'OC\\RedisFactory' => __DIR__ . '/../../..' . '/lib/private/RedisFactory.php',
'OC\\Repair' => __DIR__ . '/../../..' . '/lib/private/Repair.php',
diff --git a/lib/private/Preview.php b/lib/private/Preview.php
index ccaec738caf..caa1e89bacc 100644
--- a/lib/private/Preview.php
+++ b/lib/private/Preview.php
@@ -125,7 +125,7 @@ class Preview {
$sysConfig = \OC::$server->getConfig();
$this->configMaxWidth = $sysConfig->getSystemValue('preview_max_x', 2048);
$this->configMaxHeight = $sysConfig->getSystemValue('preview_max_y', 2048);
- $this->maxScaleFactor = $sysConfig->getSystemValue('preview_max_scale_factor', 2);
+ $this->maxScaleFactor = $sysConfig->getSystemValue('preview_max_scale_factor', 1);
//save parameters
$this->setFile($file);
diff --git a/lib/private/Preview/Generator.php b/lib/private/Preview/Generator.php
new file mode 100644
index 00000000000..3d4e9bf3677
--- /dev/null
+++ b/lib/private/Preview/Generator.php
@@ -0,0 +1,338 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016, Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OC\Preview;
+
+use OCP\Files\File;
+use OCP\Files\IAppData;
+use OCP\Files\NotFoundException;
+use OCP\Files\SimpleFS\ISimpleFile;
+use OCP\Files\SimpleFS\ISimpleFolder;
+use OCP\IConfig;
+use OCP\IImage;
+use OCP\IPreview;
+use OCP\Preview\IProvider;
+
+class Generator {
+
+ /** @var IPreview */
+ private $previewManager;
+ /** @var IConfig */
+ private $config;
+ /** @var IAppData */
+ private $appData;
+ /** @var GeneratorHelper */
+ private $helper;
+
+ /**
+ * @param IConfig $config
+ * @param IPreview $previewManager
+ * @param IAppData $appData
+ * @param GeneratorHelper $helper
+ */
+ public function __construct(
+ IConfig $config,
+ IPreview $previewManager,
+ IAppData $appData,
+ GeneratorHelper $helper
+ ) {
+ $this->config = $config;
+ $this->previewManager = $previewManager;
+ $this->appData = $appData;
+ $this->helper = $helper;
+ }
+
+ /**
+ * Returns a preview of a file
+ *
+ * The cache is searched first and if nothing usable was found then a preview is
+ * generated by one of the providers
+ *
+ * @param File $file
+ * @param int $width
+ * @param int $height
+ * @param bool $crop
+ * @param string $mode
+ * @param string $mimeType
+ * @return ISimpleFile
+ * @throws NotFoundException
+ */
+ public function getPreview(File $file, $width = -1, $height = -1, $crop = false, $mode = IPreview::MODE_FILL, $mimeType = null) {
+ if ($mimeType === null) {
+ $mimeType = $file->getMimeType();
+ }
+ if (!$this->previewManager->isMimeSupported($mimeType)) {
+ throw new NotFoundException();
+ }
+
+ $previewFolder = $this->getPreviewFolder($file);
+
+ // Get the max preview and infer the max preview sizes from that
+ $maxPreview = $this->getMaxPreview($previewFolder, $file, $mimeType);
+ list($maxWidth, $maxHeight) = $this->getPreviewSize($maxPreview);
+
+ // Calculate the preview size
+ list($width, $height) = $this->calculateSize($width, $height, $crop, $mode, $maxWidth, $maxHeight);
+
+ // Try to get a cached preview. Else generate (and store) one
+ try {
+ $file = $this->getCachedPreview($previewFolder, $width, $height, $crop);
+ } catch (NotFoundException $e) {
+ $file = $this->generatePreview($previewFolder, $maxPreview, $width, $height, $crop, $maxWidth, $maxHeight);
+ }
+
+ return $file;
+ }
+
+ /**
+ * @param ISimpleFolder $previewFolder
+ * @param File $file
+ * @param string $mimeType
+ * @return ISimpleFile
+ * @throws NotFoundException
+ */
+ private function getMaxPreview(ISimpleFolder $previewFolder, File $file, $mimeType) {
+ $nodes = $previewFolder->getDirectoryListing();
+
+ foreach ($nodes as $node) {
+ if (strpos($node->getName(), 'max')) {
+ return $node;
+ }
+ }
+
+ $previewProviders = $this->previewManager->getProviders();
+ foreach ($previewProviders as $supportedMimeType => $providers) {
+ if (!preg_match($supportedMimeType, $mimeType)) {
+ continue;
+ }
+
+ foreach ($providers as $provider) {
+ $provider = $this->helper->getProvider($provider);
+ if (!($provider instanceof IProvider)) {
+ continue;
+ }
+
+ $maxWidth = (int)$this->config->getSystemValue('preview_max_x', 2048);
+ $maxHeight = (int)$this->config->getSystemValue('preview_max_y', 2048);
+
+ $preview = $this->helper->getThumbnail($provider, $file, $maxWidth, $maxHeight);
+
+ if (!($preview instanceof IImage)) {
+ continue;
+ }
+
+ $path = strval($preview->width()) . '-' . strval($preview->height()) . '-max.png';
+ $file = $previewFolder->newFile($path);
+ $file->putContent($preview->data());
+
+ return $file;
+ }
+ }
+
+ throw new NotFoundException();
+ }
+
+ /**
+ * @param ISimpleFile $file
+ * @return int[]
+ */
+ private function getPreviewSize(ISimpleFile $file) {
+ $size = explode('-', $file->getName());
+ return [(int)$size[0], (int)$size[1]];
+ }
+
+ /**
+ * @param int $width
+ * @param int $height
+ * @param bool $crop
+ * @return string
+ */
+ private function generatePath($width, $height, $crop) {
+ $path = strval($width) . '-' . strval($height);
+ if ($crop) {
+ $path .= '-crop';
+ }
+ $path .= '.png';
+ return $path;
+ }
+
+
+
+ /**
+ * @param int $width
+ * @param int $height
+ * @param bool $crop
+ * @param string $mode
+ * @param int $maxWidth
+ * @param int $maxHeight
+ * @return int[]
+ */
+ private function calculateSize($width, $height, $crop, $mode, $maxWidth, $maxHeight) {
+
+ /*
+ * If we are not cropping we have to make sure the requested image
+ * respects the aspect ratio of the original.
+ */
+ if (!$crop) {
+ $ratio = $maxHeight / $maxWidth;
+
+ if ($width === -1) {
+ $width = $height / $ratio;
+ }
+ if ($height === -1) {
+ $height = $width * $ratio;
+ }
+
+ $ratioH = $height / $maxHeight;
+ $ratioW = $width / $maxWidth;
+
+ /*
+ * Fill means that the $height and $width are the max
+ * Cover means min.
+ */
+ if ($mode === IPreview::MODE_FILL) {
+ if ($ratioH > $ratioW) {
+ $height = $width * $ratio;
+ } else {
+ $width = $height / $ratio;
+ }
+ } else if ($mode === IPreview::MODE_COVER) {
+ if ($ratioH > $ratioW) {
+ $width = $height / $ratio;
+ } else {
+ $height = $width * $ratio;
+ }
+ }
+ }
+
+ if ($height !== $maxHeight && $width !== $maxWidth) {
+ /*
+ * Scale to the nearest power of two
+ */
+ $pow2height = pow(2, ceil(log($height) / log(2)));
+ $pow2width = pow(2, ceil(log($width) / log(2)));
+
+ $ratioH = $height / $pow2height;
+ $ratioW = $width / $pow2width;
+
+ if ($ratioH < $ratioW) {
+ $width = $pow2width;
+ $height = $height / $ratioW;
+ } else {
+ $height = $pow2height;
+ $width = $width / $ratioH;
+ }
+ }
+
+ /*
+ * Make sure the requested height and width fall within the max
+ * of the preview.
+ */
+ if ($height > $maxHeight) {
+ $ratio = $height / $maxHeight;
+ $height = $maxHeight;
+ $width = $width / $ratio;
+ }
+ if ($width > $maxWidth) {
+ $ratio = $width / $maxWidth;
+ $width = $maxWidth;
+ $height = $height / $ratio;
+ }
+
+ return [(int)round($width), (int)round($height)];
+ }
+
+ /**
+ * @param ISimpleFolder $previewFolder
+ * @param ISimpleFile $maxPreview
+ * @param int $width
+ * @param int $height
+ * @param bool $crop
+ * @param int $maxWidth
+ * @param int $maxHeight
+ * @return ISimpleFile
+ * @throws NotFoundException
+ */
+ private function generatePreview(ISimpleFolder $previewFolder, ISimpleFile $maxPreview, $width, $height, $crop, $maxWidth, $maxHeight) {
+ $preview = $this->helper->getImage($maxPreview);
+
+ if ($crop) {
+ if ($height !== $preview->height() && $width !== $preview->width()) {
+ //Resize
+ $widthR = $preview->width() / $width;
+ $heightR = $preview->height() / $height;
+
+ if ($widthR > $heightR) {
+ $scaleH = $height;
+ $scaleW = $maxWidth / $heightR;
+ } else {
+ $scaleH = $maxHeight / $widthR;
+ $scaleW = $width;
+ }
+ $preview->preciseResize(round($scaleW), round($scaleH));
+ }
+ $cropX = floor(abs($width - $preview->width()) * 0.5);
+ $cropY = 0;
+ $preview->crop($cropX, $cropY, $width, $height);
+ } else {
+ $preview->resize(max($width, $height));
+ }
+
+ $path = $this->generatePath($width, $height, $crop);
+ $file = $previewFolder->newFile($path);
+ $file->putContent($preview->data());
+
+ return $file;
+ }
+
+ /**
+ * @param ISimpleFolder $previewFolder
+ * @param int $width
+ * @param int $height
+ * @param bool $crop
+ * @return ISimpleFile
+ *
+ * @throws NotFoundException
+ */
+ private function getCachedPreview(ISimpleFolder $previewFolder, $width, $height, $crop) {
+ $path = $this->generatePath($width, $height, $crop);
+
+ return $previewFolder->getFile($path);
+ }
+
+ /**
+ * Get the specific preview folder for this file
+ *
+ * @param File $file
+ * @return ISimpleFolder
+ */
+ private function getPreviewFolder(File $file) {
+ try {
+ $folder = $this->appData->getFolder($file->getId());
+ } catch (NotFoundException $e) {
+ $folder = $this->appData->newFolder($file->getId());
+ }
+
+ return $folder;
+ }
+}
diff --git a/lib/private/Preview/GeneratorHelper.php b/lib/private/Preview/GeneratorHelper.php
new file mode 100644
index 00000000000..282c46a2a5d
--- /dev/null
+++ b/lib/private/Preview/GeneratorHelper.php
@@ -0,0 +1,91 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016, Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OC\Preview;
+
+use OC\Files\View;
+use OCP\Files\File;
+use OCP\Files\IRootFolder;
+use OCP\Files\SimpleFS\ISimpleFile;
+use OCP\IImage;
+use OCP\Image as img;
+use OCP\Preview\IProvider;
+
+/**
+ * Very small wrapper class to make the generator fully unit testable
+ */
+class GeneratorHelper {
+
+ /** @var IRootFolder */
+ private $rootFolder;
+
+ public function __construct(IRootFolder $rootFolder) {
+ $this->rootFolder = $rootFolder;
+ }
+
+ /**
+ * @param IProvider $provider
+ * @param File $file
+ * @param int $maxWidth
+ * @param int $maxHeight
+ * @return bool|IImage
+ */
+ public function getThumbnail(IProvider $provider, File $file, $maxWidth, $maxHeight) {
+ list($view, $path) = $this->getViewAndPath($file);
+ return $provider->getThumbnail($path, $maxWidth, $maxHeight, false, $view);
+ }
+
+ /**
+ * @param File $file
+ * @return array
+ * This is required to create the old view and path
+ */
+ private function getViewAndPath(File $file) {
+ $owner = $file->getOwner()->getUID();
+
+ $userFolder = $this->rootFolder->getUserFolder($owner)->getParent();
+
+ $nodes = $userFolder->getById($file->getId());
+ $file = $nodes[0];
+
+ $view = new View($userFolder->getPath());
+ $path = $userFolder->getRelativePath($file->getPath());
+
+ return [$view, $path];
+ }
+
+ /**
+ * @param ISimpleFile $maxPreview
+ * @return IImage
+ */
+ public function getImage(ISimpleFile $maxPreview) {
+ return new img($maxPreview->getContent());
+ }
+
+ /**
+ * @param $provider
+ * @return IProvider
+ */
+ public function getProvider($provider) {
+ return $provider();
+ }
+}
diff --git a/lib/private/Preview/Watcher.php b/lib/private/Preview/Watcher.php
new file mode 100644
index 00000000000..0b87bcda86e
--- /dev/null
+++ b/lib/private/Preview/Watcher.php
@@ -0,0 +1,98 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016, Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OC\Preview;
+
+use OCP\Files\File;
+use OCP\Files\Node;
+use OCP\Files\Folder;
+use OCP\Files\IAppData;
+use OCP\Files\NotFoundException;
+
+/**
+ * Class Watcher
+ *
+ * @package OC\Preview
+ *
+ * Class that will watch filesystem activity and remove previews as needed.
+ */
+class Watcher {
+ /** @var IAppData */
+ private $appData;
+
+ /** @var int[] */
+ private $toDelete = [];
+
+ /**
+ * Watcher constructor.
+ *
+ * @param IAppData $appData
+ */
+ public function __construct(IAppData $appData) {
+ $this->appData = $appData;
+ }
+
+ public function postWrite(Node $node) {
+ // We only handle files
+ if ($node instanceof Folder) {
+ return;
+ }
+
+ try {
+ $folder = $this->appData->getFolder($node->getId());
+ $folder->delete();
+ } catch (NotFoundException $e) {
+ //Nothing to do
+ }
+ }
+
+ public function preDelete(Node $node) {
+ // To avoid cycles
+ if ($this->toDelete !== []) {
+ return;
+ }
+
+ if ($node instanceof File) {
+ $this->toDelete[] = $node->getId();
+ return;
+ }
+
+ /** @var Folder $node */
+ $nodes = $node->search('');
+ foreach ($nodes as $node) {
+ if ($node instanceof File) {
+ $this->toDelete[] = $node->getId();
+ }
+ }
+ }
+
+ public function postDelete(Node $node) {
+ foreach ($this->toDelete as $fid) {
+ try {
+ $folder = $this->appData->getFolder($fid);
+ $folder->delete();
+ } catch (NotFoundException $e) {
+ // continue
+ }
+ }
+ }
+}
diff --git a/lib/private/Preview/WatcherConnector.php b/lib/private/Preview/WatcherConnector.php
new file mode 100644
index 00000000000..4e6e786cec7
--- /dev/null
+++ b/lib/private/Preview/WatcherConnector.php
@@ -0,0 +1,72 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016, Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace OC\Preview;
+
+use OC\SystemConfig;
+use OCP\Files\Node;
+use OCP\Files\IRootFolder;
+
+class WatcherConnector {
+
+ /** @var IRootFolder */
+ private $root;
+
+ /** @var SystemConfig */
+ private $config;
+
+ /**
+ * WatcherConnector constructor.
+ *
+ * @param IRootFolder $root
+ * @param SystemConfig $config
+ */
+ public function __construct(IRootFolder $root,
+ SystemConfig $config) {
+ $this->root = $root;
+ $this->config = $config;
+ }
+
+ /**
+ * @return Watcher
+ */
+ private function getWatcher() {
+ return \OC::$server->query(Watcher::class);
+ }
+
+ public function connectWatcher() {
+ // Do not connect if we are not setup yet!
+ if ($this->config->getValue('instanceid', null) !== null) {
+ $this->root->listen('\OC\Files', 'postWrite', function (Node $node) {
+ $this->getWatcher()->postWrite($node);
+ });
+
+ $this->root->listen('\OC\Files', 'preDelete', function (Node $node) {
+ $this->getWatcher()->preDelete($node);
+ });
+
+ $this->root->listen('\OC\Files', 'postDelete', function (Node $node) {
+ $this->getWatcher()->postDelete($node);
+ });
+ }
+ }
+}
diff --git a/lib/private/PreviewManager.php b/lib/private/PreviewManager.php
index 109feb45864..a2ef9659b3b 100644
--- a/lib/private/PreviewManager.php
+++ b/lib/private/PreviewManager.php
@@ -25,13 +25,30 @@
*/
namespace OC;
+use OC\Preview\Generator;
+use OC\Preview\GeneratorHelper;
+use OCP\Files\File;
+use OCP\Files\IAppData;
+use OCP\Files\IRootFolder;
+use OCP\Files\NotFoundException;
+use OCP\Files\SimpleFS\ISimpleFile;
+use OCP\IConfig;
use OCP\IPreview;
use OCP\Preview\IProvider;
class PreviewManager implements IPreview {
- /** @var \OCP\IConfig */
+ /** @var IConfig */
protected $config;
+ /** @var IRootFolder */
+ protected $rootFolder;
+
+ /** @var IAppData */
+ protected $appData;
+
+ /** @var Generator */
+ private $generator;
+
/** @var bool */
protected $providerListDirty = false;
@@ -52,8 +69,12 @@ class PreviewManager implements IPreview {
*
* @param \OCP\IConfig $config
*/
- public function __construct(\OCP\IConfig $config) {
+ public function __construct(IConfig $config,
+ IRootFolder $rootFolder,
+ IAppData $appData) {
$this->config = $config;
+ $this->rootFolder = $rootFolder;
+ $this->appData = $appData;
}
/**
@@ -121,6 +142,37 @@ class PreviewManager implements IPreview {
}
/**
+ * Returns a preview of a file
+ *
+ * The cache is searched first and if nothing usable was found then a preview is
+ * generated by one of the providers
+ *
+ * @param File $file
+ * @param int $width
+ * @param int $height
+ * @param bool $crop
+ * @param string $mode
+ * @param string $mimeType
+ * @return ISimpleFile
+ * @throws NotFoundException
+ * @since 9.2.0
+ */
+ public function getPreview(File $file, $width = -1, $height = -1, $crop = false, $mode = IPreview::MODE_FILL, $mimeType = null) {
+ if ($this->generator === null) {
+ $this->generator = new Generator(
+ $this->config,
+ $this,
+ $this->appData,
+ new GeneratorHelper(
+ $this->rootFolder
+ )
+ );
+ }
+
+ return $this->generator->getPreview($file, $width, $height, $crop, $mode, $mimeType);
+ }
+
+ /**
* returns true if the passed mime type is supported
*
* @param string $mimeType
diff --git a/lib/private/Server.php b/lib/private/Server.php
index 9f993ade7fe..8f4e7d9ca2d 100644
--- a/lib/private/Server.php
+++ b/lib/private/Server.php
@@ -117,7 +117,17 @@ class Server extends ServerContainer implements IServerContainer {
});
$this->registerService('PreviewManager', function (Server $c) {
- return new PreviewManager($c->getConfig());
+ return new PreviewManager(
+ $c->getConfig(),
+ $c->getRootFolder(),
+ $c->getAppDataDir('preview')
+ );
+ });
+
+ $this->registerService(\OC\Preview\Watcher::class, function (Server $c) {
+ return new \OC\Preview\Watcher(
+ $c->getAppDataDir('preview')
+ );
});
$this->registerService('EncryptionManager', function (Server $c) {
@@ -192,6 +202,10 @@ class Server extends ServerContainer implements IServerContainer {
);
$connector = new HookConnector($root, $view);
$connector->viewToNode();
+
+ $previewConnector = new \OC\Preview\WatcherConnector($root, $c->getSystemConfig());
+ $previewConnector->connectWatcher();
+
return $root;
});
$this->registerService('LazyRootFolder', function(Server $c) {
diff --git a/lib/public/IPreview.php b/lib/public/IPreview.php
index 071b5b8064c..c6417b4d182 100644
--- a/lib/public/IPreview.php
+++ b/lib/public/IPreview.php
@@ -33,11 +33,19 @@
// This means that they should be used by apps instead of the internal ownCloud classes
namespace OCP;
+use OCP\Files\File;
+use OCP\Files\SimpleFS\ISimpleFile;
+use OCP\Files\NotFoundException;
+
/**
* This class provides functions to render and show thumbnails and previews of files
* @since 6.0.0
*/
interface IPreview {
+
+ const MODE_FILL = 'fill';
+ const MODE_COVER = 'cover';
+
/**
* In order to improve lazy loading a closure can be registered which will be
* called in case preview providers are actually requested
@@ -73,9 +81,27 @@ interface IPreview {
* @param boolean $scaleUp Scale smaller images up to the thumbnail size or not. Might look ugly
* @return \OCP\IImage
* @since 6.0.0
+ * @deprecated 9.2.0 Use getPreview
*/
public function createPreview($file, $maxX = 100, $maxY = 75, $scaleUp = false);
+ /**
+ * Returns a preview of a file
+ *
+ * The cache is searched first and if nothing usable was found then a preview is
+ * generated by one of the providers
+ *
+ * @param File $file
+ * @param int $width
+ * @param int $height
+ * @param bool $crop
+ * @param string $mode
+ * @param string $mimeType To force a given mimetype for the file (files_versions needs this)
+ * @return ISimpleFile
+ * @throws NotFoundException
+ * @since 9.2.0
+ */
+ public function getPreview(File $file, $width = -1, $height = -1, $crop = false, $mode = IPreview::MODE_FILL, $mimeType = null);
/**
* Returns true if the passed mime type is supported
diff --git a/tests/Core/Controller/PreviewControllerTest.php b/tests/Core/Controller/PreviewControllerTest.php
new file mode 100644
index 00000000000..df1af6a0802
--- /dev/null
+++ b/tests/Core/Controller/PreviewControllerTest.php
@@ -0,0 +1,226 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016, Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace Tests\Core\Controller;
+
+use OC\Core\Controller\PreviewController;
+use OCP\AppFramework\Http;
+use OCP\AppFramework\Http\DataResponse;
+use OCP\AppFramework\Utility\ITimeFactory;
+use OCP\Files\File;
+use OCP\Files\Folder;
+use OCP\Files\IRootFolder;
+use OCP\Files\NotFoundException;
+use OCP\Files\SimpleFS\ISimpleFile;
+use OCP\IPreview;
+use OCP\IRequest;
+
+class PreviewControllerTest extends \Test\TestCase {
+
+ /** @var IRootFolder|\PHPUnit_Framework_MockObject_MockObject */
+ private $rootFolder;
+
+ /** @var string */
+ private $userId;
+
+ /** @var IPreview|\PHPUnit_Framework_MockObject_MockObject */
+ private $previewManager;
+
+ /** @var PreviewController|\PHPUnit_Framework_MockObject_MockObject */
+ private $controller;
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->rootFolder = $this->createMock(IRootFolder::class);
+ $this->userId = 'user';
+ $this->previewManager = $this->createMock(IPreview::class);
+
+ $this->controller = new PreviewController(
+ 'core',
+ $this->createMock(IRequest::class),
+ $this->previewManager,
+ $this->rootFolder,
+ $this->userId,
+ $this->createMock(ITimeFactory::class)
+ );
+ }
+
+ public function testInvalidFile() {
+ $res = $this->controller->getPreview('');
+ $expected = new DataResponse([], Http::STATUS_BAD_REQUEST);
+
+ $this->assertEquals($expected, $res);
+ }
+
+ public function testInvalidWidth() {
+ $res = $this->controller->getPreview('file', 0);
+ $expected = new DataResponse([], Http::STATUS_BAD_REQUEST);
+
+ $this->assertEquals($expected, $res);
+ }
+
+ public function testInvalidHeight() {
+ $res = $this->controller->getPreview('file', 10, 0);
+ $expected = new DataResponse([], Http::STATUS_BAD_REQUEST);
+
+ $this->assertEquals($expected, $res);
+ }
+
+ public function testFileNotFound() {
+ $userFolder = $this->createMock(Folder::class);
+ $this->rootFolder->method('getUserFolder')
+ ->with($this->equalTo($this->userId))
+ ->willReturn($userFolder);
+
+ $userFolder->method('get')
+ ->with($this->equalTo('file'))
+ ->willThrowException(new NotFoundException());
+
+ $res = $this->controller->getPreview('file');
+ $expected = new DataResponse([], Http::STATUS_NOT_FOUND);
+
+ $this->assertEquals($expected, $res);
+ }
+
+ public function testNotAFile() {
+ $userFolder = $this->createMock(Folder::class);
+ $this->rootFolder->method('getUserFolder')
+ ->with($this->equalTo($this->userId))
+ ->willReturn($userFolder);
+
+ $folder = $this->createMock(Folder::class);
+ $userFolder->method('get')
+ ->with($this->equalTo('file'))
+ ->willReturn($folder);
+
+ $res = $this->controller->getPreview('file');
+ $expected = new DataResponse([], Http::STATUS_NOT_FOUND);
+
+ $this->assertEquals($expected, $res);
+ }
+
+ public function testNoPreviewAndNoIcon() {
+ $userFolder = $this->createMock(Folder::class);
+ $this->rootFolder->method('getUserFolder')
+ ->with($this->equalTo($this->userId))
+ ->willReturn($userFolder);
+
+ $file = $this->createMock(File::class);
+ $userFolder->method('get')
+ ->with($this->equalTo('file'))
+ ->willReturn($file);
+
+ $this->previewManager->method('isAvailable')
+ ->with($this->equalTo($file))
+ ->willReturn(false);
+
+ $res = $this->controller->getPreview('file', 10, 10, true, false);
+ $expected = new DataResponse([], Http::STATUS_NOT_FOUND);
+
+ $this->assertEquals($expected, $res);
+ }
+
+ public function testForbiddenFile() {
+ $userFolder = $this->createMock(Folder::class);
+ $this->rootFolder->method('getUserFolder')
+ ->with($this->equalTo($this->userId))
+ ->willReturn($userFolder);
+
+ $file = $this->createMock(File::class);
+ $userFolder->method('get')
+ ->with($this->equalTo('file'))
+ ->willReturn($file);
+
+ $this->previewManager->method('isAvailable')
+ ->with($this->equalTo($file))
+ ->willReturn(true);
+
+ $file->method('isReadable')
+ ->willReturn(false);
+
+ $res = $this->controller->getPreview('file', 10, 10, true, true);
+ $expected = new DataResponse([], Http::STATUS_FORBIDDEN);
+
+ $this->assertEquals($expected, $res);
+ }
+
+ public function testNoPreview() {
+ $userFolder = $this->createMock(Folder::class);
+ $this->rootFolder->method('getUserFolder')
+ ->with($this->equalTo($this->userId))
+ ->willReturn($userFolder);
+
+ $file = $this->createMock(File::class);
+ $userFolder->method('get')
+ ->with($this->equalTo('file'))
+ ->willReturn($file);
+
+ $this->previewManager->method('isAvailable')
+ ->with($this->equalTo($file))
+ ->willReturn(true);
+
+ $file->method('isReadable')
+ ->willReturn(true);
+
+ $this->previewManager->method('getPreview')
+ ->with($this->equalTo($file), 10, 10, false, $this->equalTo('myMode'))
+ ->willThrowException(new NotFoundException());
+
+ $res = $this->controller->getPreview('file', 10, 10, true, true, 'myMode');
+ $expected = new DataResponse([], Http::STATUS_NOT_FOUND);
+
+ $this->assertEquals($expected, $res);
+ }
+
+ public function testValidPreview() {
+ $userFolder = $this->createMock(Folder::class);
+ $this->rootFolder->method('getUserFolder')
+ ->with($this->equalTo($this->userId))
+ ->willReturn($userFolder);
+
+ $file = $this->createMock(File::class);
+ $userFolder->method('get')
+ ->with($this->equalTo('file'))
+ ->willReturn($file);
+
+ $this->previewManager->method('isAvailable')
+ ->with($this->equalTo($file))
+ ->willReturn(true);
+
+ $file->method('isReadable')
+ ->willReturn(true);
+
+ $preview = $this->createMock(ISimpleFile::class);
+ $this->previewManager->method('getPreview')
+ ->with($this->equalTo($file), 10, 10, false, $this->equalTo('myMode'))
+ ->willReturn($preview);
+ $preview->method('getMimeType')
+ ->willReturn('myMime');
+
+ $res = $this->controller->getPreview('file', 10, 10, true, true, 'myMode');
+
+ $this->assertEquals('myMime', $res->getHeaders()['Content-Type']);
+ $this->assertEquals(Http::STATUS_OK, $res->getStatus());
+ $this->assertEquals($preview, $this->invokePrivate($res, 'file'));
+ }
+}
diff --git a/tests/lib/Preview/GeneratorTest.php b/tests/lib/Preview/GeneratorTest.php
new file mode 100644
index 00000000000..d64a0b912e1
--- /dev/null
+++ b/tests/lib/Preview/GeneratorTest.php
@@ -0,0 +1,338 @@
+<?php
+/**
+ * @copyright Copyright (c) 2016, Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @author Roeland Jago Douma <roeland@famdouma.nl>
+ *
+ * @license GNU AGPL version 3 or any later version
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * 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
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+namespace Test\Preview;
+
+use OC\Preview\Generator;
+use OC\Preview\GeneratorHelper;
+use OCP\Files\File;
+use OCP\Files\IAppData;
+use OCP\Files\NotFoundException;
+use OCP\Files\SimpleFS\ISimpleFile;
+use OCP\Files\SimpleFS\ISimpleFolder;
+use OCP\IConfig;
+use OCP\IImage;
+use OCP\IPreview;
+use OCP\Preview\IProvider;
+
+class GeneratorTest extends \Test\TestCase {
+
+ /** @var IConfig|\PHPUnit_Framework_MockObject_MockObject */
+ private $config;
+
+ /** @var IPreview|\PHPUnit_Framework_MockObject_MockObject */
+ private $previewManager;
+
+ /** @var IAppData|\PHPUnit_Framework_MockObject_MockObject */
+ private $appData;
+
+ /** @var GeneratorHelper|\PHPUnit_Framework_MockObject_MockObject */
+ private $helper;
+
+ /** @var Generator */
+ private $generator;
+
+ public function setUp() {
+ parent::setUp();
+
+ $this->config = $this->createMock(IConfig::class);
+ $this->previewManager = $this->createMock(IPreview::class);
+ $this->appData = $this->createMock(IAppData::class);
+ $this->helper = $this->createMock(GeneratorHelper::class);
+
+ $this->generator = new Generator(
+ $this->config,
+ $this->previewManager,
+ $this->appData,
+ $this->helper
+ );
+ }
+
+ public function testGetCachedPreview() {
+ $file = $this->createMock(File::class);
+ $file->method('getMimeType')
+ ->willReturn('myMimeType');
+ $file->method('getId')
+ ->willReturn(42);
+
+ $this->previewManager->method('isMimeSupported')
+ ->with($this->equalTo('myMimeType'))
+ ->willReturn(true);
+
+ $previewFolder = $this->createMock(ISimpleFolder::class);
+ $this->appData->method('getFolder')
+ ->with($this->equalTo(42))
+ ->willReturn($previewFolder);
+
+ $maxPreview = $this->createMock(ISimpleFile::class);
+ $maxPreview->method('getName')
+ ->willReturn('1000-1000-max.png');
+
+ $previewFolder->method('getDirectoryListing')
+ ->willReturn([$maxPreview]);
+
+ $previewFile = $this->createMock(ISimpleFile::class);
+
+ $previewFolder->method('getFile')
+ ->with($this->equalTo('128-128.png'))
+ ->willReturn($previewFile);
+
+ $result = $this->generator->getPreview($file, 100, 100);
+ $this->assertSame($previewFile, $result);
+ }
+
+ public function testGetNewPreview() {
+ $file = $this->createMock(File::class);
+ $file->method('getMimeType')
+ ->willReturn('myMimeType');
+ $file->method('getId')
+ ->willReturn(42);
+
+ $this->previewManager->method('isMimeSupported')
+ ->with($this->equalTo('myMimeType'))
+ ->willReturn(true);
+
+ $previewFolder = $this->createMock(ISimpleFolder::class);
+ $this->appData->method('getFolder')
+ ->with($this->equalTo(42))
+ ->willThrowException(new NotFoundException());
+
+ $this->appData->method('newFolder')
+ ->with($this->equalTo(42))
+ ->willReturn($previewFolder);
+
+ $this->config->method('getSystemValue')
+ ->will($this->returnCallback(function($key, $defult) {
+ return $defult;
+ }));
+
+ $invalidProvider = $this->createMock(IProvider::class);
+ $validProvider = $this->createMock(IProvider::class);
+
+ $this->previewManager->method('getProviders')
+ ->willReturn([
+ '/image\/png/' => ['wrongProvider'],
+ '/myMimeType/' => ['brokenProvider', 'invalidProvider', 'validProvider'],
+ ]);
+
+ $this->helper->method('getProvider')
+ ->will($this->returnCallback(function($provider) use ($invalidProvider, $validProvider) {
+ if ($provider === 'wrongProvider') {
+ $this->fail('Wrongprovider should not be constructed!');
+ } else if ($provider === 'brokenProvider') {
+ return false;
+ } else if ($provider === 'invalidProvider') {
+ return $invalidProvider;
+ } else if ($provider === 'validProvider') {
+ return $validProvider;
+ }
+ $this->fail('Unexpected provider requested');
+ }));
+
+ $image = $this->createMock(IImage::class);
+ $image->method('width')->willReturn(2048);
+ $image->method('height')->willReturn(2048);
+
+ $this->helper->method('getThumbnail')
+ ->will($this->returnCallback(function ($provider, $file, $x, $y) use ($invalidProvider, $validProvider, $image) {
+ if ($provider === $validProvider) {
+ return $image;
+ } else {
+ return false;
+ }
+ }));
+
+ $image->method('data')
+ ->willReturn('my data');
+
+ $maxPreview = $this->createMock(ISimpleFile::class);
+ $maxPreview->method('getName')->willReturn('2048-2048-max.png');
+
+ $previewFile = $this->createMock(ISimpleFile::class);
+
+ $previewFolder->method('getDirectoryListing')
+ ->willReturn([]);
+ $previewFolder->method('newFile')
+ ->will($this->returnCallback(function($filename) use ($maxPreview, $previewFile) {
+ if ($filename === '2048-2048-max.png') {
+ return $maxPreview;
+ } else if ($filename === '128-128.png') {
+ return $previewFile;
+ }
+ $this->fail('Unexpected file');
+ }));
+
+ $maxPreview->expects($this->once())
+ ->method('putContent')
+ ->with($this->equalTo('my data'));
+
+ $previewFolder->method('getFile')
+ ->with($this->equalTo('128-128.png'))
+ ->willThrowException(new NotFoundException());
+
+ $image = $this->createMock(IImage::class);
+ $this->helper->method('getImage')
+ ->with($this->equalTo($maxPreview))
+ ->willReturn($image);
+
+ $image->expects($this->once())
+ ->method('resize')
+ ->with(128);
+ $image->method('data')
+ ->willReturn('my resized data');
+
+ $previewFile->expects($this->once())
+ ->method('putContent')
+ ->with('my resized data');
+
+ $result = $this->generator->getPreview($file, 100, 100);
+ $this->assertSame($previewFile, $result);
+ }
+
+ public function testInvalidMimeType() {
+ $this->expectException(NotFoundException::class);
+
+ $file = $this->createMock(File::class);
+
+ $this->previewManager->method('isMimeSupported')
+ ->with('invalidType')
+ ->willReturn(false);
+
+ $this->generator->getPreview($file, 0, 0, true, IPreview::MODE_COVER, 'invalidType');
+ }
+
+ public function testNoProvider() {
+ $file = $this->createMock(File::class);
+ $file->method('getMimeType')
+ ->willReturn('myMimeType');
+ $file->method('getId')
+ ->willReturn(42);
+
+ $this->previewManager->method('isMimeSupported')
+ ->with($this->equalTo('myMimeType'))
+ ->willReturn(true);
+
+ $previewFolder = $this->createMock(ISimpleFolder::class);
+ $this->appData->method('getFolder')
+ ->with($this->equalTo(42))
+ ->willReturn($previewFolder);
+
+ $previewFolder->method('getDirectoryListing')
+ ->willReturn([]);
+
+ $this->previewManager->method('getProviders')
+ ->willReturn([]);
+
+ $this->expectException(NotFoundException::class);
+ $this->generator->getPreview($file, 100, 100);
+ }
+
+ public function dataSize() {
+ return [
+ [1024, 2048, 512, 512, false, IPreview::MODE_FILL, 256, 512],
+ [1024, 2048, 512, 512, false, IPreview::MODE_COVER, 512, 1024],
+ [1024, 2048, 512, 512, true, IPreview::MODE_FILL, 512, 512],
+ [1024, 2048, 512, 512, true, IPreview::MODE_COVER, 512, 512],
+
+ [1024, 2048, -1, 512, false, IPreview::MODE_COVER, 256, 512],
+ [1024, 2048, 512, -1, false, IPreview::MODE_FILL, 512, 1024],
+
+ [1024, 2048, 250, 1100, true, IPreview::MODE_COVER, 256, 1126],
+ [1024, 1100, 250, 1100, true, IPreview::MODE_COVER, 250, 1100],
+
+ [1024, 2048, 4096, 2048, false, IPreview::MODE_FILL, 1024, 2048],
+ [1024, 2048, 4096, 2048, false, IPreview::MODE_COVER, 1024, 2048],
+
+
+ [2048, 1024, 512, 512, false, IPreview::MODE_FILL, 512, 256],
+ [2048, 1024, 512, 512, false, IPreview::MODE_COVER, 1024, 512],
+ [2048, 1024, 512, 512, true, IPreview::MODE_FILL, 512, 512],
+ [2048, 1024, 512, 512, true, IPreview::MODE_COVER, 512, 512],
+
+ [2048, 1024, -1, 512, false, IPreview::MODE_FILL, 1024, 512],
+ [2048, 1024, 512, -1, false, IPreview::MODE_COVER, 512, 256],
+
+ [2048, 1024, 4096, 1024, true, IPreview::MODE_FILL, 2048, 512],
+ [2048, 1024, 4096, 1024, true, IPreview::MODE_COVER, 2048, 512],
+ ];
+ }
+
+ /**
+ * @dataProvider dataSize
+ *
+ * @param int $maxX
+ * @param int $maxY
+ * @param int $reqX
+ * @param int $reqY
+ * @param bool $crop
+ * @param string $mode
+ * @param int $expectedX
+ * @param int $expectedY
+ */
+ public function testCorrectSize($maxX, $maxY, $reqX, $reqY, $crop, $mode, $expectedX, $expectedY) {
+ $file = $this->createMock(File::class);
+ $file->method('getMimeType')
+ ->willReturn('myMimeType');
+ $file->method('getId')
+ ->willReturn(42);
+
+ $this->previewManager->method('isMimeSupported')
+ ->with($this->equalTo('myMimeType'))
+ ->willReturn(true);
+
+ $previewFolder = $this->createMock(ISimpleFolder::class);
+ $this->appData->method('getFolder')
+ ->with($this->equalTo(42))
+ ->willReturn($previewFolder);
+
+ $maxPreview = $this->createMock(ISimpleFile::class);
+ $maxPreview->method('getName')
+ ->willReturn($maxX . '-' . $maxY . '-max.png');
+
+ $previewFolder->method('getDirectoryListing')
+ ->willReturn([$maxPreview]);
+
+ $filename = $expectedX . '-' . $expectedY;
+ if ($crop) {
+ $filename .= '-crop';
+ }
+ $filename .= '.png';
+ $previewFolder->method('getFile')
+ ->with($this->equalTo($filename))
+ ->willThrowException(new NotFoundException());
+
+ $image = $this->createMock(IImage::class);
+ $this->helper->method('getImage')
+ ->with($this->equalTo($maxPreview))
+ ->willReturn($image);
+ $image->method('height')->willReturn($maxY);
+ $image->method('width')->willReturn($maxX);
+
+ $preview = $this->createMock(ISimpleFile::class);
+ $previewFolder->method('newFile')
+ ->with($this->equalTo($filename))
+ ->willReturn($preview);
+
+ $result = $this->generator->getPreview($file, $reqX, $reqY, $crop, $mode);
+ $this->assertSame($preview, $result);
+ }
+}
diff --git a/tests/lib/UrlGeneratorTest.php b/tests/lib/UrlGeneratorTest.php
index c8d5b8ece2c..28fd2d336d2 100644
--- a/tests/lib/UrlGeneratorTest.php
+++ b/tests/lib/UrlGeneratorTest.php
@@ -63,7 +63,7 @@ class UrlGeneratorTest extends \Test\TestCase {
public function provideRoutes() {
return array(
array('files_ajax_list', 'http://localhost/owncloud/index.php/apps/files/ajax/list.php'),
- array('core_ajax_preview', 'http://localhost/owncloud/index.php/core/preview.png'),
+ array('core.Preview.getPreview', 'http://localhost/owncloud/index.php/core/preview.png'),
);
}