Use separate tag preview endpoint
parent
46eb0fd97a
commit
a0d757adfc
|
@ -30,6 +30,7 @@ return [
|
||||||
['name' => 'api#day', 'url' => '/api/days/{id}', 'verb' => 'GET'],
|
['name' => 'api#day', 'url' => '/api/days/{id}', 'verb' => 'GET'],
|
||||||
|
|
||||||
['name' => 'api#tags', 'url' => '/api/tags', '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'],
|
['name' => 'api#albums', 'url' => '/api/albums', 'verb' => 'GET'],
|
||||||
|
|
||||||
|
|
|
@ -253,8 +253,40 @@ class ApiController extends Controller
|
||||||
$folder,
|
$folder,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Preload all tag previews
|
return new JSONResponse($list, Http::STATUS_OK);
|
||||||
$this->timelineQuery->getTagPreviews($list, $folder);
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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);
|
return new JSONResponse($list, Http::STATUS_OK);
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,66 +88,46 @@ trait TimelineQueryTags
|
||||||
return $tags;
|
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
|
$query = $this->connection->getQueryBuilder();
|
||||||
$sql = '';
|
$tagId = $this->getSystemTagId($query, $tagName);
|
||||||
foreach ($tags as &$tag) {
|
if (false === $tagId) {
|
||||||
if (!empty($sql)) {
|
return [];
|
||||||
$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})";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
// FETCH tag previews
|
||||||
$cursor = $this->executeQueryWithCTEs($query, $sql);
|
$cursor = $this->executeQueryWithCTEs($query);
|
||||||
$ans = $cursor->fetchAll();
|
$ans = $cursor->fetchAll();
|
||||||
|
|
||||||
// Post-process
|
// Post-process
|
||||||
$previewMap = [];
|
|
||||||
foreach ($ans as &$row) {
|
foreach ($ans as &$row) {
|
||||||
$row['fileid'] = (int) $row['fileid'];
|
$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
|
return $ans;
|
||||||
foreach ($tags as &$tag) {
|
|
||||||
$tag['previews'] = $previewMap[$tag['id']] ?? [];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,7 +34,9 @@ import { generateUrl } from '@nextcloud/router'
|
||||||
import { getPreviewUrl } from "../../services/FileUtils";
|
import { getPreviewUrl } from "../../services/FileUtils";
|
||||||
import { getCurrentUser } from '@nextcloud/auth';
|
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 GlobalMixin from '../../mixins/GlobalMixin';
|
||||||
import { constants } from '../../services/Utils';
|
import { constants } from '../../services/Utils';
|
||||||
|
@ -112,7 +114,28 @@ export default class Tag extends Mixins(GlobalMixin) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look for previews
|
// 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
|
// Reset flag
|
||||||
this.data.previews.forEach((p) => p.flag = 0);
|
this.data.previews.forEach((p) => p.flag = 0);
|
||||||
|
|
Loading…
Reference in New Issue