rootFolder = $rootFolder; $this->previewManager = $previewManager; } /** * @NoAdminRequired */ public function myAlbums(string $path = ''): JSONResponse { return $this->generate($path, false); } /** * @NoAdminRequired */ public function sharedAlbums(string $path = ''): JSONResponse { return $this->generate($path, true); } private function generate(string $path, bool $shared): JSONResponse { $userFolder = $this->rootFolder->getUserFolder($this->userId); $folder = $userFolder; if ($path !== '') { try { $folder = $userFolder->get($path); } catch (NotFoundException) { return new JSONResponse([], Http::STATUS_NOT_FOUND); } } $data = $this->scanCurrentFolder($folder, $shared); $result = $this->formatData($data); return new JSONResponse($result, Http::STATUS_OK); } private function formatData(iterable $nodes): array { $userFolder = $this->rootFolder->getUserFolder($this->userId); $result = []; /** @var Node $node */ foreach ($nodes as $node) { // properly format full path and make sure // we're relative to the user home folder $isRoot = $node === $userFolder; $path = $userFolder->getRelativePath($node->getPath()); $result[] = [ 'basename' => $isRoot ? '' : $node->getName(), 'etag' => $node->getEtag(), 'fileid' => $node->getId(), 'filename' => $path, 'lastmod' => $node->getMTime(), 'mime' => $node->getMimetype(), 'size' => $node->getSize(), 'type' => $node->getType(), 'permissions' => $this->formatPermissions($node->getPermissions()), 'hasPreview' => $this->previewManager->isAvailable($node), ]; } return $result; } private function formatPermissions(int $permissions): string { $strPermissions = ''; if ($permissions) { if ($permissions & Constants::PERMISSION_CREATE) { $strPermissions .= 'CK'; } if ($permissions & Constants::PERMISSION_READ) { $strPermissions .= 'G'; } if ($permissions & Constants::PERMISSION_UPDATE) { $strPermissions .= 'W'; } if ($permissions & Constants::PERMISSION_DELETE) { $strPermissions .= 'D'; } if ($permissions & Constants::PERMISSION_SHARE) { $strPermissions .= 'R'; } } return $strPermissions; } private function scanCurrentFolder(Folder $folder, bool $shared): iterable { $nodes = $folder->getDirectoryListing(); // add current folder to iterable set yield $folder; foreach ($nodes as $node) { if ($node instanceof Folder && $this->scanFolder($node, 0, $shared)) { yield $node; } elseif ($node instanceof File) { if ($this->validFile($node, $shared)) { yield $node; } } } } private function validFile(File $file, bool $shared): bool { $allowed_mimes = array_merge(Application::IMAGE_MIMES, Application::VIDEO_MIMES); if (in_array($file->getMimeType(), $allowed_mimes) && $this->isShared($file) === $shared) { return true; } return false; } private function isShared(Node $node): bool { /** * @psalm-suppress UndefinedClass * Adding the GroupFolderStorage class to the stubs would mean adding a lot of other classes. * This is enough for the current usage. */ return $node->getStorage()->instanceOfStorage(ISharedStorage::class) || $node->getStorage()->instanceOfStorage(\OCA\GroupFolders\Mount\GroupFolderStorage::class); } private function scanFolder(Folder $folder, int $depth, bool $shared): bool { if ($depth > 4) { return false; } try { // Ignore folder with a .noimage or .nomedia node if ($folder->nodeExists('.noimage') || $folder->nodeExists('.nomedia')) { return false; } $nodes = $folder->getDirectoryListing(); } catch (StorageNotAvailableException) { return false; } foreach ($nodes as $node) { if ($node instanceof File) { if ($this->validFile($node, $shared)) { return true; } } } foreach ($nodes as $node) { if ($node instanceof Folder && $this->isShared($node) === $shared) { if ($this->scanFolder($node, $depth + 1, $shared)) { return true; } } } return false; } }