diff --git a/lib/ClustersBackend/AlbumsBackend.php b/lib/ClustersBackend/AlbumsBackend.php index 34e40dc5..6f8c3226 100644 --- a/lib/ClustersBackend/AlbumsBackend.php +++ b/lib/ClustersBackend/AlbumsBackend.php @@ -24,6 +24,7 @@ declare(strict_types=1); namespace OCA\Memories\ClustersBackend; use OCA\Memories\Db\AlbumsQuery; +use OCA\Memories\Db\TimelineQuery; use OCA\Memories\Exceptions; use OCA\Memories\Util; use OCP\IRequest; @@ -32,13 +33,16 @@ class AlbumsBackend extends Backend { protected AlbumsQuery $albumsQuery; protected IRequest $request; + protected TimelineQuery $tq; public function __construct( AlbumsQuery $albumsQuery, - IRequest $request + IRequest $request, + TimelineQuery $tq ) { $this->albumsQuery = $albumsQuery; $this->request = $request; + $this->tq = $tq; } public static function appName(): string @@ -78,6 +82,9 @@ class AlbumsBackend extends Backend $query->expr()->eq('paf.album_id', $query->createNamedParameter($album['album_id'])), $query->expr()->eq('paf.file_id', 'm.fileid'), )); + + // Since we joined to the album, otherwise this is unsafe + $this->tq->allowEmptyRoot(); } public function getClusters(): array diff --git a/lib/Db/TimelineQuery.php b/lib/Db/TimelineQuery.php index 967c14c3..59c8bf15 100644 --- a/lib/Db/TimelineQuery.php +++ b/lib/Db/TimelineQuery.php @@ -24,7 +24,8 @@ class TimelineQuery protected IDBConnection $connection; protected IRequest $request; - private ?TimelineRoot $_root = null; + protected ?TimelineRoot $_root = null; + protected bool $_rootEmptyAllowed = false; public function __construct(IDBConnection $connection, IRequest $request) { @@ -32,16 +33,29 @@ class TimelineQuery $this->request = $request; } - public function root(): TimelineRoot + public function root(?TimelineRoot $override = null): TimelineRoot { + if (null !== $override) { + $this->_root = $override; + } + if (null === $this->_root) { $this->_root = new TimelineRoot(); $this->_root->populate(); } + if (!$this->_rootEmptyAllowed && $this->_root->isEmpty()) { + throw new \Exception('No valid root folder found (.nomedia?)'); + } + return $this->_root; } + public function allowEmptyRoot(bool $value = true) + { + $this->_rootEmptyAllowed = $value; + } + public function getBuilder() { return $this->connection->getQueryBuilder(); diff --git a/lib/Db/TimelineQueryDays.php b/lib/Db/TimelineQueryDays.php index 8d73222c..e0fe9a7e 100644 --- a/lib/Db/TimelineQueryDays.php +++ b/lib/Db/TimelineQueryDays.php @@ -35,7 +35,6 @@ trait TimelineQueryDays $query->select('m.dayid', $count) ->from('memories', 'm') ; - $query = $this->joinFilecache($query, null, $recursive, $archive); // Group and sort by dayid $query->groupBy('m.dayid') @@ -45,9 +44,11 @@ trait TimelineQueryDays // Apply all transformations $this->applyAllTransforms($queryTransforms, $query, true); - $cursor = $this->executeQueryWithCTEs($query); - $rows = $cursor->fetchAll(); - $cursor->closeCursor(); + // JOIN with filecache for existing files + $query = $this->joinFilecache($query, null, $recursive, $archive); + + // FETCH all days + $rows = $this->executeQueryWithCTEs($query)->fetchAll(); return $this->processDays($rows); } @@ -82,9 +83,6 @@ trait TimelineQueryDays ->from('memories', 'm') ; - // JOIN with filecache for existing files - $query = $this->joinFilecache($query, null, $recursive, $archive); - // JOIN with mimetypes to get the mimetype $query->join('f', 'mimetypes', 'mimetypes', $query->expr()->eq('f.mimetype', 'mimetypes.id')); @@ -106,6 +104,9 @@ trait TimelineQueryDays // Apply all transformations $this->applyAllTransforms($queryTransforms, $query, false); + // JOIN with filecache for existing files + $query = $this->joinFilecache($query, null, $recursive, $archive); + // FETCH all photos in this day $day = $this->executeQueryWithCTEs($query)->fetchAll(); @@ -150,14 +151,8 @@ trait TimelineQueryDays bool $recursive = true, bool $archive = false ): IQueryBuilder { - if (null === $root) { - $root = $this->root(); - } - - // Never join against an empty root - if (!$root || $root->isEmpty()) { - throw new \InvalidArgumentException('Timeline root is empty'); - } + // This will throw if the root is illegally empty + $root = $this->root($root); // Join with memories $baseOp = $query->expr()->eq('f.fileid', 'm.fileid');