Merge pull request #474 from ente-io/master

release
This commit is contained in:
Abhinav Kumar 2022-04-09 22:16:48 +05:30 committed by GitHub
commit 873cc0abc4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 343 additions and 170 deletions

View file

@ -8,7 +8,7 @@ import constants from 'utils/strings/constants';
import AutoSizer from 'react-virtualized-auto-sizer';
import PhotoSwipe from 'components/PhotoSwipe/PhotoSwipe';
import { isInsideBox, isSameDay as isSameDayAnyYear } from 'utils/search';
import { fileIsArchived, formatDateRelative } from 'utils/file';
import { formatDateRelative } from 'utils/file';
import {
ALL_SECTION,
ARCHIVE_SECTION,
@ -25,6 +25,7 @@ import { useRouter } from 'next/router';
import EmptyScreen from './EmptyScreen';
import { AppContext } from 'pages/_app';
import { DeduplicateContext } from 'pages/deduplicate';
import { IsArchived } from 'utils/magicMetadata';
const Container = styled.div`
display: block;
@ -46,6 +47,7 @@ interface Props {
setFiles: SetFiles;
syncWithRemote: () => Promise<void>;
favItemIds?: Set<number>;
archivedCollections?: Set<number>;
setSelected: (
selected: SelectedState | ((selected: SelectedState) => SelectedState)
) => void;
@ -71,6 +73,7 @@ const PhotoFrame = ({
setFiles,
syncWithRemote,
favItemIds,
archivedCollections,
setSelected,
selected,
isFirstLoad,
@ -196,13 +199,14 @@ const PhotoFrame = ({
) {
return false;
}
if (activeCollection === ALL_SECTION && fileIsArchived(item)) {
if (
activeCollection === ALL_SECTION &&
(IsArchived(item) ||
archivedCollections?.has(item.collectionID))
) {
return false;
}
if (
activeCollection === ARCHIVE_SECTION &&
!fileIsArchived(item)
) {
if (activeCollection === ARCHIVE_SECTION && !IsArchived(item)) {
return false;
}

View file

@ -7,7 +7,7 @@ import {
addToFavorites,
removeFromFavorites,
} from 'services/collectionService';
import { updatePublicMagicMetadata } from 'services/fileService';
import { updateFilePublicMagicMetadata } from 'services/fileService';
import { EnteFile } from 'types/file';
import constants from 'utils/strings/constants';
import exifr from 'exifr';
@ -151,7 +151,7 @@ function RenderCreationTime({
unixTimeInMicroSec
);
updatedFile = (
await updatePublicMagicMetadata([updatedFile])
await updateFilePublicMagicMetadata([updatedFile])
)[0];
updateExistingFilePubMetadata(file, updatedFile);
scheduleUpdate();
@ -342,7 +342,7 @@ function RenderFileName({
const newTitle = getFileTitle(newFilename, extension);
let updatedFile = await changeFileName(file, newTitle);
updatedFile = (
await updatePublicMagicMetadata([updatedFile])
await updateFilePublicMagicMetadata([updatedFile])
)[0];
updateExistingFilePubMetadata(file, updatedFile);
scheduleUpdate();

View file

@ -2,12 +2,17 @@ import React from 'react';
import { SetDialogMessage } from 'components/MessageDialog';
import { ListGroup, Popover } from 'react-bootstrap';
import { deleteCollection, renameCollection } from 'services/collectionService';
import { downloadCollection, getSelectedCollection } from 'utils/collection';
import {
changeCollectionVisibilityHelper,
downloadCollection,
getSelectedCollection,
} from 'utils/collection';
import constants from 'utils/strings/constants';
import { SetCollectionNamerAttributes } from './CollectionNamer';
import LinkButton, { ButtonVariant, LinkButtonProps } from './LinkButton';
import { sleep } from 'utils/common';
import { Collection } from 'types/collection';
import { IsArchived } from 'utils/magicMetadata';
interface CollectionOptionsProps {
syncWithRemote: () => Promise<void>;
@ -96,6 +101,19 @@ const CollectionOptions = (props: CollectionOptionsProps) => {
});
};
const archiveCollectionHelper = () => {
changeCollectionVisibilityHelper(
getSelectedCollection(
props.selectedCollectionID,
props.collections
),
props.startLoading,
props.finishLoading,
props.setDialogMessage,
props.syncWithRemote
);
};
const confirmDownloadCollection = () => {
props.setDialogMessage({
title: constants.CONFIRM_DOWNLOAD_COLLECTION,
@ -141,6 +159,18 @@ const CollectionOptions = (props: CollectionOptionsProps) => {
{constants.DOWNLOAD}
</MenuLink>
</MenuItem>
<MenuItem>
<MenuLink onClick={archiveCollectionHelper}>
{IsArchived(
getSelectedCollection(
props.selectedCollectionID,
props.collections
)
)
? constants.UNARCHIVE
: constants.ARCHIVE}
</MenuLink>
</MenuItem>
<MenuItem>
<MenuLink
variant={ButtonVariant.danger}

View file

@ -24,6 +24,9 @@ import {
COLLECTION_SORT_BY,
TRASH_SECTION,
} from 'constants/collection';
import { IsArchived } from 'utils/magicMetadata';
import Archive from 'components/icons/Archive';
import { IconWithMessage } from 'components/IconWithMessage';
interface CollectionProps {
collections: Collection[];
@ -69,10 +72,11 @@ const CollectionBar = styled.div`
justify-content: flex-start;
`;
const Chip = styled.button<{ active: boolean }>`
const Chip = styled.button<{ active: boolean; archived?: boolean }>`
border-radius: 8px;
padding: 4px;
padding-left: 24px;
padding-left: 15px;
${({ archived }) => !archived && 'padding-left: 24px;'}
margin: 3px;
border: none;
background-color: ${(props) =>
@ -227,7 +231,20 @@ export default function Collections(props: CollectionProps) {
<Chip
ref={collectionChipsRef[item.id]}
active={activeCollection === item.id}
onClick={clickHandler(item.id)}>
onClick={clickHandler(item.id)}
archived={IsArchived(item)}>
{IsArchived(item) && (
<IconWithMessage
message={constants.ARCHIVED_ALBUM}>
<div
style={{
display: 'inline-block',
marginRight: '5px',
}}>
<Archive />
</div>
</IconWithMessage>
)}
{item.name}
{item.type !== CollectionType.favorites &&
item.owner.id === user?.id ? (

View file

@ -16,8 +16,3 @@ export enum FILE_TYPE {
LIVE_PHOTO,
OTHERS,
}
export enum VISIBILITY_STATE {
VISIBLE,
ARCHIVED,
}

View file

@ -10,7 +10,7 @@ import { clearKeys, getKey, SESSION_KEYS } from 'utils/storage/sessionStorage';
import {
getLocalFiles,
syncFiles,
updateMagicMetadata,
updateFileMagicMetadata,
trashFiles,
deleteFromTrash,
} from 'services/fileService';
@ -77,6 +77,7 @@ import {
handleCollectionOps,
getSelectedCollection,
isFavoriteCollection,
getArchivedCollections,
} from 'utils/collection';
import { logError } from 'utils/sentry';
import {
@ -101,7 +102,7 @@ import {
NotificationAttributes,
} from 'types/gallery';
import Collections from 'components/pages/gallery/Collections';
import { VISIBILITY_STATE } from 'constants/file';
import { VISIBILITY_STATE } from 'types/magicMetadata';
import ToastNotification from 'components/ToastNotification';
export const DeadCenter = styled.div`
@ -193,6 +194,9 @@ export default function Gallery() {
const [notificationAttributes, setNotificationAttributes] =
useState<NotificationAttributes>(null);
const [archivedCollections, setArchivedCollections] =
useState<Set<number>>();
const showPlanSelectorModal = () => setPlanModalView(true);
const clearNotificationAttributes = () => setNotificationAttributes(null);
@ -342,6 +346,9 @@ export default function Gallery() {
collectionFilesCount.set(id, files.length);
}
setCollectionFilesCount(collectionFilesCount);
const archivedCollections = getArchivedCollections(collections);
setArchivedCollections(new Set(archivedCollections));
};
const clearSelection = function () {
@ -388,7 +395,7 @@ export default function Gallery() {
selected,
visibility
);
await updateMagicMetadata(updatedFiles);
await updateFileMagicMetadata(updatedFiles);
clearSelection();
} catch (e) {
logError(e, 'change file visibility failed');
@ -653,6 +660,7 @@ export default function Gallery() {
setFiles={setFiles}
syncWithRemote={syncWithRemote}
favItemIds={favItemIds}
archivedCollections={archivedCollections}
setSelected={setSelected}
selected={selected}
isFirstLoad={isFirstLoad}

View file

@ -25,6 +25,8 @@ import {
UpdatePublicURL,
} from 'types/collection';
import { COLLECTION_SORT_BY, CollectionType } from 'constants/collection';
import { UpdateMagicMetadataRequest } from 'types/magicMetadata';
import { EncryptionResult } from 'types/upload';
const ENDPOINT = getEndpoint();
const COLLECTION_TABLE = 'collections';
@ -63,6 +65,14 @@ const getCollectionWithSecrets = async (
collection.nameDecryptionNonce,
decryptedKey
));
if (collection.magicMetadata?.data) {
collection.magicMetadata.data = await worker.decryptMetadata(
collection.magicMetadata.data,
collection.magicMetadata.header,
decryptedKey
);
}
return {
...collection,
key: decryptedKey,
@ -275,6 +285,7 @@ export const createCollection = async (
sharees: null,
updationTime: null,
isDeleted: false,
magicMetadata: null,
};
let createdCollection: Collection = await postCollection(
newCollection,
@ -494,6 +505,48 @@ export const deleteCollection = async (
}
};
export const updateCollectionMagicMetadata = async (collection: Collection) => {
const token = getToken();
if (!token) {
return;
}
const worker = await new CryptoWorker();
const { file: encryptedMagicMetadata }: EncryptionResult =
await worker.encryptMetadata(
collection.magicMetadata.data,
collection.key
);
const reqBody: UpdateMagicMetadataRequest = {
id: collection.id,
magicMetadata: {
version: collection.magicMetadata.version,
count: collection.magicMetadata.count,
data: encryptedMagicMetadata.encryptedData as unknown as string,
header: encryptedMagicMetadata.decryptionHeader,
},
};
await HTTPService.put(
`${ENDPOINT}/collections/magic-metadata`,
reqBody,
null,
{
'X-Auth-Token': token,
}
);
const updatedCollection: Collection = {
...collection,
magicMetadata: {
...collection.magicMetadata,
version: collection.magicMetadata.version + 1,
},
};
return updatedCollection;
};
export const renameCollection = async (
collection: Collection,
newCollectionName: string

View file

@ -13,9 +13,10 @@ import {
sortFiles,
} from 'utils/file';
import CryptoWorker from 'utils/crypto';
import { EnteFile, TrashRequest, UpdateMagicMetadataRequest } from 'types/file';
import { EnteFile, TrashRequest } from 'types/file';
import { SetFiles } from 'types/gallery';
import { MAX_TRASH_BATCH_SIZE } from 'constants/file';
import { BulkUpdateMagicMetadataRequest } from 'types/magicMetadata';
const ENDPOINT = getEndpoint();
const FILES_TABLE = 'files';
@ -203,12 +204,12 @@ export const deleteFromTrash = async (filesToDelete: number[]) => {
}
};
export const updateMagicMetadata = async (files: EnteFile[]) => {
export const updateFileMagicMetadata = async (files: EnteFile[]) => {
const token = getToken();
if (!token) {
return;
}
const reqBody: UpdateMagicMetadataRequest = { metadataList: [] };
const reqBody: BulkUpdateMagicMetadataRequest = { metadataList: [] };
const worker = await new CryptoWorker();
for (const file of files) {
const { file: encryptedMagicMetadata }: EncryptionResult =
@ -237,12 +238,12 @@ export const updateMagicMetadata = async (files: EnteFile[]) => {
);
};
export const updatePublicMagicMetadata = async (files: EnteFile[]) => {
export const updateFilePublicMagicMetadata = async (files: EnteFile[]) => {
const token = getToken();
if (!token) {
return;
}
const reqBody: UpdateMagicMetadataRequest = { metadataList: [] };
const reqBody: BulkUpdateMagicMetadataRequest = { metadataList: [] };
const worker = await new CryptoWorker();
for (const file of files) {
const { file: encryptedPubMagicMetadata }: EncryptionResult =

View file

@ -7,7 +7,7 @@ import {
} from 'utils/file';
import { logError } from 'utils/sentry';
import downloadManager from './downloadManager';
import { updatePublicMagicMetadata } from './fileService';
import { updateFilePublicMagicMetadata } from './fileService';
import { EnteFile } from 'types/file';
import { getRawExif } from './upload/exifService';
@ -60,7 +60,7 @@ export async function updateCreationTimeWithExif(
correctCreationTime
);
updatedFile = (
await updatePublicMagicMetadata([updatedFile])
await updateFilePublicMagicMetadata([updatedFile])
)[0];
updateExistingFilePubMetadata(file, updatedFile);
}

View file

@ -1,6 +1,7 @@
import { User } from 'types/user';
import { EnteFile } from 'types/file';
import { CollectionType } from 'constants/collection';
import { MagicMetadataCore, VISIBILITY_STATE } from 'types/magicMetadata';
export interface Collection {
id: number;
@ -18,6 +19,7 @@ export interface Collection {
isDeleted: boolean;
isSharedCollection?: boolean;
publicURLs?: PublicURL[];
magicMetadata?: CollectionMagicMetadata;
}
export interface PublicURL {
@ -80,3 +82,12 @@ export interface RemoveFromCollectionRequest {
collectionID: number;
fileIDs: number[];
}
export interface CollectionMagicMetadataProps {
visibility?: VISIBILITY_STATE;
}
export interface CollectionMagicMetadata
extends Omit<MagicMetadataCore, 'data'> {
data: CollectionMagicMetadataProps;
}

View file

@ -1,4 +1,4 @@
import { VISIBILITY_STATE } from 'constants/file';
import { MagicMetadataCore, VISIBILITY_STATE } from 'types/magicMetadata';
import { DataStream, Metadata } from 'types/upload';
export interface fileAttribute {
@ -7,33 +7,22 @@ export interface fileAttribute {
decryptionHeader: string;
}
export interface MagicMetadataCore {
version: number;
count: number;
header: string;
data: Record<string, any>;
}
export interface EncryptedMagicMetadataCore
extends Omit<MagicMetadataCore, 'data'> {
data: string;
}
export interface MagicMetadataProps {
export interface FileMagicMetadataProps {
visibility?: VISIBILITY_STATE;
}
export interface MagicMetadata extends Omit<MagicMetadataCore, 'data'> {
data: MagicMetadataProps;
export interface FileMagicMetadata extends Omit<MagicMetadataCore, 'data'> {
data: FileMagicMetadataProps;
}
export interface PublicMagicMetadataProps {
export interface FilePublicMagicMetadataProps {
editedTime?: number;
editedName?: string;
}
export interface PublicMagicMetadata extends Omit<MagicMetadataCore, 'data'> {
data: PublicMagicMetadataProps;
export interface FilePublicMagicMetadata
extends Omit<MagicMetadataCore, 'data'> {
data: FilePublicMagicMetadataProps;
}
export interface EnteFile {
@ -43,8 +32,8 @@ export interface EnteFile {
file: fileAttribute;
thumbnail: fileAttribute;
metadata: Metadata;
magicMetadata: MagicMetadata;
pubMagicMetadata: PublicMagicMetadata;
magicMetadata: FileMagicMetadata;
pubMagicMetadata: FilePublicMagicMetadata;
encryptedKey: string;
keyDecryptionNonce: string;
key: string;
@ -60,22 +49,6 @@ export interface EnteFile {
updationTime: number;
}
export interface UpdateMagicMetadataRequest {
metadataList: UpdateMagicMetadata[];
}
export interface UpdateMagicMetadata {
id: number;
magicMetadata: EncryptedMagicMetadataCore;
}
export const NEW_MAGIC_METADATA: MagicMetadataCore = {
version: 0,
data: {},
header: null,
count: 0,
};
export interface TrashRequest {
items: TrashRequestItems[];
}

View file

@ -0,0 +1,39 @@
export interface MagicMetadataCore {
version: number;
count: number;
header: string;
data: Record<string, any>;
}
export interface EncryptedMagicMetadataCore
extends Omit<MagicMetadataCore, 'data'> {
data: string;
}
export enum VISIBILITY_STATE {
VISIBLE,
ARCHIVED,
}
export const NEW_FILE_MAGIC_METADATA: MagicMetadataCore = {
version: 0,
data: {},
header: null,
count: 0,
};
export const NEW_COLLECTION_MAGIC_METADATA: MagicMetadataCore = {
version: 1,
data: {},
header: null,
count: 0,
};
export interface BulkUpdateMagicMetadataRequest {
metadataList: UpdateMagicMetadataRequest[];
}
export interface UpdateMagicMetadataRequest {
id: number;
magicMetadata: EncryptedMagicMetadataCore;
}

View file

@ -3,21 +3,27 @@ import {
moveToCollection,
removeFromCollection,
restoreToCollection,
updateCollectionMagicMetadata,
} from 'services/collectionService';
import { downloadFiles, getSelectedFiles } from 'utils/file';
import { getLocalFiles } from 'services/fileService';
import { EnteFile } from 'types/file';
import { CustomError } from 'utils/error';
import { CustomError, ServerErrorCodes } from 'utils/error';
import { SelectedState } from 'types/gallery';
import { User } from 'types/user';
import { getData, LS_KEYS } from 'utils/storage/localStorage';
import { SetDialogMessage } from 'components/MessageDialog';
import { logError } from 'utils/sentry';
import constants from 'utils/strings/constants';
import { Collection } from 'types/collection';
import { Collection, CollectionMagicMetadataProps } from 'types/collection';
import { CollectionType } from 'constants/collection';
import { getAlbumSiteHost } from 'constants/pages';
import { getUnixTimeInMicroSecondsWithDelta } from 'utils/time';
import {
NEW_COLLECTION_MAGIC_METADATA,
VISIBILITY_STATE,
} from 'types/magicMetadata';
import { IsArchived, updateMagicMetadataProps } from 'utils/magicMetadata';
export enum COLLECTION_OPS_TYPE {
ADD,
@ -161,3 +167,56 @@ export const shareExpiryOptions = [
value: () => getUnixTimeInMicroSecondsWithDelta({ years: 1 }),
},
];
export const changeCollectionVisibilityHelper = async (
collection: Collection,
startLoading: () => void,
finishLoading: () => void,
setDialogMessage: SetDialogMessage,
syncWithRemote: () => Promise<void>
) => {
startLoading();
try {
const updatedMagicMetadataProps: CollectionMagicMetadataProps = {
visibility: collection.magicMetadata?.data.visibility
? VISIBILITY_STATE.VISIBLE
: VISIBILITY_STATE.ARCHIVED,
};
const updatedCollection = {
...collection,
magicMetadata: await updateMagicMetadataProps(
collection.magicMetadata ?? NEW_COLLECTION_MAGIC_METADATA,
collection.key,
updatedMagicMetadataProps
),
} as Collection;
await updateCollectionMagicMetadata(updatedCollection);
} catch (e) {
logError(e, 'change file visibility failed');
switch (e.status?.toString()) {
case ServerErrorCodes.FORBIDDEN:
setDialogMessage({
title: constants.ERROR,
staticBackdrop: true,
close: { variant: 'danger' },
content: constants.NOT_FILE_OWNER,
});
return;
}
setDialogMessage({
title: constants.ERROR,
staticBackdrop: true,
close: { variant: 'danger' },
content: constants.UNKNOWN_ERROR,
});
} finally {
await syncWithRemote();
finishLoading();
}
};
export const getArchivedCollections = (collections: Collection[]) => {
return collections.filter(IsArchived).map((collection) => collection.id);
};

View file

@ -2,9 +2,8 @@ import { SelectedState } from 'types/gallery';
import {
EnteFile,
fileAttribute,
MagicMetadataProps,
NEW_MAGIC_METADATA,
PublicMagicMetadataProps,
FileMagicMetadataProps,
FilePublicMagicMetadataProps,
} from 'types/file';
import { decodeMotionPhoto } from 'services/motionPhotoService';
import { getFileType } from 'services/typeDetectionService';
@ -20,11 +19,12 @@ import {
TYPE_HEIC,
TYPE_HEIF,
FILE_TYPE,
VISIBILITY_STATE,
} from 'constants/file';
import PublicCollectionDownloadManager from 'services/publicCollectionDownloadManager';
import HEICConverter from 'services/heicConverter/heicConverterService';
import ffmpegService from 'services/ffmpeg/ffmpegService';
import { NEW_FILE_MAGIC_METADATA, VISIBILITY_STATE } from 'types/magicMetadata';
import { updateMagicMetadataProps } from 'utils/magicMetadata';
export function downloadAsFile(filename: string, content: string) {
const file = new Blob([content], {
type: 'text/plain',
@ -370,90 +370,6 @@ export async function convertForPreview(
return [fileBlob];
}
export function fileIsArchived(file: EnteFile) {
if (
!file ||
!file.magicMetadata ||
!file.magicMetadata.data ||
typeof file.magicMetadata.data === 'string' ||
typeof file.magicMetadata.data.visibility === 'undefined'
) {
return false;
}
return file.magicMetadata.data.visibility === VISIBILITY_STATE.ARCHIVED;
}
export async function updateMagicMetadataProps(
file: EnteFile,
magicMetadataUpdates: MagicMetadataProps
) {
const worker = await new CryptoWorker();
if (!file.magicMetadata) {
file.magicMetadata = NEW_MAGIC_METADATA;
}
if (typeof file.magicMetadata.data === 'string') {
file.magicMetadata.data = (await worker.decryptMetadata(
file.magicMetadata.data,
file.magicMetadata.header,
file.key
)) as MagicMetadataProps;
}
if (magicMetadataUpdates) {
// copies the existing magic metadata properties of the files and updates the visibility value
// The expected behaviour while updating magic metadata is to let the existing property as it is and update/add the property you want
const magicMetadataProps: MagicMetadataProps = {
...file.magicMetadata.data,
...magicMetadataUpdates,
};
return {
...file,
magicMetadata: {
...file.magicMetadata,
data: magicMetadataProps,
count: Object.keys(file.magicMetadata.data).length,
},
};
} else {
return file;
}
}
export async function updatePublicMagicMetadataProps(
file: EnteFile,
publicMetadataUpdates: PublicMagicMetadataProps
) {
const worker = await new CryptoWorker();
if (!file.pubMagicMetadata) {
file.pubMagicMetadata = NEW_MAGIC_METADATA;
}
if (typeof file.pubMagicMetadata.data === 'string') {
file.pubMagicMetadata.data = (await worker.decryptMetadata(
file.pubMagicMetadata.data,
file.pubMagicMetadata.header,
file.key
)) as PublicMagicMetadataProps;
}
if (publicMetadataUpdates) {
const publicMetadataProps = {
...file.pubMagicMetadata.data,
...publicMetadataUpdates,
};
return {
...file,
pubMagicMetadata: {
...file.pubMagicMetadata,
data: publicMetadataProps,
count: Object.keys(file.pubMagicMetadata.data).length,
},
};
} else {
return file;
}
}
export async function changeFilesVisibility(
files: EnteFile[],
selected: SelectedState,
@ -462,13 +378,18 @@ export async function changeFilesVisibility(
const selectedFiles = getSelectedFiles(selected, files);
const updatedFiles: EnteFile[] = [];
for (const file of selectedFiles) {
const updatedMagicMetadataProps: MagicMetadataProps = {
const updatedMagicMetadataProps: FileMagicMetadataProps = {
visibility,
};
updatedFiles.push(
await updateMagicMetadataProps(file, updatedMagicMetadataProps)
);
updatedFiles.push({
...file,
magicMetadata: await updateMagicMetadataProps(
file.magicMetadata ?? NEW_FILE_MAGIC_METADATA,
file.key,
updatedMagicMetadataProps
),
});
}
return updatedFiles;
}
@ -477,25 +398,33 @@ export async function changeFileCreationTime(
file: EnteFile,
editedTime: number
) {
const updatedPublicMagicMetadataProps: PublicMagicMetadataProps = {
const updatedPublicMagicMetadataProps: FilePublicMagicMetadataProps = {
editedTime,
};
return await updatePublicMagicMetadataProps(
file,
updatedPublicMagicMetadataProps
);
return {
...file,
publicMagicMetadata: await updateMagicMetadataProps(
file.pubMagicMetadata ?? NEW_FILE_MAGIC_METADATA,
file.key,
updatedPublicMagicMetadataProps
),
} as EnteFile;
}
export async function changeFileName(file: EnteFile, editedName: string) {
const updatedPublicMagicMetadataProps: PublicMagicMetadataProps = {
const updatedPublicMagicMetadataProps: FilePublicMagicMetadataProps = {
editedName,
};
return await updatePublicMagicMetadataProps(
file,
updatedPublicMagicMetadataProps
);
return {
...file,
publicMagicMetadata: await updateMagicMetadataProps(
file.pubMagicMetadata ?? NEW_FILE_MAGIC_METADATA,
file.key,
updatedPublicMagicMetadataProps
),
} as EnteFile;
}
export function isSharedFile(file: EnteFile) {
@ -590,4 +519,4 @@ export const isLivePhoto = (file: EnteFile) =>
file.metadata.fileType === FILE_TYPE.LIVE_PHOTO;
export const isImageOrVideo = (fileType: FILE_TYPE) =>
fileType in [FILE_TYPE.IMAGE, FILE_TYPE.VIDEO];
[FILE_TYPE.IMAGE, FILE_TYPE.VIDEO].includes(fileType);

View file

@ -0,0 +1,52 @@
import { Collection } from 'types/collection';
import { EnteFile, FileMagicMetadataProps } from 'types/file';
import { MagicMetadataCore, VISIBILITY_STATE } from 'types/magicMetadata';
import CryptoWorker from 'utils/crypto';
export function IsArchived(item: Collection | EnteFile) {
if (
!item ||
!item.magicMetadata ||
!item.magicMetadata.data ||
typeof item.magicMetadata.data === 'string' ||
typeof item.magicMetadata.data.visibility === 'undefined'
) {
return false;
}
return item.magicMetadata.data.visibility === VISIBILITY_STATE.ARCHIVED;
}
export async function updateMagicMetadataProps(
originalMagicMetadata: MagicMetadataCore,
decryptionKey: string,
magicMetadataUpdates: Record<string, any>
) {
const worker = await new CryptoWorker();
if (!originalMagicMetadata) {
throw Error('invalid originalMagicMetadata ');
}
if (typeof originalMagicMetadata.data === 'string') {
originalMagicMetadata.data = (await worker.decryptMetadata(
originalMagicMetadata.data,
originalMagicMetadata.header,
decryptionKey
)) as FileMagicMetadataProps;
}
if (magicMetadataUpdates) {
// copies the existing magic metadata properties of the files and updates the visibility value
// The expected behavior while updating magic metadata is to let the existing property as it is and update/add the property you want
const magicMetadataProps: FileMagicMetadataProps = {
...originalMagicMetadata.data,
...magicMetadataUpdates,
};
return {
...originalMagicMetadata,
data: magicMetadataProps,
count: Object.keys(magicMetadataProps).length,
};
} else {
return originalMagicMetadata;
}
}

View file

@ -380,8 +380,10 @@ const englishConstants = {
<p>all files will be queued for download sequentially</p>
</>
),
ARCHIVED_ALBUM: 'archived album',
DOWNLOAD_COLLECTION_FAILED: 'album downloading failed, please try again',
CREATE_ALBUM_FAILED: 'failed to create album , please try again',
SEARCH_HINT: () => (
<span>try searching for New York, April 14, Christmas...</span>
),