Improve update magic metadata functions (#1149)

This commit is contained in:
Abhinav Kumar 2023-05-30 18:52:07 +05:30 committed by GitHub
commit 2c499442a6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 156 additions and 121 deletions

View file

@ -75,6 +75,10 @@ const CollectionCardContainer = React.memo(
areEqual
);
const getItemKey = (index: number, data: ItemData) => {
return `${data.collectionSummaries[index].id}-${data.collectionSummaries[index].latestFile?.id}`;
};
const CollectionListBar = (props: IProps) => {
const {
activeCollection,
@ -153,6 +157,7 @@ const CollectionListBar = (props: IProps) => {
layout="horizontal"
width={width}
height={110}
itemKey={getItemKey}
itemCount={collectionSummaries.length}
itemSize={CollectionListBarCardWidth}
useIsScrolling>

View file

@ -1,5 +1,4 @@
import React, { useState } from 'react';
import { updateFilePublicMagicMetadata } from 'services/fileService';
import { EnteFile } from 'types/file';
import { changeCaption, updateExistingFilePubMetadata } from 'utils/file';
import { logError } from 'utils/sentry';
@ -41,10 +40,7 @@ export function RenderCaption({
}
setCaption(newCaption);
let updatedFile = await changeCaption(file, newCaption);
updatedFile = (
await updateFilePublicMagicMetadata([updatedFile])
)[0];
const updatedFile = await changeCaption(file, newCaption);
updateExistingFilePubMetadata(file, updatedFile);
file.title = file.pubMagicMetadata.data.caption;
refreshPhotoswipe();

View file

@ -1,5 +1,4 @@
import React, { useState } from 'react';
import { updateFilePublicMagicMetadata } from 'services/fileService';
import { EnteFile } from 'types/file';
import CalendarTodayIcon from '@mui/icons-material/CalendarToday';
import {
@ -37,13 +36,10 @@ export function RenderCreationTime({
closeEditMode();
return;
}
let updatedFile = await changeFileCreationTime(
const updatedFile = await changeFileCreationTime(
file,
unixTimeInMicroSec
);
updatedFile = (
await updateFilePublicMagicMetadata([updatedFile])
)[0];
updateExistingFilePubMetadata(file, updatedFile);
scheduleUpdate();
}

View file

@ -1,5 +1,4 @@
import React, { useEffect, useState } from 'react';
import { updateFilePublicMagicMetadata } from 'services/fileService';
import { EnteFile } from 'types/file';
import {
changeFileName,
@ -82,10 +81,7 @@ export function RenderFileName({
}
setFilename(newFilename);
const newTitle = getFileTitle(newFilename, extension);
let updatedFile = await changeFileName(file, newTitle);
updatedFile = (
await updateFilePublicMagicMetadata([updatedFile])
)[0];
const updatedFile = await changeFileName(file, newTitle);
updateExistingFilePubMetadata(file, updatedFile);
scheduleUpdate();
}

View file

@ -11,7 +11,6 @@ import { clearKeys, getKey, SESSION_KEYS } from 'utils/storage/sessionStorage';
import {
getLocalFiles,
syncFiles,
updateFileMagicMetadata,
trashFiles,
deleteFromTrash,
getLocalHiddenFiles,
@ -664,11 +663,7 @@ export default function Gallery() {
startLoading();
try {
const selectedFiles = getSelectedFiles(selected, filteredData);
const updatedFiles = await changeFilesVisibility(
selectedFiles,
visibility
);
await updateFileMagicMetadata(updatedFiles);
await changeFilesVisibility(selectedFiles, visibility);
clearSelection();
} catch (e) {
logError(e, 'change file visibility failed');

View file

@ -47,7 +47,7 @@ import {
SUB_TYPE,
UpdateMagicMetadataRequest,
} from 'types/magicMetadata';
import { IsArchived, updateMagicMetadataProps } from 'utils/magicMetadata';
import { IsArchived, updateMagicMetadata } from 'utils/magicMetadata';
import { User } from 'types/user';
import {
isQuickLinkCollection,
@ -58,6 +58,7 @@ import {
isHiddenCollection,
isValidReplacementAlbum,
getNonHiddenCollections,
changeCollectionSubType,
} from 'utils/collection';
import ComlinkCryptoWorker from 'utils/comlink/ComlinkCryptoWorker';
import { getLocalFiles } from './fileService';
@ -345,7 +346,7 @@ const createCollection = async (
await cryptoWorker.encryptUTF8(collectionName, collectionKey);
let encryptedMagicMetadata: EncryptedMagicMetadata;
if (magicMetadataProps) {
const magicMetadata = await updateMagicMetadataProps(
const magicMetadata = await updateMagicMetadata(
NEW_COLLECTION_MAGIC_METADATA,
null,
magicMetadataProps
@ -711,7 +712,10 @@ export const leaveSharedAlbum = async (collectionID: number) => {
}
};
export const updateCollectionMagicMetadata = async (collection: Collection) => {
export const updateCollectionMagicMetadata = async (
collection: Collection,
updatedMagicMetadata: CollectionMagicMetadata
) => {
const token = getToken();
if (!token) {
return;
@ -720,15 +724,15 @@ export const updateCollectionMagicMetadata = async (collection: Collection) => {
const cryptoWorker = await ComlinkCryptoWorker.getInstance();
const { file: encryptedMagicMetadata } = await cryptoWorker.encryptMetadata(
collection.magicMetadata.data,
updatedMagicMetadata.data,
collection.key
);
const reqBody: UpdateMagicMetadataRequest = {
id: collection.id,
magicMetadata: {
version: collection.magicMetadata.version,
count: collection.magicMetadata.count,
version: updatedMagicMetadata.version,
count: updatedMagicMetadata.count,
data: encryptedMagicMetadata.encryptedData,
header: encryptedMagicMetadata.decryptionHeader,
},
@ -745,8 +749,8 @@ export const updateCollectionMagicMetadata = async (collection: Collection) => {
const updatedCollection: Collection = {
...collection,
magicMetadata: {
...collection.magicMetadata,
version: collection.magicMetadata.version + 1,
...updatedMagicMetadata,
version: updatedMagicMetadata.version + 1,
},
};
return updatedCollection;
@ -758,7 +762,7 @@ export const renameCollection = async (
) => {
if (isQuickLinkCollection(collection)) {
// Convert quick link collection to normal collection on rename
await updateCollectionSubType(collection, SUB_TYPE.DEFAULT);
await changeCollectionSubType(collection, SUB_TYPE.DEFAULT);
}
const token = getToken();
const cryptoWorker = await ComlinkCryptoWorker.getInstance();
@ -779,24 +783,6 @@ export const renameCollection = async (
);
};
const updateCollectionSubType = async (
collection: Collection,
subType: SUB_TYPE
) => {
const updatedMagicMetadataProps: CollectionMagicMetadataProps = {
subType: subType,
};
const updatedCollection = {
...collection,
magicMetadata: await updateMagicMetadataProps(
collection.magicMetadata ?? NEW_COLLECTION_MAGIC_METADATA,
collection.key,
updatedMagicMetadataProps
),
} as Collection;
await updateCollectionMagicMetadata(updatedCollection);
};
export const shareCollection = async (
collection: Collection,
withUserEmail: string

View file

@ -12,7 +12,13 @@ import {
sortFiles,
} from 'utils/file';
import { eventBus, Events } from './events';
import { EnteFile, EncryptedEnteFile, TrashRequest } from 'types/file';
import {
EnteFile,
EncryptedEnteFile,
TrashRequest,
FileWithUpdatedMagicMetadata,
FileWithUpdatedPublicMagicMetadata,
} from 'types/file';
import { SetFiles } from 'types/gallery';
import { BulkUpdateMagicMetadataRequest } from 'types/magicMetadata';
import { addLogLine } from 'utils/logging';
@ -250,24 +256,29 @@ export const deleteFromTrash = async (filesToDelete: number[]) => {
}
};
export const updateFileMagicMetadata = async (files: EnteFile[]) => {
export const updateFileMagicMetadata = async (
fileWithUpdatedMagicMetadataList: FileWithUpdatedMagicMetadata[]
) => {
const token = getToken();
if (!token) {
return;
}
const reqBody: BulkUpdateMagicMetadataRequest = { metadataList: [] };
const cryptoWorker = await ComlinkCryptoWorker.getInstance();
for (const file of files) {
for (const {
file,
updatedMagicMetadata,
} of fileWithUpdatedMagicMetadataList) {
const { file: encryptedMagicMetadata } =
await cryptoWorker.encryptMetadata(
file.magicMetadata.data,
updatedMagicMetadata.data,
file.key
);
reqBody.metadataList.push({
id: file.id,
magicMetadata: {
version: file.magicMetadata.version,
count: file.magicMetadata.count,
version: updatedMagicMetadata.version,
count: updatedMagicMetadata.count,
data: encryptedMagicMetadata.encryptedData,
header: encryptedMagicMetadata.decryptionHeader,
},
@ -276,35 +287,40 @@ export const updateFileMagicMetadata = async (files: EnteFile[]) => {
await HTTPService.put(`${ENDPOINT}/files/magic-metadata`, reqBody, null, {
'X-Auth-Token': token,
});
return files.map(
(file): EnteFile => ({
return fileWithUpdatedMagicMetadataList.map(
({ file, updatedMagicMetadata }): EnteFile => ({
...file,
magicMetadata: {
...file.magicMetadata,
version: file.magicMetadata.version + 1,
...updatedMagicMetadata,
version: updatedMagicMetadata.version + 1,
},
})
);
};
export const updateFilePublicMagicMetadata = async (files: EnteFile[]) => {
export const updateFilePublicMagicMetadata = async (
fileWithUpdatedPublicMagicMetadataList: FileWithUpdatedPublicMagicMetadata[]
): Promise<EnteFile[]> => {
const token = getToken();
if (!token) {
return;
}
const reqBody: BulkUpdateMagicMetadataRequest = { metadataList: [] };
const cryptoWorker = await ComlinkCryptoWorker.getInstance();
for (const file of files) {
for (const {
file,
updatedPublicMagicMetadata: updatePublicMagicMetadata,
} of fileWithUpdatedPublicMagicMetadataList) {
const { file: encryptedPubMagicMetadata } =
await cryptoWorker.encryptMetadata(
file.pubMagicMetadata.data,
updatePublicMagicMetadata.data,
file.key
);
reqBody.metadataList.push({
id: file.id,
magicMetadata: {
version: file.pubMagicMetadata.version,
count: file.pubMagicMetadata.count,
version: updatePublicMagicMetadata.version,
count: updatePublicMagicMetadata.count,
data: encryptedPubMagicMetadata.encryptedData,
header: encryptedPubMagicMetadata.decryptionHeader,
},
@ -318,12 +334,12 @@ export const updateFilePublicMagicMetadata = async (files: EnteFile[]) => {
'X-Auth-Token': token,
}
);
return files.map(
(file): EnteFile => ({
return fileWithUpdatedPublicMagicMetadataList.map(
({ file, updatedPublicMagicMetadata }): EnteFile => ({
...file,
pubMagicMetadata: {
...file.pubMagicMetadata,
version: file.pubMagicMetadata.version + 1,
...updatedPublicMagicMetadata,
version: updatedPublicMagicMetadata.version + 1,
},
})
);

View file

@ -7,7 +7,6 @@ import {
} from 'utils/file';
import { logError } from 'utils/sentry';
import downloadManager from './downloadManager';
import { updateFilePublicMagicMetadata } from './fileService';
import { EnteFile } from 'types/file';
import { getParsedExifData } from './upload/exifService';
@ -66,13 +65,10 @@ export async function updateCreationTimeWithExif(
correctCreationTime &&
correctCreationTime !== file.metadata.creationTime
) {
let updatedFile = await changeFileCreationTime(
const updatedFile = await changeFileCreationTime(
file,
correctCreationTime
);
updatedFile = (
await updateFilePublicMagicMetadata([updatedFile])
)[0];
updateExistingFilePubMetadata(file, updatedFile);
}
} catch (e) {

View file

@ -3,12 +3,12 @@ import {
FilePublicMagicMetadataProps,
FilePublicMagicMetadata,
} from 'types/magicMetadata';
import { updateMagicMetadataProps } from 'utils/magicMetadata';
import { updateMagicMetadata } from 'utils/magicMetadata';
export async function constructPublicMagicMetadata(
publicMagicMetadataProps: FilePublicMagicMetadataProps
): Promise<FilePublicMagicMetadata> {
const pubMagicMetadata = await updateMagicMetadataProps(
const pubMagicMetadata = await updateMagicMetadata(
NEW_FILE_MAGIC_METADATA,
null,
publicMagicMetadataProps

View file

@ -70,3 +70,13 @@ export interface TrashRequestItems {
fileID: number;
collectionID: number;
}
export interface FileWithUpdatedMagicMetadata {
file: EnteFile;
updatedMagicMetadata: FileMagicMetadata;
}
export interface FileWithUpdatedPublicMagicMetadata {
file: EnteFile;
updatedPublicMagicMetadata: FilePublicMagicMetadata;
}

View file

@ -10,7 +10,7 @@ import {
import { downloadFiles } from 'utils/file';
import { getLocalFiles, getLocalHiddenFiles } from 'services/fileService';
import { EnteFile } from 'types/file';
import { CustomError, ServerErrorCodes } from 'utils/error';
import { CustomError } from 'utils/error';
import { User } from 'types/user';
import { getData, LS_KEYS } from 'utils/storage/localStorage';
import { logError } from 'utils/sentry';
@ -33,7 +33,7 @@ import {
SUB_TYPE,
VISIBILITY_STATE,
} from 'types/magicMetadata';
import { IsArchived, updateMagicMetadataProps } from 'utils/magicMetadata';
import { IsArchived, updateMagicMetadata } from 'utils/magicMetadata';
import { getAlbumsURL } from 'utils/common/apiUtil';
import bs58 from 'bs58';
import { t } from 'i18next';
@ -165,22 +165,35 @@ export const changeCollectionVisibility = async (
visibility,
};
const updatedCollection = {
...collection,
magicMetadata: await updateMagicMetadataProps(
collection.magicMetadata ?? NEW_COLLECTION_MAGIC_METADATA,
collection.key,
updatedMagicMetadataProps
),
} as Collection;
await updateCollectionMagicMetadata(updatedCollection);
const updatedMagicMetadata = await updateMagicMetadata(
collection.magicMetadata ?? NEW_COLLECTION_MAGIC_METADATA,
collection.key,
updatedMagicMetadataProps
);
await updateCollectionMagicMetadata(collection, updatedMagicMetadata);
} catch (e) {
logError(e, 'change file visibility failed');
switch (e.status?.toString()) {
case ServerErrorCodes.FORBIDDEN:
throw Error(CustomError.NOT_FILE_OWNER);
}
logError(e, 'change collection visibility failed');
throw e;
}
};
export const changeCollectionSubType = async (
collection: Collection,
subType: SUB_TYPE
) => {
try {
const updatedMagicMetadataProps: CollectionMagicMetadataProps = {
subType: subType,
};
const updatedMagicMetadata = await updateMagicMetadata(
collection.magicMetadata ?? NEW_COLLECTION_MAGIC_METADATA,
collection.key,
updatedMagicMetadataProps
);
await updateCollectionMagicMetadata(collection, updatedMagicMetadata);
} catch (e) {
logError(e, 'change collection subType failed');
throw e;
}
};

View file

@ -1,5 +1,9 @@
import { SelectedState } from 'types/gallery';
import { EnteFile, EncryptedEnteFile } from 'types/file';
import {
EnteFile,
EncryptedEnteFile,
FileWithUpdatedMagicMetadata,
} from 'types/file';
import { decodeLivePhoto } from 'services/livePhotoService';
import { getFileType } from 'services/typeDetectionService';
import DownloadManager from 'services/downloadManager';
@ -25,12 +29,16 @@ import {
NEW_FILE_MAGIC_METADATA,
VISIBILITY_STATE,
} from 'types/magicMetadata';
import { IsArchived, updateMagicMetadataProps } from 'utils/magicMetadata';
import { IsArchived, updateMagicMetadata } from 'utils/magicMetadata';
import { addLogLine } from 'utils/logging';
import { CustomError } from 'utils/error';
import { convertBytesToHumanReadable } from './size';
import ComlinkCryptoWorker from 'utils/comlink/ComlinkCryptoWorker';
import {
updateFileMagicMetadata,
updateFilePublicMagicMetadata,
} from 'services/fileService';
const WAIT_TIME_IMAGE_CONVERSION = 30 * 1000;
@ -351,64 +359,82 @@ export function isExactTypeHEIC(exactType: string) {
export async function changeFilesVisibility(
files: EnteFile[],
visibility: VISIBILITY_STATE
) {
const updatedFiles: EnteFile[] = [];
): Promise<EnteFile[]> {
const fileWithUpdatedMagicMetadataList: FileWithUpdatedMagicMetadata[] = [];
for (const file of files) {
const updatedMagicMetadataProps: FileMagicMetadataProps = {
visibility,
};
updatedFiles.push({
...file,
magicMetadata: await updateMagicMetadataProps(
fileWithUpdatedMagicMetadataList.push({
file,
updatedMagicMetadata: await updateMagicMetadata(
file.magicMetadata ?? NEW_FILE_MAGIC_METADATA,
file.key,
updatedMagicMetadataProps
),
});
}
return updatedFiles;
return await updateFileMagicMetadata(fileWithUpdatedMagicMetadataList);
}
export async function changeFileCreationTime(
file: EnteFile,
editedTime: number
) {
): Promise<EnteFile> {
const updatedPublicMagicMetadataProps: FilePublicMagicMetadataProps = {
editedTime,
};
file.pubMagicMetadata = await updateMagicMetadataProps(
file.pubMagicMetadata ?? NEW_FILE_MAGIC_METADATA,
file.key,
updatedPublicMagicMetadataProps
);
return file;
const updatedPublicMagicMetadata: FilePublicMagicMetadata =
await updateMagicMetadata(
file.pubMagicMetadata ?? NEW_FILE_MAGIC_METADATA,
file.key,
updatedPublicMagicMetadataProps
);
const updateResult = await updateFilePublicMagicMetadata([
{ file, updatedPublicMagicMetadata },
]);
return updateResult[0];
}
export async function changeFileName(file: EnteFile, editedName: string) {
export async function changeFileName(
file: EnteFile,
editedName: string
): Promise<EnteFile> {
const updatedPublicMagicMetadataProps: FilePublicMagicMetadataProps = {
editedName,
};
file.pubMagicMetadata = await updateMagicMetadataProps(
file.pubMagicMetadata ?? NEW_FILE_MAGIC_METADATA,
file.key,
updatedPublicMagicMetadataProps
);
return file;
const updatedPublicMagicMetadata: FilePublicMagicMetadata =
await updateMagicMetadata(
file.pubMagicMetadata ?? NEW_FILE_MAGIC_METADATA,
file.key,
updatedPublicMagicMetadataProps
);
const updateResult = await updateFilePublicMagicMetadata([
{ file, updatedPublicMagicMetadata },
]);
return updateResult[0];
}
export async function changeCaption(file: EnteFile, caption: string) {
export async function changeCaption(
file: EnteFile,
caption: string
): Promise<EnteFile> {
const updatedPublicMagicMetadataProps: FilePublicMagicMetadataProps = {
caption,
};
file.pubMagicMetadata = await updateMagicMetadataProps(
file.pubMagicMetadata ?? NEW_FILE_MAGIC_METADATA,
file.key,
updatedPublicMagicMetadataProps
);
return file;
const updatedPublicMagicMetadata: FilePublicMagicMetadata =
await updateMagicMetadata(
file.pubMagicMetadata ?? NEW_FILE_MAGIC_METADATA,
file.key,
updatedPublicMagicMetadataProps
);
const updateResult = await updateFilePublicMagicMetadata([
{ file, updatedPublicMagicMetadata },
]);
return updateResult[0];
}
export function isSharedFile(user: User, file: EnteFile) {

View file

@ -20,7 +20,7 @@ export function IsArchived(item: Collection | EnteFile) {
return item.magicMetadata.data.visibility === VISIBILITY_STATE.ARCHIVED;
}
export async function updateMagicMetadataProps(
export async function updateMagicMetadata(
originalMagicMetadata: MagicMetadataCore,
decryptionKey: string,
magicMetadataUpdates: Record<string, any>