From 0c6d5a57b58e22839de04df3de4ec7fa88ca7c39 Mon Sep 17 00:00:00 2001 From: Varun Patil Date: Tue, 15 Nov 2022 21:05:11 -0800 Subject: [PATCH] Fix filename of recursive mounts --- lib/Db/TimelineQueryDays.php | 98 ++++++++++++++++++++++++------------ src/components/Timeline.vue | 4 +- 2 files changed, 70 insertions(+), 32 deletions(-) diff --git a/lib/Db/TimelineQueryDays.php b/lib/Db/TimelineQueryDays.php index 23c405cb..dee83296 100644 --- a/lib/Db/TimelineQueryDays.php +++ b/lib/Db/TimelineQueryDays.php @@ -9,16 +9,18 @@ use OCP\Files\Folder; use OCP\IDBConnection; const CTE_FOLDERS = // CTE to get all folders recursively in the given top folders excluding archive - 'WITH RECURSIVE *PREFIX*cte_folders(fileid) AS ( + 'WITH RECURSIVE *PREFIX*cte_folders(fileid, rootid) AS ( SELECT - f.fileid + f.fileid, + f.fileid AS rootid FROM *PREFIX*filecache f WHERE f.fileid IN (:topFolderIds) UNION ALL SELECT - f.fileid + f.fileid, + c.rootid FROM *PREFIX*filecache f INNER JOIN *PREFIX*cte_folders c @@ -65,6 +67,9 @@ trait TimelineQueryDays { protected IDBConnection $connection; + /** Map of rootid => mount point */ + private $topFolderPaths = []; + /** * Get the days response from the database for the timeline. * @@ -196,30 +201,51 @@ trait TimelineQueryDays */ private function processDay(&$day, $uid, $folder) { - $basePath = '#__#__#'; - $davPath = ''; + /** + * Path entry in database for folder. + * We need to splice this from the start of the file path. + */ + $internalPaths = []; + + /** + * DAV paths for the folders. + * We need to prefix this to the start of the file path. + */ + $davPaths = []; + + /** + * The root folder id for the folder. + * We fallback to this if rootid is not found + */ + $defaultRootId = 0; + if (null !== $folder) { + // Get root id of the top folder + $defaultRootId = $folder->getId(); + // No way to get the internal path from the folder $query = $this->connection->getQueryBuilder(); - $query->select('path') + $query->select('fileid', 'path') ->from('filecache') - ->where($query->expr()->eq('fileid', $query->createNamedParameter($folder->getId(), IQueryBuilder::PARAM_INT))) + ->where($query->expr()->in('fileid', $query->createNamedParameter(array_keys($this->topFolderPaths), IQueryBuilder::PARAM_INT_ARRAY))) ; - $path = $query->executeQuery()->fetchOne(); - $basePath = $path ?: $basePath; + $paths = $query->executeQuery()->fetchAll(); + foreach ($paths as &$path) { + $fileid = (int) $path['fileid']; + $internalPaths[$fileid] = $path['path']; - // Get user facing path - // getPath looks like /user/files/... but we want /files/user/... - // Split at / and swap these - // For public shares, we just give the relative path - if (!empty($uid)) { - $actualPath = $folder->getPath(); - $actualPath = explode('/', $actualPath); - if (\count($actualPath) >= 3) { - $tmp = $actualPath[1]; - $actualPath[1] = $actualPath[2]; - $actualPath[2] = $tmp; - $davPath = implode('/', $actualPath); + // Get DAV path. + // getPath looks like /user/files/... but we want /files/user/... + // Split at / and swap these + // For public shares, we just give the relative path + if (!empty($uid) && ($actualPath = $this->topFolderPaths[$fileid])) { + $actualPath = explode('/', $actualPath); + if (\count($actualPath) >= 3) { + $tmp = $actualPath[1]; + $actualPath[1] = $actualPath[2]; + $actualPath[2] = $tmp; + $davPaths[$fileid] = implode('/', $actualPath); + } } } } @@ -245,9 +271,14 @@ trait TimelineQueryDays // Check if path exists and starts with basePath and remove if (isset($row['path']) && !empty($row['path'])) { + $rootId = $row['rootid'] ?: $defaultRootId; + $basePath = $internalPaths[$rootId] ?: '#__#'; + $davPath = $davPaths[$rootId] ?: ''; + if (0 === strpos($row['path'], $basePath)) { $row['filename'] = $davPath.substr($row['path'], \strlen($basePath)); } + unset($row['path']); } @@ -280,18 +311,10 @@ trait TimelineQueryDays */ private function addSubfolderJoinParams( IQueryBuilder &$query, - Folder &$folder, bool $archive ) { - // Get storages recursively - $topFolderIds = [$folder->getId()]; - $mounts = \OC\Files\Filesystem::getMountManager()->findIn($folder->getPath()); - foreach ($mounts as &$mount) { - $topFolderIds[] = $mount->getStorageRootId(); - } - // Add query parameters - $query->setParameter('topFolderIds', $topFolderIds, IQueryBuilder::PARAM_INT_ARRAY); + $query->setParameter('topFolderIds', array_keys($this->topFolderPaths), IQueryBuilder::PARAM_INT_ARRAY); $query->setParameter('cteFoldersArchive', $archive, IQueryBuilder::PARAM_BOOL); } @@ -315,12 +338,25 @@ trait TimelineQueryDays return $query->innerJoin('m', 'filecache', 'f', $baseOp); } + // Create top folders paths for later processing + $this->topFolderPaths = []; + $this->topFolderPaths[$folder->getId()] = $folder->getPath(); + // Filter by folder (recursive or otherwise) $pathOp = null; if ($recursive) { + // Add mountpoints recursively + $this->mounts = \OC\Files\Filesystem::getMountManager()->findIn($folder->getPath()); + foreach ($this->mounts as &$mount) { + $id = $mount->getStorageRootId(); + $path = $mount->getMountPoint(); + $this->topFolderPaths[$id] = $path; + } + // Join with folders CTE - $this->addSubfolderJoinParams($query, $folder, $archive); + $this->addSubfolderJoinParams($query, $archive); $query->innerJoin('f', 'cte_folders', 'cte_f', $query->expr()->eq('f.parent', 'cte_f.fileid')); + $query->addSelect('cte_f.rootid'); } else { // If getting non-recursively folder only check for parent $pathOp = $query->expr()->eq('f.parent', $query->createNamedParameter($folder->getId(), IQueryBuilder::PARAM_INT)); diff --git a/src/components/Timeline.vue b/src/components/Timeline.vue index 419ef280..c7bbd2df 100644 --- a/src/components/Timeline.vue +++ b/src/components/Timeline.vue @@ -917,7 +917,9 @@ export default class Timeline extends Mixins(GlobalMixin, UserConfig) { head.day.detail.length === photos.length && head.day.detail.every( (p, i) => - p.fileid === photos[i].fileid && p.etag === photos[i].etag + p.fileid === photos[i].fileid && + p.etag === photos[i].etag && + p.filename === photos[i].filename ) ) { continue;