Add albums transform

old-stable24
Varun Patil 2022-10-26 16:20:28 -07:00
parent 50bb55536f
commit 8d97dc7914
4 changed files with 101 additions and 32 deletions

View File

@ -95,6 +95,12 @@ class ApiController extends Controller
return new JSONResponse(['message' => 'Folder not found'], Http::STATUS_NOT_FOUND); return new JSONResponse(['message' => 'Folder not found'], Http::STATUS_NOT_FOUND);
} }
// Remove folder if album
// Permissions will be checked during the transform
if ($this->request->getParam('album')) {
$folder = null;
}
// Run actual query // Run actual query
try { try {
$list = $this->timelineQuery->getDays( $list = $this->timelineQuery->getDays(
@ -255,7 +261,6 @@ class ApiController extends Controller
/** /**
* @NoAdminRequired * @NoAdminRequired
* @NoCSRFRequired
* *
* Get list of albums with counts of images * Get list of albums with counts of images
*/ */
@ -672,12 +677,18 @@ class ApiController extends Controller
// Filter only for one tag // Filter only for one tag
if ($this->tagsIsEnabled()) { if ($this->tagsIsEnabled()) {
$tagName = $this->request->getParam('tag'); if ($tagName = $this->request->getParam('tag')) {
if ($tagName) {
$transforms[] = [$this->timelineQuery, 'transformTagFilter', $tagName]; $transforms[] = [$this->timelineQuery, 'transformTagFilter', $tagName];
} }
} }
// Filter for one album
if ($this->albumsIsEnabled()) {
if ($albumId = $this->request->getParam('album')) {
$transforms[] = [$this->timelineQuery, 'transformAlbumFilter', $albumId];
}
}
// Limit number of responses for day query // Limit number of responses for day query
$limit = $this->request->getParam('limit'); $limit = $this->request->getParam('limit');
if ($limit) { if ($limit) {
@ -687,8 +698,15 @@ class ApiController extends Controller
return $transforms; return $transforms;
} }
/** Preload a few "day" at the start of "days" response */ /**
private function preloadDays(array &$days, Folder &$folder, bool $recursive, bool $archive) * Preload a few "day" at the start of "days" response.
*
* @param array $days the days array
* @param null|Folder $folder the folder to search in
* @param bool $recursive search in subfolders
* @param bool $archive search in archive folder only
*/
private function preloadDays(array &$days, &$folder, bool $recursive, bool $archive)
{ {
$uid = $this->userSession->getUser()->getUID(); $uid = $this->userSession->getUser()->getUID();
$transforms = $this->getTransformations(false); $transforms = $this->getTransformations(false);
@ -696,13 +714,15 @@ class ApiController extends Controller
$preloadDayIds = []; $preloadDayIds = [];
$preloadDays = []; $preloadDays = [];
foreach ($days as &$day) { foreach ($days as &$day) {
if ($day['count'] <= 0) continue; if ($day['count'] <= 0) {
continue;
}
$preloaded += $day['count']; $preloaded += $day['count'];
$preloadDayIds[] = $day['dayid']; $preloadDayIds[] = $day['dayid'];
$preloadDays[] = &$day; $preloadDays[] = &$day;
if ($preloaded >= 50 || count($preloadDayIds) > 5) { // should be enough if ($preloaded >= 50 || \count($preloadDayIds) > 5) { // should be enough
break; break;
} }
} }

View File

@ -8,11 +8,11 @@ use OCP\IDBConnection;
class TimelineQuery class TimelineQuery
{ {
use TimelineQueryAlbums;
use TimelineQueryDays; use TimelineQueryDays;
use TimelineQueryFaces; use TimelineQueryFaces;
use TimelineQueryFilters; use TimelineQueryFilters;
use TimelineQueryTags; use TimelineQueryTags;
use TimelineQueryAlbums;
protected IDBConnection $connection; protected IDBConnection $connection;

View File

@ -4,12 +4,28 @@ declare(strict_types=1);
namespace OCA\Memories\Db; namespace OCA\Memories\Db;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection; use OCP\IDBConnection;
trait TimelineQueryAlbums trait TimelineQueryAlbums
{ {
protected IDBConnection $connection; protected IDBConnection $connection;
/** Transform only for album */
public function transformAlbumFilter(IQueryBuilder &$query, string $uid, string $albumId)
{
if (!$this->hasAlbumPermission($query->getConnection(), $uid, (int) $albumId)) {
throw new \Exception("Album {$albumId} not found");
}
// WHERE these are items with this album
$query->innerJoin('m', 'photos_albums_files', 'paf', $query->expr()->andX(
$query->expr()->eq('paf.album_id', $query->createNamedParameter($albumId)),
$query->expr()->eq('paf.file_id', 'm.fileid'),
));
}
/** Get list of albums */
public function getAlbums(string $uid) public function getAlbums(string $uid)
{ {
$query = $this->connection->getQueryBuilder(); $query = $this->connection->getQueryBuilder();
@ -20,7 +36,7 @@ trait TimelineQueryAlbums
$query->expr()->eq('user', $query->createNamedParameter($uid)), $query->expr()->eq('user', $query->createNamedParameter($uid)),
); );
// WHERE there are items with this tag // WHERE these are items with this album
$query->innerJoin('pa', 'photos_albums_files', 'paf', $query->expr()->andX( $query->innerJoin('pa', 'photos_albums_files', 'paf', $query->expr()->andX(
$query->expr()->eq('paf.album_id', 'pa.album_id'), $query->expr()->eq('paf.album_id', 'pa.album_id'),
)); ));
@ -29,7 +45,7 @@ trait TimelineQueryAlbums
$query->innerJoin('paf', 'memories', 'm', $query->expr()->eq('m.fileid', 'paf.file_id')); $query->innerJoin('paf', 'memories', 'm', $query->expr()->eq('m.fileid', 'paf.file_id'));
// WHERE these photos are in the filecache // WHERE these photos are in the filecache
$query->innerJoin('m', 'filecache', 'f', $query->expr()->eq('m.fileid', 'f.fileid'),); $query->innerJoin('m', 'filecache', 'f', $query->expr()->eq('m.fileid', 'f.fileid'));
// GROUP and ORDER by // GROUP and ORDER by
$query->groupBy('pa.album_id'); $query->groupBy('pa.album_id');
@ -48,4 +64,30 @@ trait TimelineQueryAlbums
return $albums; return $albums;
} }
private function hasAlbumPermission(IDBConnection $conn, string $uid, int $albumId)
{
// Check if owner
$query = $conn->getQueryBuilder();
$query->select('album_id')->from('photos_albums')->where(
$query->expr()->andX(
$query->expr()->eq('album_id', $query->createNamedParameter($albumId, IQueryBuilder::PARAM_INT)),
$query->expr()->eq('user', $query->createNamedParameter($uid)),
)
);
if (false !== $query->executeQuery()->fetchOne()) {
return true;
}
// Check in collaborators
$query = $conn->getQueryBuilder();
$query->select('album_id')->from('photos_collaborators')->where(
$query->expr()->andX(
$query->expr()->eq('album_id', $query->createNamedParameter($albumId, IQueryBuilder::PARAM_INT)),
$query->expr()->eq('collaborator_id', $query->createNamedParameter($uid)),
)
);
return false !== $query->executeQuery()->fetchOne();
}
} }

View File

@ -15,15 +15,15 @@ trait TimelineQueryDays
/** /**
* Get the days response from the database for the timeline. * Get the days response from the database for the timeline.
* *
* @param Folder $folder The folder to get the days from * @param null|Folder $folder The folder to get the days from
* @param bool $recursive Whether to get the days recursively * @param bool $recursive Whether to get the days recursively
* @param bool $archive Whether to get the days only from the archive folder * @param bool $archive Whether to get the days only from the archive folder
* @param array $queryTransforms An array of query transforms to apply to the query * @param array $queryTransforms An array of query transforms to apply to the query
* *
* @return array The days response * @return array The days response
*/ */
public function getDays( public function getDays(
Folder &$folder, &$folder,
string $uid, string $uid,
bool $recursive, bool $recursive,
bool $archive, bool $archive,
@ -56,18 +56,18 @@ trait TimelineQueryDays
/** /**
* Get the day response from the database for the timeline. * Get the day response from the database for the timeline.
* *
* @param Folder $folder The folder to get the day from * @param null|Folder $folder The folder to get the day from
* @param string $uid The user id * @param string $uid The user id
* @param int[] $dayid The day id * @param int[] $dayid The day id
* @param bool $recursive If the query should be recursive * @param bool $recursive If the query should be recursive
* @param bool $archive If the query should include only the archive folder * @param bool $archive If the query should include only the archive folder
* @param array $queryTransforms The query transformations to apply * @param array $queryTransforms The query transformations to apply
* @param mixed $day_ids * @param mixed $day_ids
* *
* @return array An array of day responses * @return array An array of day responses
*/ */
public function getDay( public function getDay(
Folder &$folder, &$folder,
string $uid, string $uid,
$day_ids, $day_ids,
bool $recursive, bool $recursive,
@ -227,10 +227,10 @@ trait TimelineQueryDays
/** /**
* Get the query for oc_filecache join. * Get the query for oc_filecache join.
* *
* @param IQueryBuilder $query Query builder * @param IQueryBuilder $query Query builder
* @param array|Folder $folder Either the top folder or array of folder Ids * @param null|array|Folder $folder Either the top folder or array of folder Ids
* @param bool $recursive Whether to get the days recursively * @param bool $recursive Whether to get the days recursively
* @param bool $archive Whether to get the days only from the archive folder * @param bool $archive Whether to get the days only from the archive folder
*/ */
private function getFilecacheJoinQuery( private function getFilecacheJoinQuery(
IQueryBuilder &$query, IQueryBuilder &$query,
@ -238,7 +238,14 @@ trait TimelineQueryDays
bool $recursive, bool $recursive,
bool $archive bool $archive
) { ) {
$pathQuery = null; // Join with memories
$baseOp = $query->expr()->eq('f.fileid', 'm.fileid');
if (null === $folder) {
return $baseOp; // No folder, get all
}
// Filter by folder (recursive or otherwise)
$pathOp = null;
if ($recursive) { if ($recursive) {
// Get all subfolder Ids recursively // Get all subfolder Ids recursively
$folderIds = []; $folderIds = [];
@ -250,15 +257,15 @@ trait TimelineQueryDays
} }
// Join with folder IDs // Join with folder IDs
$pathQuery = $query->expr()->in('f.parent', $query->createNamedParameter($folderIds, IQueryBuilder::PARAM_INT_ARRAY)); $pathOp = $query->expr()->in('f.parent', $query->createNamedParameter($folderIds, IQueryBuilder::PARAM_INT_ARRAY));
} else { } else {
// If getting non-recursively folder only check for parent // If getting non-recursively folder only check for parent
$pathQuery = $query->expr()->eq('f.parent', $query->createNamedParameter($folder->getId(), IQueryBuilder::PARAM_INT)); $pathOp = $query->expr()->eq('f.parent', $query->createNamedParameter($folder->getId(), IQueryBuilder::PARAM_INT));
} }
return $query->expr()->andX( return $query->expr()->andX(
$query->expr()->eq('f.fileid', 'm.fileid'), $baseOp,
$pathQuery, $pathOp,
); );
} }
} }