Use separate tag preview endpoint

old-stable24
Varun Patil 2022-10-27 13:26:51 -07:00
parent 46eb0fd97a
commit a0d757adfc
4 changed files with 90 additions and 54 deletions

View File

@ -30,6 +30,7 @@ return [
['name' => 'api#day', 'url' => '/api/days/{id}', 'verb' => 'GET'],
['name' => 'api#tags', 'url' => '/api/tags', 'verb' => 'GET'],
['name' => 'api#tagPreviews', 'url' => '/api/tag-previews', 'verb' => 'GET'],
['name' => 'api#albums', 'url' => '/api/albums', 'verb' => 'GET'],

View File

@ -253,8 +253,40 @@ class ApiController extends Controller
$folder,
);
// Preload all tag previews
$this->timelineQuery->getTagPreviews($list, $folder);
return new JSONResponse($list, Http::STATUS_OK);
}
/**
* @NoAdminRequired
*
* Get previews for a tag
*/
public function tagPreviews(): JSONResponse
{
$user = $this->userSession->getUser();
if (null === $user) {
return new JSONResponse([], Http::STATUS_PRECONDITION_FAILED);
}
// Check tags enabled for this user
if (!$this->tagsIsEnabled()) {
return new JSONResponse(['message' => 'Tags not enabled for user'], Http::STATUS_PRECONDITION_FAILED);
}
// If this isn't the timeline folder then things aren't going to work
$folder = $this->getRequestFolder();
if (null === $folder) {
return new JSONResponse([], Http::STATUS_NOT_FOUND);
}
// Get the tag
$tagName = $this->request->getParam('tag');
// Run actual query
$list = $this->timelineQuery->getTagPreviews(
$tagName,
$folder,
);
return new JSONResponse($list, Http::STATUS_OK);
}

View File

@ -88,66 +88,46 @@ trait TimelineQueryTags
return $tags;
}
public function getTagPreviews(array &$tags, Folder &$folder)
public function getTagPreviews(string $tagName, Folder &$folder)
{
// This is really horrible but will have to do for now
$sql = '';
foreach ($tags as &$tag) {
if (!empty($sql)) {
$sql .= ' UNION ALL ';
}
$query = $this->connection->getQueryBuilder();
// SELECT all photos with this tag
$query->select('f.fileid', 'f.etag', 'stom.systemtagid')->from(
'systemtag_object_mapping',
'stom'
)->where(
$query->expr()->eq('stom.objecttype', $query->createNamedParameter('files')),
$query->expr()->eq('stom.systemtagid', $query->createNamedParameter($tag['id'])),
);
// WHERE these items are memories indexed photos
$query->innerJoin('stom', 'memories', 'm', $query->expr()->eq('m.fileid', 'stom.objectid'));
// WHERE these photos are in the user's requested folder recursively
// See the function above for an explanation of this hack
$this->addSubfolderJoinParams($query, $folder, false);
$query->innerJoin('m', 'filecache', 'f', $query->expr()->andX(
$query->expr()->eq('f.fileid', 'm.fileid'),
$query->createFunction('EXISTS (SELECT 1 from *PREFIX*cte_folders WHERE *PREFIX*cte_folders.fileid = `f`.parent)')
));
// MAX 4
$query->setMaxResults(4);
// Replace parameters
$thisSql = self::replaceQueryParams($query, $query->getSQL());
// Add clause
$sql .= "({$thisSql})";
$query = $this->connection->getQueryBuilder();
$tagId = $this->getSystemTagId($query, $tagName);
if (false === $tagId) {
return [];
}
// SELECT all photos with this tag
$query->select('f.fileid', 'f.etag', 'stom.systemtagid')->from(
'systemtag_object_mapping',
'stom'
)->where(
$query->expr()->eq('stom.objecttype', $query->createNamedParameter('files')),
$query->expr()->eq('stom.systemtagid', $query->createNamedParameter($tagId)),
);
// WHERE these items are memories indexed photos
$query->innerJoin('stom', 'memories', 'm', $query->expr()->eq('m.fileid', 'stom.objectid'));
// WHERE these photos are in the user's requested folder recursively
// See the function above for an explanation of this hack
$this->addSubfolderJoinParams($query, $folder, false);
$query->innerJoin('m', 'filecache', 'f', $query->expr()->andX(
$query->expr()->eq('f.fileid', 'm.fileid'),
$query->createFunction('EXISTS (SELECT 1 from *PREFIX*cte_folders WHERE *PREFIX*cte_folders.fileid = `f`.parent)')
));
// MAX 4
$query->setMaxResults(4);
// FETCH tag previews
$cursor = $this->executeQueryWithCTEs($query, $sql);
$cursor = $this->executeQueryWithCTEs($query);
$ans = $cursor->fetchAll();
// Post-process
$previewMap = [];
foreach ($ans as &$row) {
$row['fileid'] = (int) $row['fileid'];
$key = (int) $row['systemtagid'];
unset($row['systemtagid']);
if (!isset($previewMap[$key])) {
$previewMap[$key] = [];
}
$previewMap[$key][] = $row;
}
// Add previews to tags
foreach ($tags as &$tag) {
$tag['previews'] = $previewMap[$tag['id']] ?? [];
}
return $ans;
}
}

View File

@ -34,7 +34,9 @@ import { generateUrl } from '@nextcloud/router'
import { getPreviewUrl } from "../../services/FileUtils";
import { getCurrentUser } from '@nextcloud/auth';
import { NcCounterBubble } from '@nextcloud/vue'
import { NcCounterBubble } from '@nextcloud/vue';
import axios from '@nextcloud/axios';
import * as utils from "../../services/Utils";
import GlobalMixin from '../../mixins/GlobalMixin';
import { constants } from '../../services/Utils';
@ -112,7 +114,28 @@ export default class Tag extends Mixins(GlobalMixin) {
}
// Look for previews
if (!this.data.previews) return;
if (!this.data.previews) {
try {
const todayDayId = utils.dateToDayId(new Date());
const url = generateUrl(`/apps/memories/api/tag-previews?tag=${this.data.name}`);
const cacheUrl = `${url}&today=${Math.floor(todayDayId / 10)}`;
const cache = await utils.getCachedData(cacheUrl);
if (cache) {
this.data.previews = cache as any;
} else {
const res = await axios.get(url);
this.data.previews = res.data;
// Cache only if >= 4 previews
if (this.data.previews.length >= 4) {
utils.cacheData(cacheUrl, res.data);
}
}
} catch (e) {
this.error = true;
return;
}
}
// Reset flag
this.data.previews.forEach((p) => p.flag = 0);