Merge branch 'master' into ml-search-beta
This commit is contained in:
commit
c52c8004f9
|
@ -86,7 +86,7 @@ export function AbuseReportForm({ show, close, url }: Iprops) {
|
|||
publicCollectionGalleryContent.setDialogMessage({
|
||||
title: constants.REPORT_SUBMIT_SUCCESS_TITLE,
|
||||
content: constants.REPORT_SUBMIT_SUCCESS_CONTENT,
|
||||
close: { text: constants.CLOSE },
|
||||
close: { text: constants.OK },
|
||||
});
|
||||
} catch (e) {
|
||||
setFieldError('signature', constants.REPORT_SUBMIT_FAILED);
|
||||
|
|
|
@ -348,7 +348,7 @@ export default function Gallery() {
|
|||
isLoadingBarRunning.current = true;
|
||||
};
|
||||
const finishLoading = () => {
|
||||
loadingBar.current?.complete();
|
||||
isLoadingBarRunning.current && loadingBar.current?.complete();
|
||||
isLoadingBarRunning.current = false;
|
||||
};
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import {
|
|||
getLocalPublicCollection,
|
||||
getLocalPublicFiles,
|
||||
getPublicCollection,
|
||||
getPublicCollectionUID,
|
||||
removePublicCollectionWithFiles,
|
||||
syncPublicFiles,
|
||||
} from 'services/publicCollectionService';
|
||||
|
@ -19,7 +20,7 @@ import {
|
|||
defaultPublicCollectionGalleryContext,
|
||||
PublicCollectionGalleryContext,
|
||||
} from 'utils/publicCollectionGallery';
|
||||
import { CustomError } from 'utils/error';
|
||||
import { CustomError, parseSharingErrorCodes } from 'utils/error';
|
||||
import Container from 'components/Container';
|
||||
import constants from 'utils/strings/constants';
|
||||
import EnteSpinner from 'components/EnteSpinner';
|
||||
|
@ -28,11 +29,18 @@ import CryptoWorker from 'utils/crypto';
|
|||
import { PAGES } from 'constants/pages';
|
||||
import router from 'next/router';
|
||||
|
||||
const Loader = () => (
|
||||
<Container>
|
||||
<EnteSpinner>
|
||||
<span className="sr-only">Loading...</span>
|
||||
</EnteSpinner>
|
||||
</Container>
|
||||
);
|
||||
export default function PublicCollectionGallery() {
|
||||
const token = useRef<string>(null);
|
||||
const collectionKey = useRef<string>(null);
|
||||
const url = useRef<string>(null);
|
||||
const [publicFiles, setPublicFiles] = useState<EnteFile[]>([]);
|
||||
const [publicFiles, setPublicFiles] = useState<EnteFile[]>(null);
|
||||
const [publicCollection, setPublicCollection] = useState<Collection>(null);
|
||||
const appContext = useContext(AppContext);
|
||||
const [abuseReportFormView, setAbuseReportFormView] = useState(false);
|
||||
|
@ -42,23 +50,22 @@ export default function PublicCollectionGallery() {
|
|||
const openReportForm = () => setAbuseReportFormView(true);
|
||||
const closeReportForm = () => setAbuseReportFormView(false);
|
||||
const loadingBar = useRef(null);
|
||||
const [isLoadingBarRunning, setIsLoadingBarRunning] = useState(false);
|
||||
const isLoadingBarRunning = useRef(false);
|
||||
|
||||
const openMessageDialog = () => setMessageDialogView(true);
|
||||
const closeMessageDialog = () => setMessageDialogView(false);
|
||||
|
||||
const startLoading = () => {
|
||||
!isLoadingBarRunning && loadingBar.current?.continuousStart();
|
||||
setIsLoadingBarRunning(true);
|
||||
const startLoadingBar = () => {
|
||||
!isLoadingBarRunning.current && loadingBar.current?.continuousStart();
|
||||
isLoadingBarRunning.current = true;
|
||||
};
|
||||
const finishLoading = () => {
|
||||
loadingBar.current?.complete();
|
||||
setIsLoadingBarRunning(false);
|
||||
const finishLoadingBar = () => {
|
||||
isLoadingBarRunning.current && loadingBar.current?.complete();
|
||||
isLoadingBarRunning.current = false;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
appContext.showNavBar(true);
|
||||
setLoading(false);
|
||||
const currentURL = new URL(window.location.href);
|
||||
if (currentURL.pathname !== PAGES.ROOT) {
|
||||
router.push(
|
||||
|
@ -75,6 +82,7 @@ export default function PublicCollectionGallery() {
|
|||
);
|
||||
}
|
||||
const main = async () => {
|
||||
try {
|
||||
const worker = await new CryptoWorker();
|
||||
url.current = window.location.href;
|
||||
const currentURL = new URL(url.current);
|
||||
|
@ -82,7 +90,6 @@ export default function PublicCollectionGallery() {
|
|||
const ck = currentURL.hash.slice(1);
|
||||
const dck = await worker.fromHex(ck);
|
||||
if (!t || !dck) {
|
||||
setLoading(false);
|
||||
return;
|
||||
}
|
||||
token.current = t;
|
||||
|
@ -93,12 +100,20 @@ export default function PublicCollectionGallery() {
|
|||
);
|
||||
if (localCollection) {
|
||||
setPublicCollection(localCollection);
|
||||
const collectionUID = getPublicCollectionUID(
|
||||
collectionKey.current,
|
||||
token.current
|
||||
);
|
||||
const localFiles = await getLocalPublicFiles(collectionUID);
|
||||
const localPublicFiles = sortFiles(
|
||||
mergeMetadata(await getLocalPublicFiles(localCollection))
|
||||
mergeMetadata(localFiles)
|
||||
);
|
||||
setPublicFiles(localPublicFiles);
|
||||
}
|
||||
syncWithRemote();
|
||||
await syncWithRemote();
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
main();
|
||||
}, []);
|
||||
|
@ -107,7 +122,7 @@ export default function PublicCollectionGallery() {
|
|||
|
||||
const syncWithRemote = async () => {
|
||||
try {
|
||||
startLoading();
|
||||
startLoadingBar();
|
||||
const collection = await getPublicCollection(
|
||||
token.current,
|
||||
collectionKey.current
|
||||
|
@ -116,29 +131,29 @@ export default function PublicCollectionGallery() {
|
|||
|
||||
await syncPublicFiles(token.current, collection, setPublicFiles);
|
||||
} catch (e) {
|
||||
if (e.message === CustomError.TOKEN_EXPIRED) {
|
||||
const parsedError = parseSharingErrorCodes(e);
|
||||
if (parsedError.message === CustomError.TOKEN_EXPIRED) {
|
||||
// share has been disabled
|
||||
// local cache should be cleared
|
||||
removePublicCollectionWithFiles(collectionKey.current);
|
||||
removePublicCollectionWithFiles(
|
||||
token.current,
|
||||
collectionKey.current
|
||||
);
|
||||
setPublicCollection(null);
|
||||
setPublicFiles([]);
|
||||
}
|
||||
} finally {
|
||||
finishLoading();
|
||||
finishLoadingBar();
|
||||
}
|
||||
};
|
||||
if (loading) {
|
||||
return (
|
||||
<Container>
|
||||
<EnteSpinner>
|
||||
<span className="sr-only">Loading...</span>
|
||||
</EnteSpinner>
|
||||
</Container>
|
||||
);
|
||||
|
||||
if (!publicFiles && loading) {
|
||||
return <Loader />;
|
||||
}
|
||||
if (!isLoadingBarRunning && !publicFiles) {
|
||||
if (!publicFiles?.length && !loading) {
|
||||
return <Container>{constants.NOT_FOUND}</Container>;
|
||||
}
|
||||
|
||||
return (
|
||||
<PublicCollectionGalleryContext.Provider
|
||||
value={{
|
||||
|
|
|
@ -23,12 +23,7 @@ import {
|
|||
CreatePublicAccessTokenRequest,
|
||||
PublicURL,
|
||||
} from 'types/collection';
|
||||
import {
|
||||
COLLECTION_SORT_BY,
|
||||
CollectionType,
|
||||
COLLECTION_SHARE_DEFAULT_DEVICE_LIMIT,
|
||||
COLLECTION_SHARE_DEFAULT_VALID_DURATION,
|
||||
} from 'constants/collection';
|
||||
import { COLLECTION_SORT_BY, CollectionType } from 'constants/collection';
|
||||
|
||||
const ENDPOINT = getEndpoint();
|
||||
const COLLECTION_TABLE = 'collections';
|
||||
|
@ -588,9 +583,6 @@ export const createShareableURL = async (collection: Collection) => {
|
|||
}
|
||||
const createPublicAccessTokenRequest: CreatePublicAccessTokenRequest = {
|
||||
collectionID: collection.id,
|
||||
validTill:
|
||||
Date.now() * 1000 + COLLECTION_SHARE_DEFAULT_VALID_DURATION,
|
||||
deviceLimit: COLLECTION_SHARE_DEFAULT_DEVICE_LIMIT,
|
||||
};
|
||||
const resp = await HTTPService.post(
|
||||
`${ENDPOINT}/collections/share-url`,
|
||||
|
|
|
@ -368,7 +368,8 @@ class MachineLearningService {
|
|||
let error = e;
|
||||
console.error('Error in ml sync, fileId: ', enteFile.id, error);
|
||||
if ('status' in error) {
|
||||
error = parseServerError(error).parsedError || error;
|
||||
const parsedMessage = parseServerError(error);
|
||||
error = parsedMessage ? new Error(parsedMessage) : error;
|
||||
}
|
||||
// TODO: throw errors not related to specific file
|
||||
// sync job run should stop after these errors
|
||||
|
|
|
@ -12,17 +12,18 @@ import {
|
|||
} from 'types/publicCollection';
|
||||
import CryptoWorker from 'utils/crypto';
|
||||
import { REPORT_REASON } from 'constants/publicCollection';
|
||||
import { CustomError, ServerErrorCodes } from 'utils/error';
|
||||
|
||||
const ENDPOINT = getEndpoint();
|
||||
const PUBLIC_COLLECTION_FILES_TABLE = 'public-collection-files';
|
||||
const PUBLIC_COLLECTIONS_TABLE = 'public-collections';
|
||||
|
||||
const getCollectionUID = (collection: Collection) => `${collection.key}`;
|
||||
const getCollectionSyncTimeUID = (collectionUID: string) =>
|
||||
export const getPublicCollectionUID = (collectionKey: string, token: string) =>
|
||||
`${collectionKey.slice(0, 8)}-${token.slice(0, 8)}`;
|
||||
|
||||
const getPublicCollectionSyncTimeUID = (collectionUID: string) =>
|
||||
`public-${collectionUID}-time`;
|
||||
|
||||
export const getLocalPublicFiles = async (collection: Collection) => {
|
||||
export const getLocalPublicFiles = async (collectionUID: string) => {
|
||||
const localSavedPublicCollectionFiles =
|
||||
(
|
||||
(await localForage.getItem<LocalSavedPublicCollectionFiles[]>(
|
||||
|
@ -30,8 +31,7 @@ export const getLocalPublicFiles = async (collection: Collection) => {
|
|||
)) || []
|
||||
).find(
|
||||
(localSavedPublicCollectionFiles) =>
|
||||
localSavedPublicCollectionFiles.collectionUID ===
|
||||
getCollectionUID(collection)
|
||||
localSavedPublicCollectionFiles.collectionUID === collectionUID
|
||||
) ||
|
||||
({
|
||||
collectionUID: null,
|
||||
|
@ -106,13 +106,17 @@ const dedupeCollectionFiles = (
|
|||
|
||||
const getPublicCollectionLastSyncTime = async (collectionUID: string) =>
|
||||
(await localForage.getItem<number>(
|
||||
getCollectionSyncTimeUID(collectionUID)
|
||||
getPublicCollectionSyncTimeUID(collectionUID)
|
||||
)) ?? 0;
|
||||
|
||||
const setPublicCollectionLastSyncTime = async (
|
||||
collectionUID: string,
|
||||
time: number
|
||||
) => await localForage.setItem(getCollectionSyncTimeUID(collectionUID), time);
|
||||
) =>
|
||||
await localForage.setItem(
|
||||
getPublicCollectionSyncTimeUID(collectionUID),
|
||||
time
|
||||
);
|
||||
|
||||
export const syncPublicFiles = async (
|
||||
token: string,
|
||||
|
@ -121,14 +125,15 @@ export const syncPublicFiles = async (
|
|||
) => {
|
||||
try {
|
||||
let files: EnteFile[] = [];
|
||||
const localFiles = await getLocalPublicFiles(collection);
|
||||
const collectionUID = getPublicCollectionUID(collection.key, token);
|
||||
const localFiles = await getLocalPublicFiles(collectionUID);
|
||||
files.push(...localFiles);
|
||||
try {
|
||||
if (!token) {
|
||||
return files;
|
||||
}
|
||||
const lastSyncTime = await getPublicCollectionLastSyncTime(
|
||||
getCollectionUID(collection)
|
||||
collectionUID
|
||||
);
|
||||
if (collection.updationTime === lastSyncTime) {
|
||||
return files;
|
||||
|
@ -160,12 +165,9 @@ export const syncPublicFiles = async (
|
|||
}
|
||||
files.push(file);
|
||||
}
|
||||
await savePublicCollectionFiles(
|
||||
getCollectionUID(collection),
|
||||
files
|
||||
);
|
||||
await savePublicCollectionFiles(collectionUID, files);
|
||||
await setPublicCollectionLastSyncTime(
|
||||
getCollectionUID(collection),
|
||||
collectionUID,
|
||||
collection.updationTime
|
||||
);
|
||||
setPublicFiles([...sortFiles(mergeMetadata(files))]);
|
||||
|
@ -175,7 +177,7 @@ export const syncPublicFiles = async (
|
|||
return [...sortFiles(mergeMetadata(files))];
|
||||
} catch (e) {
|
||||
logError(e, 'failed to get local or sync shared collection files');
|
||||
return [];
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -260,20 +262,12 @@ export const getPublicCollection = async (
|
|||
};
|
||||
await savePublicCollection(collection);
|
||||
return collection;
|
||||
} catch (error) {
|
||||
logError(error, 'failed to get public collection', {
|
||||
} catch (e) {
|
||||
logError(e, 'failed to get public collection', {
|
||||
collectionKey,
|
||||
token,
|
||||
});
|
||||
if ('status' in error) {
|
||||
const errorCode = error.status.toString();
|
||||
if (
|
||||
errorCode === ServerErrorCodes.SESSION_EXPIRED ||
|
||||
errorCode === ServerErrorCodes.TOKEN_EXPIRED
|
||||
) {
|
||||
throw Error(CustomError.TOKEN_EXPIRED);
|
||||
}
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -317,21 +311,17 @@ export const reportAbuse = async (
|
|||
};
|
||||
|
||||
export const removePublicCollectionWithFiles = async (
|
||||
token: string,
|
||||
collectionKey: string
|
||||
) => {
|
||||
const collectionUID = getPublicCollectionUID(collectionKey, token);
|
||||
const publicCollections =
|
||||
(await localForage.getItem<Collection[]>(PUBLIC_COLLECTIONS_TABLE)) ??
|
||||
(await localForage.getItem<Collection[]>(PUBLIC_COLLECTIONS_TABLE)) ||
|
||||
[];
|
||||
const collectionToRemove = publicCollections.find(
|
||||
(collection) => (collection.key = collectionKey)
|
||||
);
|
||||
if (!collectionToRemove) {
|
||||
return;
|
||||
}
|
||||
await localForage.setItem(
|
||||
PUBLIC_COLLECTIONS_TABLE,
|
||||
publicCollections.filter(
|
||||
(collection) => collection.id !== collectionToRemove.id
|
||||
(collection) => collection.key !== collectionKey
|
||||
)
|
||||
);
|
||||
|
||||
|
@ -342,9 +332,7 @@ export const removePublicCollectionWithFiles = async (
|
|||
await localForage.setItem(
|
||||
PUBLIC_COLLECTION_FILES_TABLE,
|
||||
publicCollectionFiles.filter(
|
||||
(collectionFiles) =>
|
||||
collectionFiles.collectionUID ===
|
||||
getCollectionUID(collectionToRemove)
|
||||
(collectionFiles) => collectionFiles.collectionUID !== collectionUID
|
||||
)
|
||||
);
|
||||
};
|
||||
|
|
|
@ -28,8 +28,8 @@ export interface PublicURL {
|
|||
|
||||
export interface CreatePublicAccessTokenRequest {
|
||||
collectionID: number;
|
||||
validTill: number;
|
||||
deviceLimit: number;
|
||||
validTill?: number;
|
||||
deviceLimit?: number;
|
||||
}
|
||||
|
||||
export interface EncryptedFileKey {
|
||||
|
|
|
@ -8,6 +8,10 @@ export const ServerErrorCodes = {
|
|||
STORAGE_LIMIT_EXCEEDED: '426',
|
||||
FILE_TOO_LARGE: '413',
|
||||
TOKEN_EXPIRED: '410',
|
||||
TOO_MANY_REQUEST: '429',
|
||||
BAD_REQUEST: '400',
|
||||
PAYMENT_REQUIRED: '402',
|
||||
NOT_FOUND: '404',
|
||||
};
|
||||
|
||||
export enum CustomError {
|
||||
|
@ -32,9 +36,35 @@ export enum CustomError {
|
|||
REQUEST_CANCELLED = 'request canceled',
|
||||
NETWORK_ERROR = 'Network Error',
|
||||
TOKEN_EXPIRED = 'token expired',
|
||||
BAD_REQUEST = 'bad request',
|
||||
SUBSCRIPTION_NEEDED = 'subscription not present',
|
||||
NOT_FOUND = 'not found ',
|
||||
}
|
||||
|
||||
export function parseServerError(error: AxiosResponse) {
|
||||
export function parseServerError(error: AxiosResponse): string {
|
||||
let parsedMessage: string = null;
|
||||
const errorCode = error.status.toString();
|
||||
switch (errorCode) {
|
||||
case ServerErrorCodes.NO_ACTIVE_SUBSCRIPTION:
|
||||
parsedMessage = CustomError.SUBSCRIPTION_EXPIRED;
|
||||
break;
|
||||
case ServerErrorCodes.STORAGE_LIMIT_EXCEEDED:
|
||||
parsedMessage = CustomError.STORAGE_QUOTA_EXCEEDED;
|
||||
break;
|
||||
case ServerErrorCodes.SESSION_EXPIRED:
|
||||
parsedMessage = CustomError.SESSION_EXPIRED_MESSAGE;
|
||||
break;
|
||||
case ServerErrorCodes.FILE_TOO_LARGE:
|
||||
parsedMessage = CustomError.FILE_TOO_LARGE;
|
||||
break;
|
||||
default:
|
||||
parsedMessage = `${constants.UNKNOWN_ERROR} statusCode:${errorCode}`;
|
||||
}
|
||||
|
||||
return parsedMessage;
|
||||
}
|
||||
|
||||
function parseUploadErrorCodes(error) {
|
||||
let parsedMessage = null;
|
||||
if (error?.status) {
|
||||
const errorCode = error.status.toString();
|
||||
|
@ -54,19 +84,15 @@ export function parseServerError(error: AxiosResponse) {
|
|||
default:
|
||||
parsedMessage = `${constants.UNKNOWN_ERROR} statusCode:${errorCode}`;
|
||||
}
|
||||
} else {
|
||||
parsedMessage = error.message;
|
||||
}
|
||||
return {
|
||||
parsedError: new Error(parsedMessage),
|
||||
};
|
||||
return new Error(parsedMessage);
|
||||
}
|
||||
|
||||
export function handleUploadError(error: AxiosResponse | Error): Error {
|
||||
let parsedError: Error = null;
|
||||
if ('status' in error) {
|
||||
parsedError = parseServerError(error).parsedError;
|
||||
} else {
|
||||
parsedError = error;
|
||||
}
|
||||
export function handleUploadError(error): Error {
|
||||
const parsedError = parseUploadErrorCodes(error);
|
||||
|
||||
// breaking errors
|
||||
switch (parsedError.message) {
|
||||
case CustomError.SUBSCRIPTION_EXPIRED:
|
||||
|
@ -101,25 +127,49 @@ export function errorWithContext(originalError: Error, context: string) {
|
|||
originalError.stack;
|
||||
return errorWithContext;
|
||||
}
|
||||
export const parseSharingErrorCodes = (error) => {
|
||||
let parsedMessage = null;
|
||||
if (error?.status) {
|
||||
const errorCode = error.status.toString();
|
||||
switch (errorCode) {
|
||||
case ServerErrorCodes.BAD_REQUEST:
|
||||
parsedMessage = CustomError.BAD_REQUEST;
|
||||
break;
|
||||
case ServerErrorCodes.PAYMENT_REQUIRED:
|
||||
parsedMessage = CustomError.SUBSCRIPTION_NEEDED;
|
||||
break;
|
||||
case ServerErrorCodes.NOT_FOUND:
|
||||
parsedMessage = CustomError.NOT_FOUND;
|
||||
break;
|
||||
case ServerErrorCodes.SESSION_EXPIRED:
|
||||
case ServerErrorCodes.TOKEN_EXPIRED:
|
||||
case ServerErrorCodes.TOO_MANY_REQUEST:
|
||||
parsedMessage = CustomError.TOKEN_EXPIRED;
|
||||
break;
|
||||
default:
|
||||
parsedMessage = `${constants.UNKNOWN_ERROR} statusCode:${errorCode}`;
|
||||
}
|
||||
} else {
|
||||
parsedMessage = error.message;
|
||||
}
|
||||
return new Error(parsedMessage);
|
||||
};
|
||||
|
||||
export const handleSharingErrors = (e) => {
|
||||
let errorMessage = null;
|
||||
if ('status' in e) {
|
||||
switch (e?.status) {
|
||||
case 400:
|
||||
export const handleSharingErrors = (error) => {
|
||||
const parsedError = parseSharingErrorCodes(error);
|
||||
let errorMessage = '';
|
||||
switch (parsedError.message) {
|
||||
case CustomError.BAD_REQUEST:
|
||||
errorMessage = constants.SHARING_BAD_REQUEST_ERROR;
|
||||
break;
|
||||
case 402:
|
||||
case CustomError.SUBSCRIPTION_NEEDED:
|
||||
errorMessage = constants.SHARING_DISABLED_FOR_FREE_ACCOUNTS;
|
||||
break;
|
||||
case 404:
|
||||
case CustomError.NOT_FOUND:
|
||||
errorMessage = constants.USER_DOES_NOT_EXIST;
|
||||
break;
|
||||
default:
|
||||
errorMessage = `${constants.UNKNOWN_ERROR} statusCode:${e.status}`;
|
||||
}
|
||||
} else {
|
||||
errorMessage = e.message;
|
||||
errorMessage = parsedError.message;
|
||||
}
|
||||
return errorMessage;
|
||||
};
|
||||
|
|
|
@ -630,10 +630,10 @@ const englishConstants = {
|
|||
OPEN_PLAN_SELECTOR_MODAL_FAILED: 'failed to open plans',
|
||||
COMMENT: 'comment',
|
||||
ABUSE_REPORT_DESCRIPTION:
|
||||
'fill out the following form to submit the abuse report. Refer the dmca section for more detail for privacy policy of submitting a report ',
|
||||
'Note: Submitting this report will notify the album owner.',
|
||||
OTHER_REASON_REQUIRES_COMMENTS:
|
||||
'reason = other, require a mandatory comment ',
|
||||
REPORT_SUBMIT_SUCCESS_CONTENT: 'thank you, your report have been submitted',
|
||||
REPORT_SUBMIT_SUCCESS_CONTENT: 'your report has been submitted',
|
||||
REPORT_SUBMIT_SUCCESS_TITLE: 'report sent',
|
||||
REPORT_SUBMIT_FAILED: 'failed to sent report, try again',
|
||||
INSTALL: 'install',
|
||||
|
|
Loading…
Reference in a new issue