diff options
-rw-r--r-- | appinfo/application.php | 13 | ||||
-rw-r--r-- | controller/filescontroller.php | 14 | ||||
-rw-r--r-- | environment/environment.php | 10 | ||||
-rw-r--r-- | preview/preview.php | 2 | ||||
-rw-r--r-- | service/configservice.php | 12 | ||||
-rw-r--r-- | service/filesservice.php | 241 | ||||
-rw-r--r-- | service/searchmediaservice.php | 229 | ||||
-rw-r--r-- | service/service.php | 68 |
8 files changed, 343 insertions, 246 deletions
diff --git a/appinfo/application.php b/appinfo/application.php index 8313bec4..5f68d68a 100644 --- a/appinfo/application.php +++ b/appinfo/application.php @@ -28,6 +28,7 @@ use OCA\GalleryPlus\Environment\Environment; use OCA\GalleryPlus\Preview\Preview; use OCA\GalleryPlus\Service\FilesService; use OCA\GalleryPlus\Service\ConfigService; +use OCA\GalleryPlus\Service\SearchMediaService; use OCA\GalleryPlus\Service\ThumbnailService; use OCA\GalleryPlus\Service\PreviewService; use OCA\GalleryPlus\Service\DownloadService; @@ -73,6 +74,7 @@ class Application extends App { $c->query('Request'), $c->query('FilesService'), $c->query('ConfigService'), + $c->query('SearchMediaService'), $c->query('SmarterLogger') ); } @@ -84,6 +86,7 @@ class Application extends App { $c->query('Request'), $c->query('FilesService'), $c->query('ConfigService'), + $c->query('SearchMediaService'), $c->query('SmarterLogger') ); } @@ -229,6 +232,16 @@ class Application extends App { } ); $container->registerService( + 'SearchMediaService', function (IContainer $c) { + return new SearchMediaService( + $c->query('AppName'), + $c->query('Environment'), + $c->query('SmarterLogger') + + ); + } + ); + $container->registerService( 'ThumbnailService', function () { return new ThumbnailService(); } diff --git a/controller/filescontroller.php b/controller/filescontroller.php index 7e6c032b..55b13cc8 100644 --- a/controller/filescontroller.php +++ b/controller/filescontroller.php @@ -23,6 +23,7 @@ use OCP\AppFramework\Http\JSONResponse; use OCA\GalleryPlus\Service\FilesService; use OCA\GalleryPlus\Service\ConfigService; +use OCA\GalleryPlus\Service\SearchMediaService; use OCA\GalleryPlus\Utility\SmarterLogger; /** @@ -42,6 +43,10 @@ class FilesController extends Controller { * @type ConfigService */ private $configService; + /** + * @type SearchMediaService + */ + private $searchMediaService; /** * Constructor @@ -50,6 +55,7 @@ class FilesController extends Controller { * @param IRequest $request * @param FilesService $filesService * @param ConfigService $configService + * @param SearchMediaService $searchMediaService * @param SmarterLogger $logger */ public function __construct( @@ -57,12 +63,14 @@ class FilesController extends Controller { IRequest $request, FilesService $filesService, ConfigService $configService, + SearchMediaService $searchMediaService, SmarterLogger $logger ) { parent::__construct($appName, $request); $this->filesService = $filesService; $this->configService = $configService; + $this->searchMediaService = $searchMediaService; //$this->logger = $logger; } @@ -98,9 +106,11 @@ class FilesController extends Controller { list($albumInfo, $privateAlbum) = $this->configService->getAlbumInfo($folderNode, $folderPathFromRoot); if ($privateAlbum) { - return new JSONResponse(['message' => 'Album is private', 'success' => false], 403); + return new JSONResponse( + ['message' => 'Album is private or unavailable', 'success' => false], 403 + ); } - $files = $this->filesService->getMediaFiles($folderNode, $mediaTypesArray); + $files = $this->searchMediaService->getMediaFiles($folderNode, $mediaTypesArray); return $this->formatResults($files, $albumInfo, $locationHasChanged); } catch (\Exception $exception) { diff --git a/environment/environment.php b/environment/environment.php index d82cdb2a..f51cf240 100644 --- a/environment/environment.php +++ b/environment/environment.php @@ -255,14 +255,14 @@ class Environment { * * That root folder changes when folders are shared publicly * - * @param Node $file + * @param File|Folder $node * * @return string */ - public function getPathFromVirtualRoot($file) { - $path = $file->getPath(); + public function getPathFromVirtualRoot($node) { + $path = $node->getPath(); - if ($file->getType() === 'dir') { + if ($node->getType() === 'dir') { // Needed because fromRootToFolder always ends with a slash $path .= '/'; } @@ -318,7 +318,7 @@ class Environment { * * @param int $resourceId * - * @return Node + * @return File|Folder * * @throws EnvironmentException */ diff --git a/preview/preview.php b/preview/preview.php index a9c633cd..d6bbcd9e 100644 --- a/preview/preview.php +++ b/preview/preview.php @@ -186,7 +186,7 @@ class Preview { * @return \OC_Image */ private function getPreviewFromCore($keepAspect) { - $this->logger->debug("[PreviewService] Fetching the preview"); + //$this->logger->debug("[PreviewService] Fetching the preview"); list($maxX, $maxY) = $this->dims; $this->preview->setMaxX($maxX); diff --git a/service/configservice.php b/service/configservice.php index 511751d5..b599ed85 100644 --- a/service/configservice.php +++ b/service/configservice.php @@ -25,7 +25,7 @@ use OCP\Files\File; * * @package OCA\GalleryPlus\Service */ -class ConfigService extends Service { +class ConfigService extends FilesService { /** * @type int @@ -85,8 +85,8 @@ class ConfigService extends Service { private function getAlbumConfig( $folder, $privacyChecker, $configName, $configItems, $level = 0, $config = [] ) { - if ($folder->nodeExists($privacyChecker)) { - // Cancel as soon as we find out that the folder is private + if (!$this->isLocalAndAvailable($folder) || $folder->nodeExists($privacyChecker)) { + // Cancel as soon as we find out that the folder is private or external return [null, true]; } $isRootFolder = $this->isRootFolder($folder, $level); @@ -135,7 +135,7 @@ class ConfigService extends Service { * @param Folder $folder * @param string $configName * @param array $currentConfig - * @param array<string,bool> $configItems + * @param array <string,bool> $configItems * @param int $level * @param bool $isRootFolder * @@ -192,7 +192,7 @@ class ConfigService extends Service { * @param Folder $folder * @param string $privacyChecker * @param string $configName - * @param array<string,bool> $configItems + * @param array <string,bool> $configItems * @param int $level * @param array $config * @@ -232,7 +232,7 @@ class ConfigService extends Service { * * @param array $currentConfig * @param array $parsedConfig - * @param array<string,bool> $configItems + * @param array <string,bool> $configItems * @param int $level * @param bool $isRootFolder * diff --git a/service/filesservice.php b/service/filesservice.php index 45a3330b..8a05a2f4 100644 --- a/service/filesservice.php +++ b/service/filesservice.php @@ -13,71 +13,49 @@ namespace OCA\GalleryPlus\Service; use OCP\Files\Folder; -use OCP\Files\File; use OCP\Files\Node; +use OCA\GalleryPlus\Environment\NotFoundEnvException; + /** - * Contains various methods which provide initial information about the - * supported media types, the folder permissions and the images contained in - * the system + * Contains various methods to retrieve information from the filesystem * * @package OCA\GalleryPlus\Service */ class FilesService extends Service { /** - * @type null|array<string,string|int> - */ - private $images = []; - /** - * @type string[] - */ - private $supportedMediaTypes; - - /** - * This returns the list of all media files which can be shown starting from the given folder + * This returns the current folder node based on a path * - * @param Folder $folder - * @param string[] $supportedMediaTypes + * If the path leads to a file, we'll return the node of the containing folder * - * @return array<string,string|int> all the images we could find - */ - public function getMediaFiles($folder, $supportedMediaTypes) { - $this->supportedMediaTypes = $supportedMediaTypes; - - $this->searchFolder($folder); - - return $this->images; - } - - /** - * Look for media files and folders in the given folder + * If we can't find anything, we try with the parent folder, up to the root or until we reach + * our recursive limit * - * @param Folder $folder - * @param int $subDepth + * @param string $location + * @param int $depth * - * @return int + * @return array <Folder,string,bool> */ - private function searchFolder($folder, $subDepth = 0) { - $albumImageCounter = 0; - $subFolders = []; - - $nodes = $this->getNodes($folder, $subDepth); - foreach ($nodes as $node) { - //$this->logger->debug("Sub-Node path : {path}", ['path' => $node->getPath()]); - $nodeType = $this->getNodeType($node); - $subFolders = array_merge($subFolders, $this->getAllowedSubFolder($node, $nodeType)); - - if ($nodeType === 'file') { - $albumImageCounter = $albumImageCounter + (int)$this->isPreviewAvailable($node); - if ($this->haveEnoughPictures($albumImageCounter, $subDepth)) { - break; - } + public function getCurrentFolder($location, $depth = 0) { + $node = null; + $location = $this->validateLocation($location, $depth); + try { + $node = $this->environment->getResourceFromPath($location); + if ($node->getType() === 'file') { + $node = $node->getParent(); } + } catch (NotFoundEnvException $exception) { + // There might be a typo in the file or folder name + $folder = pathinfo($location, PATHINFO_DIRNAME); + $depth++; + + return $this->getCurrentFolder($folder, $depth); } - $albumImageCounter = $this->searchSubFolders($subFolders, $subDepth, $albumImageCounter); + $path = $this->environment->getPathFromVirtualRoot($node); + $locationHasChanged = $this->hasLocationChanged($depth); - return $albumImageCounter; + return [$path, $node, $locationHasChanged]; } /** @@ -94,15 +72,9 @@ class FilesService extends Service { * * @throws NotFoundServiceException */ - private function getNodes($folder, $subDepth) { - $nodes = []; + protected function getNodes($folder, $subDepth) { try { - if ($folder->isReadable() - && $folder->getStorage() - ->isLocal() - ) { $nodes = $folder->getDirectoryListing(); - } } catch (\Exception $exception) { $nodes = $this->recoverFromGetNodesError($subDepth, $exception); } @@ -111,21 +83,24 @@ class FilesService extends Service { } /** - * Throws an exception if this problem occurs in the current folder, otherwise just ignores the - * sub-folder + * Determines if the files are hosted locally (shared or not) * - * @param int $subDepth - * @param \Exception $exception + * isMounted() includes externally hosted shares, so we need to exclude those * - * @return array - * @throws NotFoundServiceException + * @param Node $node + * + * @return bool */ - private function recoverFromGetNodesError($subDepth, $exception) { - if ($subDepth === 0) { - $this->logAndThrowNotFound($exception->getMessage()); + protected function isLocalAndAvailable($node) { + if (!$node->isMounted() && $node->isReadable()) { + if ($this->isExternalShare($node)) { + return false; + } + + return true; } - return []; + return false; } /** @@ -137,7 +112,7 @@ class FilesService extends Service { * * @return string */ - private function getNodeType($node) { + protected function getNodeType($node) { try { $nodeType = $node->getType(); } catch (\Exception $exception) { @@ -155,7 +130,7 @@ class FilesService extends Service { * * @return array|Folder */ - private function getAllowedSubFolder($node, $nodeType) { + protected function getAllowedSubFolder($node, $nodeType) { if ($nodeType === 'dir') { /** @type Folder $node */ if (!$node->nodeExists('.nomedia')) { @@ -167,135 +142,73 @@ class FilesService extends Service { } /** - * Checks if we've collected enough pictures to be able to build the view - * - * An album is full when we find max 4 pictures at the same level + * Makes sure we don't go too far up before giving up * - * @param int $albumImageCounter - * @param int $subDepth + * @param string $location + * @param int $depth * - * @return bool - */ - private function haveEnoughPictures($albumImageCounter, $subDepth) { - if ($subDepth === 0) { - return false; - } - if ($albumImageCounter === 4) { - return true; - } - - return false; - } - - /** - * Looks for pictures in sub-folders - * - * If we're at level 0, we need to look for pictures in sub-folders no matter what - * If we're at deeper levels, we only need to go further if we haven't managed to find one - * picture in the current folder - * - * @param array <Folder> $subFolders - * @param int $subDepth - * @param int $albumImageCounter - * - * @return int + * @return string */ - private function searchSubFolders($subFolders, $subDepth, $albumImageCounter) { - if ($this->folderNeedsToBeSearched($subFolders, $subDepth, $albumImageCounter)) { - $subDepth++; - foreach ($subFolders as $subFolder) { - $albumImageCounter = $this->searchFolder($subFolder, $subDepth); - if ($this->abortSearch($subDepth, $albumImageCounter)) { - break; - } - } + private function validateLocation($location, $depth) { + if ($depth === 4) { + // We can't find anything, so we decide to return data for the root folder + $location = ''; } - return $albumImageCounter; + return $location; } /** - * Checks if we need to look for media files in the specified folder - * - * @param array <Folder> $subFolders - * @param int $subDepth - * @param int $albumImageCounter + * @param $depth * * @return bool */ - private function folderNeedsToBeSearched($subFolders, $subDepth, $albumImageCounter) { - if (!empty($subFolders) && ($subDepth === 0 || $albumImageCounter === 0)) { - return true; + private function hasLocationChanged($depth) { + $locationHasChanged = false; + if ($depth > 0) { + $locationHasChanged = true; } - return false; + return $locationHasChanged; } /** - * Returns true if there is no need to check any other sub-folder at the same depth level + * Throws an exception if this problem occurs in the current folder, otherwise just ignores the + * sub-folder * * @param int $subDepth - * @param int $count + * @param \Exception $exception * - * @return bool + * @return array + * @throws NotFoundServiceException */ - private function abortSearch($subDepth, $count) { - if ($subDepth > 1 && $count > 0) { - return true; + private function recoverFromGetNodesError($subDepth, $exception) { + if ($subDepth === 0) { + $this->logAndThrowNotFound($exception->getMessage()); } - return false; + return []; } /** - * Returns true if the file is of a supported media type and adds it to the array of items to - * return + * Determines if the node is a share which is hosted externally * - * @todo We could potentially check if the file is readable ($file->stat() maybe) in order to - * only return valid files, but this may slow down operations - * - * @param File $file the file to test + * @param Node $node * * @return bool */ - private function isPreviewAvailable($file) { - try { - $mimeType = $file->getMimetype(); - $isLocal = $file->getStorage() - ->isLocal(); - if ($isLocal && in_array($mimeType, $this->supportedMediaTypes)) { - $this->addFileToResults($file); - - return true; - } - } catch (\Exception $exception) { - return false; + private function isExternalShare($node) { + $sid = explode( + ':', + $node->getStorage() + ->getId() + ); + + if ($sid[0] === 'shared' && $sid[2][0] !== '/') { + return true; } return false; } - /** - * Adds various information about a file to the list of results - * - * @param File $file - */ - private function addFileToResults($file) { - $imagePath = $this->environment->getPathFromVirtualRoot($file); - $imageId = $file->getId(); - $mimeType = $file->getMimetype(); - $mTime = $file->getMTime(); - - $imageData = [ - 'path' => $imagePath, - 'fileid' => $imageId, - 'mimetype' => $mimeType, - 'mtime' => $mTime - ]; - - $this->images[] = $imageData; - - //$this->logger->debug("Image path : {path}", ['path' => $imagePath]); - } - } diff --git a/service/searchmediaservice.php b/service/searchmediaservice.php new file mode 100644 index 00000000..fe572492 --- /dev/null +++ b/service/searchmediaservice.php @@ -0,0 +1,229 @@ +<?php +/** + * ownCloud - galleryplus + * + * This file is licensed under the Affero General Public License version 3 or + * later. See the COPYING file. + * + * @author Olivier Paroz <owncloud@interfasys.ch> + * + * @copyright Olivier Paroz 2014-2015 + */ + +namespace OCA\GalleryPlus\Service; + +use OCP\Files\Folder; +use OCP\Files\File; +use OCP\Files\Node; + +/** + * Searches the instance for media files which can be shown + * + * @package OCA\GalleryPlus\Service + */ +class SearchMediaService extends FilesService { + + /** + * @type null|array<string,string|int> + */ + private $images = []; + /** + * @type string[] + */ + private $supportedMediaTypes; + + /** + * This returns the list of all media files which can be shown starting from the given folder + * + * @param Folder $folder + * @param string[] $supportedMediaTypes + * + * @return array<string,string|int> all the images we could find + */ + public function getMediaFiles($folder, $supportedMediaTypes) { + $this->supportedMediaTypes = $supportedMediaTypes; + $this->searchFolder($folder); + + return $this->images; + } + + /** + * Look for media files and folders in the given folder + * + * @param Folder $folder + * @param int $subDepth + * + * @return int + */ + private function searchFolder($folder, $subDepth = 0) { + $albumImageCounter = 0; + $subFolders = []; + + $nodes = $this->getNodes($folder, $subDepth); + foreach ($nodes as $node) { + if (!$this->isLocalAndAvailable($node)) { + continue; + } + //$this->logger->debug("Sub-Node path : {path}", ['path' => $node->getPath()]); + $nodeType = $this->getNodeType($node); + $subFolders = array_merge($subFolders, $this->getAllowedSubFolder($node, $nodeType)); + $albumImageCounter = $this->addMediaFiles($node, $nodeType, $albumImageCounter); + if ($this->haveEnoughPictures($albumImageCounter, $subDepth)) { + break; + } + + } + $albumImageCounter = $this->searchSubFolders($subFolders, $subDepth, $albumImageCounter); + + return $albumImageCounter; + } + + /** + * Fills the album with images and + * + * @param $node + * @param $nodeType + * @param $albumImageCounter + * + * @return bool + */ + private function addMediaFiles($node, $nodeType, $albumImageCounter) { + if ($nodeType === 'file') { + $albumImageCounter = $albumImageCounter + (int)$this->isPreviewAvailable($node); + } + + return $albumImageCounter; + } + + /** + * Checks if we've collected enough pictures to be able to build the view + * + * An album is full when we find max 4 pictures at the same level + * + * @param int $albumImageCounter + * @param int $subDepth + * + * @return bool + */ + private function haveEnoughPictures($albumImageCounter, $subDepth) { + if ($subDepth === 0) { + return false; + } + if ($albumImageCounter === 4) { + return true; + } + + return false; + } + + /** + * Looks for pictures in sub-folders + * + * If we're at level 0, we need to look for pictures in sub-folders no matter what + * If we're at deeper levels, we only need to go further if we haven't managed to find one + * picture in the current folder + * + * @param array <Folder> $subFolders + * @param int $subDepth + * @param int $albumImageCounter + * + * @return int + */ + private function searchSubFolders($subFolders, $subDepth, $albumImageCounter) { + if ($this->folderNeedsToBeSearched($subFolders, $subDepth, $albumImageCounter)) { + $subDepth++; + foreach ($subFolders as $subFolder) { + //$this->logger->debug("Sub-Node path : {path}", ['path' => $subFolder->getPath()]); + $albumImageCounter = $this->searchFolder($subFolder, $subDepth); + if ($this->abortSearch($subDepth, $albumImageCounter)) { + break; + } + } + } + + return $albumImageCounter; + } + + /** + * Checks if we need to look for media files in the specified folder + * + * @param array <Folder> $subFolders + * @param int $subDepth + * @param int $albumImageCounter + * + * @return bool + */ + private function folderNeedsToBeSearched($subFolders, $subDepth, $albumImageCounter) { + if (!empty($subFolders) && ($subDepth === 0 || $albumImageCounter === 0)) { + return true; + } + + return false; + } + + /** + * Returns true if there is no need to check any other sub-folder at the same depth level + * + * @param int $subDepth + * @param int $count + * + * @return bool + */ + private function abortSearch($subDepth, $count) { + if ($subDepth > 1 && $count > 0) { + return true; + } + + return false; + } + + /** + * Returns true if the file is of a supported media type and adds it to the array of items to + * return + * + * @todo We could potentially check if the file is readable ($file->stat() maybe) in order to + * only return valid files, but this may slow down operations + * + * @param File $file the file to test + * + * @return bool + */ + private function isPreviewAvailable($file) { + try { + $mimeType = $file->getMimetype(); + if (in_array($mimeType, $this->supportedMediaTypes)) { + $this->addFileToResults($file); + + return true; + } + } catch (\Exception $exception) { + return false; + } + + return false; + } + + /** + * Adds various information about a file to the list of results + * + * @param File $file + */ + private function addFileToResults($file) { + $imagePath = $this->environment->getPathFromVirtualRoot($file); + $imageId = $file->getId(); + $mimeType = $file->getMimetype(); + $mTime = $file->getMTime(); + + $imageData = [ + 'path' => $imagePath, + 'fileid' => $imageId, + 'mimetype' => $mimeType, + 'mtime' => $mTime + ]; + + $this->images[] = $imageData; + + //$this->logger->debug("Image path : {path}", ['path' => $imagePath]); + } + +} diff --git a/service/service.php b/service/service.php index 11d970c5..7f022fed 100644 --- a/service/service.php +++ b/service/service.php @@ -12,10 +12,7 @@ namespace OCA\GalleryPlus\Service; -use OCP\Files\Folder; - use OCA\GalleryPlus\Environment\Environment; -use OCA\GalleryPlus\Environment\NotFoundEnvException; use OCA\GalleryPlus\Utility\SmarterLogger; /** @@ -56,40 +53,6 @@ abstract class Service { } /** - * This returns the current folder node based on a path - * - * If the path leads to a file, we'll return the node of the containing folder - * - * If we can't find anything, we try with the parent folder, up to the root or until we reach - * our recursive limit - * - * @param string $location - * @param int $depth - * - * @return array <Folder,string,bool> - */ - public function getCurrentFolder($location, $depth = 0) { - $node = null; - $location = $this->validateLocation($location, $depth); - try { - $node = $this->environment->getResourceFromPath($location); - if ($node->getType() === 'file') { - $node = $node->getParent(); - } - } catch (NotFoundEnvException $exception) { - // There might be a typo in the file or folder name - $folder = pathinfo($location, PATHINFO_DIRNAME); - $depth++; - - return $this->getCurrentFolder($folder, $depth); - } - $path = $this->environment->getPathFromVirtualRoot($node); - $locationHasChanged = $this->hasLocationChanged($depth); - - return [$path, $node, $locationHasChanged]; - } - - /** * Logs the error and raises a "Not found" type exception * * @param string $message @@ -102,35 +65,4 @@ abstract class Service { throw new NotFoundServiceException($message); } - /** - * Makes sure we don't go too far up before giving up - * - * @param string $location - * @param int $depth - * - * @return string - */ - private function validateLocation($location, $depth) { - if ($depth === 4) { - // We can't find anything, so we decide to return data for the root folder - $location = ''; - } - - return $location; - } - - /** - * @param $depth - * - * @return bool - */ - private function hasLocationChanged($depth) { - $locationHasChanged = false; - if ($depth > 0) { - $locationHasChanged = true; - } - - return $locationHasChanged; - } - } |