albums: refactor backend
Signed-off-by: Varun Patil <radialapps@gmail.com>pull/767/head
parent
912e05fae8
commit
4da3bd938a
|
@ -94,14 +94,12 @@ class AlbumsBackend extends Backend
|
|||
|
||||
// Run actual query
|
||||
$list = [];
|
||||
$t = (int) $request->getParam('t', 0);
|
||||
$fileid = (int) $request->getParam('fid', -1);
|
||||
if ($t & 1) { // personal
|
||||
$list = array_merge($list, $this->albumsQuery->getList(Util::getUID(), $fileid));
|
||||
}
|
||||
if ($t & 2) { // shared
|
||||
$list = array_merge($list, $this->albumsQuery->getList(Util::getUID(), $fileid, true));
|
||||
}
|
||||
$fileid = (int) $request->getParam('fileid', -1);
|
||||
|
||||
// personal albums
|
||||
$list = array_merge($list, $this->albumsQuery->getList(Util::getUID(), false, $fileid));
|
||||
// shared albums
|
||||
$list = array_merge($list, $this->albumsQuery->getList(Util::getUID(), true, $fileid));
|
||||
|
||||
// Remove elements with duplicate album_id
|
||||
$seenIds = [];
|
||||
|
|
|
@ -16,17 +16,17 @@ class AlbumsQuery
|
|||
$this->connection = $connection;
|
||||
}
|
||||
|
||||
/** Get list of albums */
|
||||
public function getList(string $uid, int $fileId, bool $shared = false)
|
||||
/**
|
||||
* Get list of albums.
|
||||
*
|
||||
* @param bool $shared Whether to get shared albums
|
||||
* @param int $fileid File to filter by
|
||||
*/
|
||||
public function getList(string $uid, bool $shared = false, int $fileid = -1)
|
||||
{
|
||||
$query = $this->connection->getQueryBuilder();
|
||||
$allPhotosQuery = $this->connection->getQueryBuilder();
|
||||
|
||||
// SELECT everything from albums
|
||||
$allPhotosQuery->select('album_id')->from('photos_albums_files');
|
||||
$allPhotosQuery->where(
|
||||
$allPhotosQuery->expr()->eq('file_id', $allPhotosQuery->createNamedParameter($fileId, IQueryBuilder::PARAM_INT))
|
||||
);
|
||||
$count = $query->func()->count($query->createFunction('DISTINCT m.fileid'), 'count');
|
||||
$query->select(
|
||||
'pa.album_id',
|
||||
|
@ -67,14 +67,22 @@ class AlbumsQuery
|
|||
$query->orderBy('pa.created', 'DESC');
|
||||
$query->addOrderBy('pa.album_id', 'DESC'); // tie-breaker
|
||||
|
||||
// WHERE these albums contain fileid if specified
|
||||
if ($fileid > 0) {
|
||||
$fSq = $this->connection->getQueryBuilder()
|
||||
->select('paf.file_id')
|
||||
->from('photos_albums_files', 'paf')
|
||||
->where($query->expr()->andX(
|
||||
$query->expr()->eq('paf.album_id', 'pa.album_id'),
|
||||
$query->expr()->eq('paf.file_id', $query->createNamedParameter($fileid, IQueryBuilder::PARAM_INT)),
|
||||
))
|
||||
->getSQL()
|
||||
;
|
||||
$query->andWhere($query->createFunction("EXISTS ({$fSq})"));
|
||||
}
|
||||
|
||||
// FETCH all albums
|
||||
$albums = $query->executeQuery()->fetchAll();
|
||||
$allPhotos = $allPhotosQuery->executeQuery()->fetchAll();
|
||||
$albumIds = array();
|
||||
|
||||
foreach ($allPhotos as &$album) {
|
||||
$albumIds[$album['album_id']] = true;
|
||||
}
|
||||
|
||||
// Post process
|
||||
foreach ($albums as &$row) {
|
||||
|
@ -83,7 +91,6 @@ class AlbumsQuery
|
|||
$row['album_id'] = $albumId;
|
||||
$row['created'] = (int) $row['created'];
|
||||
$row['last_added_photo'] = (int) $row['last_added_photo'];
|
||||
$row['has_file'] = !!$albumIds[$albumId];
|
||||
}
|
||||
|
||||
return $albums;
|
||||
|
|
|
@ -89,7 +89,7 @@ export default defineComponent({
|
|||
await this.$refs.dtm?.refresh?.();
|
||||
|
||||
if (this.routeIsAlbums) {
|
||||
this.items = await dav.getAlbums(3, this.config.album_list_sort);
|
||||
this.items = await dav.getAlbums(this.config.album_list_sort);
|
||||
} else if (this.routeIsTags) {
|
||||
this.items = await dav.getTags();
|
||||
} else if (this.routeIsPeople) {
|
||||
|
|
|
@ -73,8 +73,8 @@ import LocationIcon from 'vue-material-design-icons/MapMarker.vue';
|
|||
import TagIcon from 'vue-material-design-icons/Tag.vue';
|
||||
|
||||
import * as utils from '../services/Utils';
|
||||
import * as dav from '../services/DavRequests';
|
||||
import { API } from '../services/API';
|
||||
import router from '../router';
|
||||
|
||||
import type { IAlbum, IImageInfo, IPhoto } from '../types';
|
||||
|
||||
|
@ -359,17 +359,13 @@ export default defineComponent({
|
|||
async refreshAlbums(): Promise<IAlbum[]> {
|
||||
const state = this.state;
|
||||
|
||||
// get album list
|
||||
let list: IAlbum[] = [];
|
||||
try {
|
||||
list = (await axios.get<IAlbum[]>(API.ALBUM_LIST(3, this.fileid!))).data;
|
||||
list = await dav.getAlbums(1, this.fileid!);
|
||||
} catch (e) {
|
||||
console.error('metadata: failed to load albums', e);
|
||||
}
|
||||
|
||||
// filter albums containing this file
|
||||
list = list.filter((a) => a.has_file);
|
||||
|
||||
if (state !== this.state) return list;
|
||||
return (this.albums = list);
|
||||
},
|
||||
|
|
|
@ -67,13 +67,11 @@ import { defineComponent, PropType } from 'vue';
|
|||
import AlbumForm from './AlbumForm.vue';
|
||||
import AlbumsList from './AlbumsList.vue';
|
||||
|
||||
import axios from '@nextcloud/axios';
|
||||
|
||||
import NcButton from '@nextcloud/vue/dist/Components/NcButton';
|
||||
const NcListItem = () => import('@nextcloud/vue/dist/Components/NcListItem');
|
||||
|
||||
import * as dav from '../../services/DavRequests';
|
||||
import { IAlbum, IPhoto } from '../../types';
|
||||
import { API } from '../../services/API';
|
||||
|
||||
import PlusIcon from 'vue-material-design-icons/Plus.vue';
|
||||
import CheckIcon from 'vue-material-design-icons/Check.vue';
|
||||
|
@ -108,9 +106,11 @@ export default defineComponent({
|
|||
loadingAlbums: true,
|
||||
/** List of all albums */
|
||||
albums: [] as IAlbum[],
|
||||
/** All selected albums */
|
||||
/** Initial selection */
|
||||
initSelection: new Set<IAlbum>(),
|
||||
/** Selected albums */
|
||||
selection: new Set<IAlbum>(),
|
||||
/** Deselected albums that were previously selected */
|
||||
/** Deselected albums that were initially selected */
|
||||
deselection: new Set<IAlbum>(),
|
||||
}),
|
||||
|
||||
|
@ -128,14 +128,21 @@ export default defineComponent({
|
|||
try {
|
||||
this.loadingAlbums = true;
|
||||
|
||||
// this only makes sense when we try to add single photo to albums
|
||||
const fileid = this.photos.length === 1 ? this.photos[0].fileid : -1;
|
||||
// get all albums
|
||||
this.albums = await dav.getAlbums();
|
||||
|
||||
// get albums, possibly for one photo
|
||||
const res = await axios.get<IAlbum[]>(API.ALBUM_LIST(3, fileid));
|
||||
this.albums = res.data;
|
||||
this.selection = new Set(this.albums.filter((album) => album.has_file));
|
||||
// reset selection
|
||||
this.initSelection = new Set();
|
||||
this.selection = new Set();
|
||||
this.deselection = new Set();
|
||||
|
||||
// if only one photo is selected, get the albums of that photo
|
||||
const fileid = this.photos.length === 1 ? this.photos[0].fileid : 0;
|
||||
if (fileid) {
|
||||
const selIds = new Set((await dav.getAlbums(1, fileid)).map((a) => a.album_id));
|
||||
this.initSelection = new Set(this.albums.filter((a) => selIds.has(a.album_id)));
|
||||
this.selection = new Set(this.initSelection);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
} finally {
|
||||
|
@ -150,7 +157,7 @@ export default defineComponent({
|
|||
this.selection.delete(album);
|
||||
|
||||
// deselection only if originally selected
|
||||
if (album.has_file) {
|
||||
if (this.initSelection.has(album)) {
|
||||
this.deselection.add(album);
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -37,7 +37,7 @@ export enum DaysFilterType {
|
|||
}
|
||||
|
||||
export class API {
|
||||
static Q(url: string, query: string | URLSearchParams | Object | undefined | null) {
|
||||
static Q(url: string, query: string | URLSearchParams | Object | undefined | null): string {
|
||||
if (!query) return url;
|
||||
|
||||
if (typeof query === 'object') {
|
||||
|
@ -84,8 +84,8 @@ export class API {
|
|||
return tok(gen(`${BASE}/folders/sub`));
|
||||
}
|
||||
|
||||
static ALBUM_LIST(t: 1 | 2 | 3 = 3, photoId: number = -1) {
|
||||
return gen(`${BASE}/clusters/albums?t=${t}&fid=${photoId}`);
|
||||
static ALBUM_LIST(fileid?: number) {
|
||||
return API.Q(gen(`${BASE}/clusters/albums`), { fileid });
|
||||
}
|
||||
|
||||
static ALBUM_DOWNLOAD(user: string, name: string) {
|
||||
|
|
|
@ -22,14 +22,14 @@ export function getAlbumPath(user: string, name: string) {
|
|||
|
||||
/**
|
||||
* Get list of albums.
|
||||
* @param type Type of albums to get; 1 = personal, 2 = shared, 3 = all
|
||||
* @param sortOrder Sort order; 1 = by date, 2 = by name
|
||||
* @param sort Sort order; 1 = by date, 2 = by name
|
||||
* @param fileid Optional file ID to get albums for
|
||||
*/
|
||||
export async function getAlbums(type: 1 | 2 | 3, sortOrder: 1 | 2) {
|
||||
const data = (await axios.get<IAlbum[]>(API.ALBUM_LIST(type))).data;
|
||||
export async function getAlbums(sort: 1 | 2 = 1, fileid?: number) {
|
||||
const data = (await axios.get<IAlbum[]>(API.ALBUM_LIST(fileid))).data;
|
||||
|
||||
// Sort the response
|
||||
switch (sortOrder) {
|
||||
switch (sort) {
|
||||
case 2:
|
||||
data.sort((a, b) => a.name.localeCompare(b.name, undefined, { sensitivity: 'base' }));
|
||||
break;
|
||||
|
|
|
@ -140,8 +140,6 @@ export interface IAlbum extends ICluster {
|
|||
location: string;
|
||||
/** File ID of last added photo */
|
||||
last_added_photo: number;
|
||||
/** Whether an album contains the file */
|
||||
has_file: boolean;
|
||||
}
|
||||
|
||||
export interface IFace extends ICluster {
|
||||
|
|
Loading…
Reference in New Issue