Include filename in days
parent
9209b8f55d
commit
cd2f714e92
|
@ -45,14 +45,6 @@ class TimelineQuery
|
|||
|
||||
public function transformExtraFields(IQueryBuilder &$query, string $uid, array &$fields)
|
||||
{
|
||||
if (\in_array('basename', $fields, true)) {
|
||||
$query->addSelect('f.name AS basename');
|
||||
}
|
||||
|
||||
if (\in_array('mimetype', $fields, true)) {
|
||||
$query->join('f', 'mimetypes', 'mimetypes', $query->expr()->eq('f.mimetype', 'mimetypes.id'));
|
||||
$query->addSelect('mimetypes.mimetype');
|
||||
}
|
||||
}
|
||||
|
||||
public function getInfoById(int $id): array
|
||||
|
|
|
@ -102,10 +102,17 @@ trait TimelineQueryDays
|
|||
// We don't actually use m.datetaken here, but postgres
|
||||
// needs that all fields in ORDER BY are also in SELECT
|
||||
// when using DISTINCT on selected fields
|
||||
$query->select($fileid, 'f.etag', 'f.path', 'm.isvideo', 'vco.categoryid', 'm.datetaken', 'm.dayid', 'm.w', 'm.h')
|
||||
$query->select($fileid, 'm.isvideo', 'm.datetaken', 'm.dayid', 'm.w', 'm.h')
|
||||
->from('memories', 'm')
|
||||
;
|
||||
|
||||
// JOIN with filecache for existing files
|
||||
$query = $this->joinFilecache($query, $folder, $recursive, $archive);
|
||||
$query->addSelect('f.etag', 'f.path', 'f.name AS basename');
|
||||
|
||||
// JOIN with mimetypes to get the mimetype
|
||||
$query->join('f', 'mimetypes', 'mimetypes', $query->expr()->eq('f.mimetype', 'mimetypes.id'));
|
||||
$query->addSelect('mimetypes.mimetype');
|
||||
|
||||
// Filter by dayid unless wildcard
|
||||
if (null !== $day_ids) {
|
||||
|
@ -155,7 +162,30 @@ trait TimelineQueryDays
|
|||
*/
|
||||
private function processDay(&$day, $folder)
|
||||
{
|
||||
$basePath = null !== $folder ? $folder->getInternalPath() : '#__#__#';
|
||||
$basePath = '#__#__#';
|
||||
$davPath = '/';
|
||||
if (null !== $folder) {
|
||||
// No way to get the internal path from the folder
|
||||
$query = $this->connection->getQueryBuilder();
|
||||
$query->select('path')
|
||||
->from('filecache')
|
||||
->where($query->expr()->eq('fileid', $query->createNamedParameter($folder->getId(), IQueryBuilder::PARAM_INT)))
|
||||
;
|
||||
$path = $query->executeQuery()->fetchOne();
|
||||
$basePath = $path ?: $basePath;
|
||||
|
||||
// Get user facing path
|
||||
// getPath looks like /user/files/... but we want /files/user/...
|
||||
// Split at / and swap these
|
||||
$actualPath = $folder->getPath();
|
||||
$actualPath = explode('/', $actualPath);
|
||||
if (\count($actualPath) >= 3) {
|
||||
$tmp = $actualPath[1];
|
||||
$actualPath[1] = $actualPath[2];
|
||||
$actualPath[2] = $tmp;
|
||||
$davPath = implode('/', $actualPath);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($day as &$row) {
|
||||
// We don't need date taken (see query builder)
|
||||
|
@ -178,7 +208,7 @@ trait TimelineQueryDays
|
|||
// Check if path exists and starts with basePath and remove
|
||||
if (isset($row['path']) && !empty($row['path'])) {
|
||||
if (0 === strpos($row['path'], $basePath)) {
|
||||
$row['filename'] = substr($row['path'], \strlen($basePath));
|
||||
$row['filename'] = $davPath.substr($row['path'], \strlen($basePath));
|
||||
}
|
||||
unset($row['path']);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ trait TimelineQueryFilters
|
|||
$query->expr()->eq('vco.objid', 'm.fileid'),
|
||||
$query->expr()->in('vco.categoryid', $this->getFavoriteVCategoryFun($query, $userId)),
|
||||
));
|
||||
$query->addSelect('vco.categoryid');
|
||||
}
|
||||
|
||||
public function transformVideoFilter(IQueryBuilder &$query, string $userId)
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
*/
|
||||
import { generateUrl } from "@nextcloud/router";
|
||||
import camelcase from "camelcase";
|
||||
import { IExtendedPhoto, IFileInfo, IPhoto } from "../types";
|
||||
import { IFileInfo, IPhoto } from "../types";
|
||||
import { isNumber } from "./NumberUtils";
|
||||
|
||||
/**
|
||||
|
|
|
@ -3,14 +3,7 @@ import { getCurrentUser } from "@nextcloud/auth";
|
|||
import { generateUrl } from "@nextcloud/router";
|
||||
import { showError } from "@nextcloud/dialogs";
|
||||
import { translate as t, translatePlural as n } from "@nextcloud/l10n";
|
||||
import {
|
||||
IAlbum,
|
||||
IDay,
|
||||
IExtendedPhoto,
|
||||
IFileInfo,
|
||||
IPhoto,
|
||||
ITag,
|
||||
} from "../../types";
|
||||
import { IAlbum, IDay, IFileInfo, IPhoto, ITag } from "../../types";
|
||||
import { constants } from "../Utils";
|
||||
import axios from "@nextcloud/axios";
|
||||
import client from "../DavClient";
|
||||
|
@ -270,15 +263,13 @@ export function getAlbumFileInfos(
|
|||
albumUser: string,
|
||||
albumName: string
|
||||
): IFileInfo[] {
|
||||
const ephotos = photos as IExtendedPhoto[];
|
||||
|
||||
const uid = getCurrentUser()?.uid;
|
||||
const collection =
|
||||
albumUser === uid
|
||||
? `/photos/${uid}/albums/${albumName}`
|
||||
: `/photos/${uid}/sharedalbums/${albumName} (${albumUser})`;
|
||||
|
||||
return ephotos.map((photo) => {
|
||||
return photos.map((photo) => {
|
||||
const basename =
|
||||
albumUser === uid
|
||||
? `${photo.fileid}-${photo.basename}`
|
||||
|
|
|
@ -46,8 +46,33 @@ export async function getFiles(photos: IPhoto[]): Promise<IFileInfo[]> {
|
|||
return getAlbumFileInfos(photos, route.params.user, route.params.name);
|
||||
}
|
||||
|
||||
// Get file infos
|
||||
let fileInfos: IFileInfo[] = [];
|
||||
|
||||
// Get all photos that already have and don't have a filename
|
||||
const photosWithFilename = photos.filter((photo) => photo.filename);
|
||||
fileInfos = fileInfos.concat(
|
||||
photosWithFilename.map((photo) => {
|
||||
return {
|
||||
fileid: photo.fileid,
|
||||
filename: photo.filename.split("/").slice(3).join("/"),
|
||||
originalFilename: photo.filename,
|
||||
basename: photo.basename,
|
||||
mime: photo.mimetype,
|
||||
hasPreview: true,
|
||||
etag: photo.etag,
|
||||
} as IFileInfo;
|
||||
})
|
||||
);
|
||||
|
||||
// Next: get all photos that have no filename using ID
|
||||
if (photosWithFilename.length === photos.length) {
|
||||
return fileInfos;
|
||||
}
|
||||
const photosWithoutFilename = photos.filter((photo) => !photo.filename);
|
||||
|
||||
// Get file IDs array
|
||||
const fileIds = photos.map((photo) => photo.fileid);
|
||||
const fileIds = photosWithoutFilename.map((photo) => photo.fileid);
|
||||
|
||||
// Divide fileIds into chunks of GET_FILE_CHUNK_SIZE
|
||||
const chunks = [];
|
||||
|
@ -56,8 +81,10 @@ export async function getFiles(photos: IPhoto[]): Promise<IFileInfo[]> {
|
|||
}
|
||||
|
||||
// Get file infos for each chunk
|
||||
const fileInfos = await Promise.all(chunks.map(getFilesInternal));
|
||||
return fileInfos.flat();
|
||||
const ef = await Promise.all(chunks.map(getFilesInternal));
|
||||
fileInfos = fileInfos.concat(ef.flat());
|
||||
|
||||
return fileInfos;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -152,16 +179,6 @@ export async function* runInParallel<T>(
|
|||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a single file
|
||||
*
|
||||
* @param path path to the file
|
||||
*/
|
||||
export async function deleteFile(path: string) {
|
||||
const prefixPath = `/files/${getCurrentUser()?.uid}`;
|
||||
return await client.deleteFile(`${prefixPath}${path}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete all files in a given list of Ids
|
||||
*
|
||||
|
@ -189,11 +206,15 @@ export async function* deletePhotos(photos: IPhoto[]) {
|
|||
fileInfos = fileInfos.filter((f) => fileIdsSet.has(f.fileid));
|
||||
const calls = fileInfos.map((fileInfo) => async () => {
|
||||
try {
|
||||
await deleteFile(fileInfo.filename);
|
||||
await client.deleteFile(fileInfo.originalFilename);
|
||||
return fileInfo.fileid;
|
||||
} catch (error) {
|
||||
console.error("Failed to delete", fileInfo, error);
|
||||
showError(t("memories", "Failed to delete {fileName}.", fileInfo));
|
||||
showError(
|
||||
t("memories", "Failed to delete {fileName}.", {
|
||||
fileName: fileInfo.filename,
|
||||
})
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
|
|
11
src/types.ts
11
src/types.ts
|
@ -39,6 +39,10 @@ export type IPhoto = {
|
|||
etag?: string;
|
||||
/** Path to file */
|
||||
filename?: string;
|
||||
/** Base name of file */
|
||||
basename?: string;
|
||||
/** Mime type of file */
|
||||
mimetype?: string;
|
||||
/** Bit flags */
|
||||
flag: number;
|
||||
/** DayID from server */
|
||||
|
@ -81,13 +85,6 @@ export type IPhoto = {
|
|||
datetaken?: number;
|
||||
};
|
||||
|
||||
export interface IExtendedPhoto extends IPhoto {
|
||||
/** Base name of file */
|
||||
basename: string;
|
||||
/** Mime type of file */
|
||||
mimetype: string;
|
||||
}
|
||||
|
||||
export interface IFolder extends IPhoto {
|
||||
/** Path to folder */
|
||||
path: string;
|
||||
|
|
Loading…
Reference in New Issue