Merge branch 'main' into folder-plus-file-drop
This commit is contained in:
commit
3665d9d4a5
|
@ -12,9 +12,6 @@ export default function CollectionSortOptions(props: CollectionSortProps) {
|
|||
<SortByOption sortBy={COLLECTION_SORT_BY.NAME}>
|
||||
{constants.SORT_BY_NAME}
|
||||
</SortByOption>
|
||||
<SortByOption sortBy={COLLECTION_SORT_BY.CREATION_TIME_DESCENDING}>
|
||||
{constants.SORT_BY_CREATION_TIME_DESCENDING}
|
||||
</SortByOption>
|
||||
<SortByOption sortBy={COLLECTION_SORT_BY.CREATION_TIME_ASCENDING}>
|
||||
{constants.SORT_BY_CREATION_TIME_ASCENDING}
|
||||
</SortByOption>
|
||||
|
|
|
@ -15,7 +15,7 @@ import {
|
|||
import { ManageDownloadAccess } from './downloadAccess';
|
||||
import { handleSharingErrors } from 'utils/error/ui';
|
||||
import { SetPublicShareProp } from 'types/publicCollection';
|
||||
// import { ManagePublicCollect } from './publicCollect';
|
||||
import { ManagePublicCollect } from './publicCollect';
|
||||
|
||||
interface Iprops {
|
||||
publicShareProp: PublicURL;
|
||||
|
@ -77,6 +77,13 @@ export default function PublicShareManage({
|
|||
updatePublicShareURLHelper
|
||||
}
|
||||
/>
|
||||
<ManagePublicCollect
|
||||
collection={collection}
|
||||
publicShareProp={publicShareProp}
|
||||
updatePublicShareURLHelper={
|
||||
updatePublicShareURLHelper
|
||||
}
|
||||
/>
|
||||
<ManageDownloadAccess
|
||||
collection={collection}
|
||||
publicShareProp={publicShareProp}
|
||||
|
@ -91,13 +98,6 @@ export default function PublicShareManage({
|
|||
updatePublicShareURLHelper
|
||||
}
|
||||
/>
|
||||
{/* <ManagePublicCollect
|
||||
collection={collection}
|
||||
publicShareProp={publicShareProp}
|
||||
updatePublicShareURLHelper={
|
||||
updatePublicShareURLHelper
|
||||
}
|
||||
/> */}
|
||||
</Stack>
|
||||
{sharableLinkError && (
|
||||
<Typography
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import { Box, Typography } from '@mui/material';
|
||||
import { AppContext } from 'pages/_app';
|
||||
import React, { useContext } from 'react';
|
||||
import React from 'react';
|
||||
import { PublicURL, Collection, UpdatePublicURL } from 'types/collection';
|
||||
import constants from 'utils/strings/constants';
|
||||
import PublicShareSwitch from '../switch';
|
||||
|
@ -16,35 +15,13 @@ export function ManagePublicCollect({
|
|||
updatePublicShareURLHelper,
|
||||
collection,
|
||||
}: Iprops) {
|
||||
const appContext = useContext(AppContext);
|
||||
|
||||
const handleFileDownloadSetting = () => {
|
||||
if (!publicShareProp.enableCollect) {
|
||||
enablePublicCollect();
|
||||
} else {
|
||||
updatePublicShareURLHelper({
|
||||
collectionID: collection.id,
|
||||
enableCollect: false,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const enablePublicCollect = () => {
|
||||
appContext.setDialogMessage({
|
||||
title: constants.ENABLE_PUBLIC_COLLECT,
|
||||
content: constants.ENABLE_PUBLIC_COLLECT_MESSAGE(),
|
||||
close: { text: constants.CANCEL },
|
||||
proceed: {
|
||||
text: constants.ENABLE,
|
||||
action: () =>
|
||||
updatePublicShareURLHelper({
|
||||
collectionID: collection.id,
|
||||
enableCollect: true,
|
||||
}),
|
||||
variant: 'accent',
|
||||
},
|
||||
updatePublicShareURLHelper({
|
||||
collectionID: collection.id,
|
||||
enableCollect: !publicShareProp.enableCollect,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Typography mb={0.5}>{constants.PUBLIC_COLLECT}</Typography>
|
||||
|
|
|
@ -28,6 +28,7 @@ export interface SingleInputFormProps {
|
|||
hiddenPostInput?: any;
|
||||
autoComplete?: string;
|
||||
blockButton?: boolean;
|
||||
hiddenLabel?: boolean;
|
||||
}
|
||||
|
||||
export default function SingleInputForm(props: SingleInputFormProps) {
|
||||
|
@ -88,12 +89,15 @@ export default function SingleInputForm(props: SingleInputFormProps) {
|
|||
<form noValidate onSubmit={handleSubmit}>
|
||||
{props.hiddenPreInput}
|
||||
<TextField
|
||||
hiddenLabel={props.hiddenLabel}
|
||||
variant="filled"
|
||||
fullWidth
|
||||
type={showPassword ? 'text' : props.fieldType}
|
||||
id={props.fieldType}
|
||||
name={props.fieldType}
|
||||
label={props.placeholder}
|
||||
{...(props.hiddenLabel
|
||||
? { placeholder: props.placeholder }
|
||||
: { label: props.placeholder })}
|
||||
value={values.inputValue}
|
||||
onChange={handleChange('inputValue')}
|
||||
error={Boolean(errors.inputValue)}
|
||||
|
|
|
@ -86,6 +86,12 @@ interface Props {
|
|||
}
|
||||
|
||||
export default function Uploader(props: Props) {
|
||||
const appContext = useContext(AppContext);
|
||||
const galleryContext = useContext(GalleryContext);
|
||||
const publicCollectionGalleryContext = useContext(
|
||||
PublicCollectionGalleryContext
|
||||
);
|
||||
|
||||
const [uploadProgressView, setUploadProgressView] = useState(false);
|
||||
const [uploadStage, setUploadStage] = useState<UPLOAD_STAGES>(
|
||||
UPLOAD_STAGES.START
|
||||
|
@ -109,8 +115,8 @@ export default function Uploader(props: Props) {
|
|||
const [importSuggestion, setImportSuggestion] = useState<ImportSuggestion>(
|
||||
DEFAULT_IMPORT_SUGGESTION
|
||||
);
|
||||
const appContext = useContext(AppContext);
|
||||
const galleryContext = useContext(GalleryContext);
|
||||
const [electronFiles, setElectronFiles] = useState<ElectronFile[]>(null);
|
||||
const [webFiles, setWebFiles] = useState([]);
|
||||
|
||||
const toUploadFiles = useRef<File[] | ElectronFile[]>(null);
|
||||
const isPendingDesktopUpload = useRef(false);
|
||||
|
@ -119,23 +125,17 @@ export default function Uploader(props: Props) {
|
|||
const pickedUploadType = useRef<PICKED_UPLOAD_TYPE>(null);
|
||||
const zipPaths = useRef<string[]>(null);
|
||||
const currentUploadPromise = useRef<Promise<void>>(null);
|
||||
const [electronFiles, setElectronFiles] = useState<ElectronFile[]>(null);
|
||||
const [webFiles, setWebFiles] = useState([]);
|
||||
const uploadRunning = useRef(false);
|
||||
const uploaderNameRef = useRef<string>(null);
|
||||
|
||||
const closeUploadProgress = () => setUploadProgressView(false);
|
||||
const showUserNameInputDialog = () => setUserNameInputDialogView(true);
|
||||
const closeUserNameInputDialog = () => setUserNameInputDialogView(false);
|
||||
|
||||
const setCollectionName = (collectionName: string) => {
|
||||
isPendingDesktopUpload.current = true;
|
||||
pendingDesktopUploadCollectionName.current = collectionName;
|
||||
};
|
||||
|
||||
const uploadRunning = useRef(false);
|
||||
const publicCollectionGalleryContext = useContext(
|
||||
PublicCollectionGalleryContext
|
||||
);
|
||||
|
||||
const handleChoiceModalClose = () => {
|
||||
setChoiceModalView(false);
|
||||
uploadRunning.current = false;
|
||||
|
@ -144,6 +144,11 @@ export default function Uploader(props: Props) {
|
|||
uploadRunning.current = false;
|
||||
};
|
||||
|
||||
const handleUserNameInputDialogClose = () => {
|
||||
setUserNameInputDialogView(false);
|
||||
uploadRunning.current = false;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
uploadManager.init(
|
||||
{
|
||||
|
@ -308,7 +313,6 @@ export default function Uploader(props: Props) {
|
|||
[collection],
|
||||
uploaderName
|
||||
);
|
||||
toUploadFiles.current = null;
|
||||
} catch (e) {
|
||||
logError(e, 'Failed to upload files to existing collections');
|
||||
}
|
||||
|
@ -470,11 +474,13 @@ export default function Uploader(props: Props) {
|
|||
try {
|
||||
addLogLine('user retrying failed upload');
|
||||
const filesWithCollections =
|
||||
await uploadManager.getFailedFilesWithCollections();
|
||||
uploadManager.getFailedFilesWithCollections();
|
||||
const uploaderName = uploadManager.getUploaderName();
|
||||
await preUploadAction();
|
||||
await uploadManager.queueFilesForUpload(
|
||||
filesWithCollections.files,
|
||||
filesWithCollections.collections
|
||||
filesWithCollections.collections,
|
||||
uploaderName
|
||||
);
|
||||
} catch (err) {
|
||||
showUserFacingError(err.message);
|
||||
|
@ -546,11 +552,8 @@ export default function Uploader(props: Props) {
|
|||
const uploaderName = await getPublicCollectionUploaderName(
|
||||
getPublicCollectionUID(publicCollectionGalleryContext.token)
|
||||
);
|
||||
if (!uploaderName) {
|
||||
showUserNameInputDialog();
|
||||
} else {
|
||||
await handlePublicUpload(uploaderName, true);
|
||||
}
|
||||
uploaderNameRef.current = uploaderName;
|
||||
showUserNameInputDialog();
|
||||
return;
|
||||
}
|
||||
if (isPendingDesktopUpload.current) {
|
||||
|
@ -709,8 +712,10 @@ export default function Uploader(props: Props) {
|
|||
/>
|
||||
<UserNameInputDialog
|
||||
open={userNameInputDialogView}
|
||||
onClose={closeUserNameInputDialog}
|
||||
onClose={handleUserNameInputDialogClose}
|
||||
onNameSubmit={handlePublicUpload}
|
||||
toUploadFilesCount={toUploadFiles.current?.length}
|
||||
uploaderName={uploaderNameRef.current}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -5,7 +5,13 @@ import AutoAwesomeOutlinedIcon from '@mui/icons-material/AutoAwesomeOutlined';
|
|||
import { Typography } from '@mui/material';
|
||||
import SingleInputForm from './SingleInputForm';
|
||||
|
||||
export default function UserNameInputDialog({ open, onClose, onNameSubmit }) {
|
||||
export default function UserNameInputDialog({
|
||||
open,
|
||||
onClose,
|
||||
onNameSubmit,
|
||||
toUploadFilesCount,
|
||||
uploaderName,
|
||||
}) {
|
||||
const handleSubmit = async (inputValue: string) => {
|
||||
onClose();
|
||||
await onNameSubmit(inputValue);
|
||||
|
@ -23,12 +29,14 @@ export default function UserNameInputDialog({ open, onClose, onNameSubmit }) {
|
|||
{constants.PUBLIC_UPLOADER_NAME_MESSAGE}
|
||||
</Typography>
|
||||
<SingleInputForm
|
||||
hiddenLabel
|
||||
initialValue={uploaderName}
|
||||
callback={handleSubmit}
|
||||
placeholder={constants.ENTER_FILE_NAME}
|
||||
buttonText={constants.CONTINUE}
|
||||
placeholder={constants.NAME_PLACEHOLDER}
|
||||
buttonText={constants.ADD_X_PHOTOS(toUploadFilesCount)}
|
||||
fieldType="text"
|
||||
blockButton
|
||||
secondaryButtonAction={() => {}}
|
||||
secondaryButtonAction={onClose}
|
||||
/>
|
||||
</DialogBox>
|
||||
);
|
||||
|
|
|
@ -21,7 +21,6 @@ export enum CollectionSummaryType {
|
|||
export enum COLLECTION_SORT_BY {
|
||||
NAME,
|
||||
CREATION_TIME_ASCENDING,
|
||||
CREATION_TIME_DESCENDING,
|
||||
UPDATION_TIME_DESCENDING,
|
||||
}
|
||||
|
||||
|
|
|
@ -736,11 +736,6 @@ export function sortCollectionSummaries(
|
|||
return collectionSummaries
|
||||
.sort((a, b) => {
|
||||
switch (sortBy) {
|
||||
case COLLECTION_SORT_BY.CREATION_TIME_DESCENDING:
|
||||
return compareCollectionsLatestFile(
|
||||
b.latestFile,
|
||||
a.latestFile
|
||||
);
|
||||
case COLLECTION_SORT_BY.CREATION_TIME_ASCENDING:
|
||||
return (
|
||||
-1 *
|
||||
|
|
|
@ -22,6 +22,7 @@ import {
|
|||
getUint8ArrayView,
|
||||
} from '../readerService';
|
||||
import { generateThumbnail } from './thumbnailService';
|
||||
import { EncryptedMagicMetadataCore } from 'types/magicMetadata';
|
||||
|
||||
const EDITED_FILE_SUFFIX = '-edited';
|
||||
|
||||
|
@ -110,6 +111,16 @@ export async function encryptFile(
|
|||
const { file: encryptedMetadata }: EncryptionResult =
|
||||
await worker.encryptMetadata(file.metadata, fileKey);
|
||||
|
||||
const { file: encryptedPubMagicMetadataData }: EncryptionResult =
|
||||
await worker.encryptMetadata(file.pubMagicMetadata.data, fileKey);
|
||||
|
||||
const encryptedPubMagicMetadata: EncryptedMagicMetadataCore = {
|
||||
version: file.pubMagicMetadata.version,
|
||||
count: file.pubMagicMetadata.count,
|
||||
data: encryptedPubMagicMetadataData.encryptedData as unknown as string,
|
||||
header: encryptedPubMagicMetadataData.decryptionHeader,
|
||||
};
|
||||
|
||||
const encryptedKey: B64EncryptionResult = await worker.encryptToB64(
|
||||
fileKey,
|
||||
encryptionKey
|
||||
|
@ -120,6 +131,7 @@ export async function encryptFile(
|
|||
file: encryptedFiledata,
|
||||
thumbnail: encryptedThumbnail,
|
||||
metadata: encryptedMetadata,
|
||||
pubMagicMetadata: encryptedPubMagicMetadata,
|
||||
localID: file.localID,
|
||||
},
|
||||
fileKey: encryptedKey,
|
||||
|
|
17
src/services/upload/magicMetadataService.ts
Normal file
17
src/services/upload/magicMetadataService.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
import {
|
||||
FilePublicMagicMetadataProps,
|
||||
FilePublicMagicMetadata,
|
||||
} from 'types/file';
|
||||
import { NEW_FILE_MAGIC_METADATA } from 'types/magicMetadata';
|
||||
import { updateMagicMetadataProps } from 'utils/magicMetadata';
|
||||
|
||||
export async function constructPublicMagicMetadata(
|
||||
publicMagicMetadataProps: FilePublicMagicMetadataProps
|
||||
): Promise<FilePublicMagicMetadata> {
|
||||
const pubMagicMetadata = await updateMagicMetadataProps(
|
||||
NEW_FILE_MAGIC_METADATA,
|
||||
null,
|
||||
publicMagicMetadataProps
|
||||
);
|
||||
return pubMagicMetadata;
|
||||
}
|
|
@ -389,13 +389,17 @@ class UploadManager {
|
|||
uploadCancelService.requestUploadCancelation();
|
||||
}
|
||||
|
||||
async getFailedFilesWithCollections() {
|
||||
getFailedFilesWithCollections() {
|
||||
return {
|
||||
files: this.failedFiles,
|
||||
collections: [...this.collections.values()],
|
||||
};
|
||||
}
|
||||
|
||||
getUploaderName() {
|
||||
return this.uploaderName;
|
||||
}
|
||||
|
||||
private updateExistingFiles(decryptedFile: EnteFile) {
|
||||
if (!decryptedFile) {
|
||||
throw Error("decrypted file can't be undefined");
|
||||
|
|
|
@ -34,6 +34,8 @@ import { uploadStreamUsingMultipart } from './multiPartUploadService';
|
|||
import UIService from './uiService';
|
||||
import { USE_CF_PROXY } from 'constants/upload';
|
||||
import publicUploadHttpClient from './publicUploadHttpClient';
|
||||
import { constructPublicMagicMetadata } from './magicMetadataService';
|
||||
import { FilePublicMagicMetadataProps } from 'types/file';
|
||||
|
||||
class UploadService {
|
||||
private uploadURLs: UploadURL[] = [];
|
||||
|
@ -127,6 +129,12 @@ class UploadService {
|
|||
return clusterLivePhotoFiles(mediaFiles);
|
||||
}
|
||||
|
||||
constructPublicMagicMetadata(
|
||||
publicMagicMetadataProps: FilePublicMagicMetadataProps
|
||||
) {
|
||||
return constructPublicMagicMetadata(publicMagicMetadataProps);
|
||||
}
|
||||
|
||||
async encryptAsset(
|
||||
worker: any,
|
||||
file: FileWithMetadata,
|
||||
|
@ -188,6 +196,7 @@ class UploadService {
|
|||
objectKey: thumbnailObjectKey,
|
||||
},
|
||||
metadata: file.metadata,
|
||||
pubMagicMetadata: file.pubMagicMetadata,
|
||||
};
|
||||
return backupedFile;
|
||||
} catch (e) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { EnteFile } from 'types/file';
|
||||
import { EnteFile, FilePublicMagicMetadata } from 'types/file';
|
||||
import { handleUploadError, CustomError } from 'utils/error';
|
||||
import { logError } from 'utils/sentry';
|
||||
import { findMatchingExistingFiles } from 'utils/upload';
|
||||
|
@ -10,6 +10,7 @@ import {
|
|||
FileWithCollection,
|
||||
BackupedFile,
|
||||
UploadFile,
|
||||
FileWithMetadata,
|
||||
FileTypeInfo,
|
||||
} from 'types/upload';
|
||||
import { addLocalLog, addLogLine } from 'utils/logging';
|
||||
|
@ -17,6 +18,7 @@ import { convertBytesToHumanReadable } from 'utils/file/size';
|
|||
import { sleep } from 'utils/common';
|
||||
import { addToCollection } from 'services/collectionService';
|
||||
import uploadCancelService from './uploadCancelService';
|
||||
import uploadService from './uploadService';
|
||||
|
||||
interface UploadResponse {
|
||||
fileUploadResult: UPLOAD_RESULT;
|
||||
|
@ -118,14 +120,18 @@ export default async function uploader(
|
|||
if (file.hasStaticThumbnail) {
|
||||
metadata.hasStaticThumbnail = true;
|
||||
}
|
||||
let pubMagicMetadata: FilePublicMagicMetadata;
|
||||
if (uploaderName) {
|
||||
metadata.uploaderName = uploaderName;
|
||||
pubMagicMetadata = await uploadService.constructPublicMagicMetadata(
|
||||
{ uploaderName }
|
||||
);
|
||||
}
|
||||
const fileWithMetadata = {
|
||||
const fileWithMetadata: FileWithMetadata = {
|
||||
localID,
|
||||
filedata: file.filedata,
|
||||
thumbnail: file.thumbnail,
|
||||
metadata,
|
||||
pubMagicMetadata,
|
||||
};
|
||||
|
||||
if (uploadCancelService.isUploadCancelationRequested()) {
|
||||
|
|
|
@ -20,6 +20,7 @@ export interface FilePublicMagicMetadataProps {
|
|||
editedTime?: number;
|
||||
editedName?: string;
|
||||
caption?: string;
|
||||
uploaderName?: string;
|
||||
}
|
||||
|
||||
export interface FilePublicMagicMetadata
|
||||
|
|
|
@ -21,7 +21,7 @@ export enum SUB_TYPE {
|
|||
}
|
||||
|
||||
export const NEW_FILE_MAGIC_METADATA: MagicMetadataCore = {
|
||||
version: 0,
|
||||
version: 1,
|
||||
data: {},
|
||||
header: null,
|
||||
count: 0,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { FILE_TYPE } from 'constants/file';
|
||||
import { Collection } from 'types/collection';
|
||||
import { fileAttribute } from 'types/file';
|
||||
import { fileAttribute, FilePublicMagicMetadata } from 'types/file';
|
||||
import { EncryptedMagicMetadataCore } from 'types/magicMetadata';
|
||||
|
||||
export interface DataStream {
|
||||
stream: ReadableStream<Uint8Array>;
|
||||
|
@ -27,7 +28,6 @@ export interface Metadata {
|
|||
hash?: string;
|
||||
imageHash?: string;
|
||||
videoHash?: string;
|
||||
uploaderName?: string;
|
||||
}
|
||||
|
||||
export interface Location {
|
||||
|
@ -114,6 +114,7 @@ export interface FileWithMetadata
|
|||
extends Omit<FileInMemory, 'hasStaticThumbnail'> {
|
||||
metadata: Metadata;
|
||||
localID: number;
|
||||
pubMagicMetadata: FilePublicMagicMetadata;
|
||||
}
|
||||
|
||||
export interface EncryptedFile {
|
||||
|
@ -124,6 +125,7 @@ export interface ProcessedFile {
|
|||
file: fileAttribute;
|
||||
thumbnail: fileAttribute;
|
||||
metadata: fileAttribute;
|
||||
pubMagicMetadata: EncryptedMagicMetadataCore;
|
||||
localID: number;
|
||||
}
|
||||
export interface BackupedFile extends Omit<ProcessedFile, 'localID'> {}
|
||||
|
|
|
@ -685,7 +685,7 @@ const englishConstants = {
|
|||
'Are you sure you want to disable public sharing?',
|
||||
FILE_DOWNLOAD: 'Allow downloads',
|
||||
LINK_PASSWORD_LOCK: 'Password lock',
|
||||
PUBLIC_COLLECT: 'Public collect',
|
||||
PUBLIC_COLLECT: 'Allow adding photos',
|
||||
LINK_DEVICE_LIMIT: 'Device limit',
|
||||
LINK_EXPIRY: 'Link expiry',
|
||||
LINK_EXPIRY_NEVER: 'Never',
|
||||
|
@ -698,17 +698,10 @@ const englishConstants = {
|
|||
</p>{' '}
|
||||
<p>
|
||||
Viewers can still take screenshots or save a copy of your photos
|
||||
using external tools'{' '}
|
||||
using external tools{' '}
|
||||
</p>
|
||||
</>
|
||||
),
|
||||
ENABLE_PUBLIC_COLLECT: 'Enable public collect',
|
||||
ENABLE_PUBLIC_COLLECT_MESSAGE: () => (
|
||||
<>
|
||||
<p>Are you sure that you want to enable public collect? </p>{' '}
|
||||
<p>Uploaded files will be counted towards your storage</p>
|
||||
</>
|
||||
),
|
||||
ABUSE_REPORT: 'Abuse report',
|
||||
ABUSE_REPORT_BUTTON_TEXT: 'Report abuse?',
|
||||
MALICIOUS_CONTENT: 'Contains malicious content',
|
||||
|
@ -890,6 +883,7 @@ const englishConstants = {
|
|||
</p>
|
||||
</>
|
||||
),
|
||||
ADD_X_PHOTOS: (x: number) => `Add ${x} ${x > 1 ? 'photos' : 'photo'}`,
|
||||
};
|
||||
|
||||
export default englishConstants;
|
||||
|
|
Loading…
Reference in a new issue