diff --git a/src/components/pages/sharedAlbum/AbuseReportForm.tsx b/src/components/pages/sharedAlbum/AbuseReportForm.tsx
index e06008512..262b588a7 100644
--- a/src/components/pages/sharedAlbum/AbuseReportForm.tsx
+++ b/src/components/pages/sharedAlbum/AbuseReportForm.tsx
@@ -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);
diff --git a/src/pages/gallery/index.tsx b/src/pages/gallery/index.tsx
index 7fc0b3552..18a3d2594 100644
--- a/src/pages/gallery/index.tsx
+++ b/src/pages/gallery/index.tsx
@@ -348,7 +348,7 @@ export default function Gallery() {
isLoadingBarRunning.current = true;
};
const finishLoading = () => {
- loadingBar.current?.complete();
+ isLoadingBarRunning.current && loadingBar.current?.complete();
isLoadingBarRunning.current = false;
};
diff --git a/src/pages/shared-albums/index.tsx b/src/pages/shared-albums/index.tsx
index f8cc6b335..11bf8f730 100644
--- a/src/pages/shared-albums/index.tsx
+++ b/src/pages/shared-albums/index.tsx
@@ -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 = () => (
+
+
+ Loading...
+
+
+);
export default function PublicCollectionGallery() {
const token = useRef(null);
const collectionKey = useRef(null);
const url = useRef(null);
- const [publicFiles, setPublicFiles] = useState([]);
+ const [publicFiles, setPublicFiles] = useState(null);
const [publicCollection, setPublicCollection] = useState(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,30 +82,38 @@ export default function PublicCollectionGallery() {
);
}
const main = async () => {
- const worker = await new CryptoWorker();
- url.current = window.location.href;
- const currentURL = new URL(url.current);
- const t = currentURL.searchParams.get('t');
- const ck = currentURL.hash.slice(1);
- const dck = await worker.fromHex(ck);
- if (!t || !dck) {
- setLoading(false);
- return;
- }
- token.current = t;
- collectionKey.current = dck;
- url.current = window.location.href;
- const localCollection = await getLocalPublicCollection(
- collectionKey.current
- );
- if (localCollection) {
- setPublicCollection(localCollection);
- const localPublicFiles = sortFiles(
- mergeMetadata(await getLocalPublicFiles(localCollection))
+ try {
+ const worker = await new CryptoWorker();
+ url.current = window.location.href;
+ const currentURL = new URL(url.current);
+ const t = currentURL.searchParams.get('t');
+ const ck = currentURL.hash.slice(1);
+ const dck = await worker.fromHex(ck);
+ if (!t || !dck) {
+ return;
+ }
+ token.current = t;
+ collectionKey.current = dck;
+ url.current = window.location.href;
+ const localCollection = await getLocalPublicCollection(
+ collectionKey.current
);
- setPublicFiles(localPublicFiles);
+ if (localCollection) {
+ setPublicCollection(localCollection);
+ const collectionUID = getPublicCollectionUID(
+ collectionKey.current,
+ token.current
+ );
+ const localFiles = await getLocalPublicFiles(collectionUID);
+ const localPublicFiles = sortFiles(
+ mergeMetadata(localFiles)
+ );
+ setPublicFiles(localPublicFiles);
+ }
+ await syncWithRemote();
+ } finally {
+ setLoading(false);
}
- syncWithRemote();
};
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 (
-
-
- Loading...
-
-
- );
+
+ if (!publicFiles && loading) {
+ return ;
}
- if (!isLoadingBarRunning && !publicFiles) {
+ if (!publicFiles?.length && !loading) {
return {constants.NOT_FOUND};
}
+
return (
{
}
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`,
diff --git a/src/services/machineLearning/machineLearningService.ts b/src/services/machineLearning/machineLearningService.ts
index 68b72bfab..6505efbee 100644
--- a/src/services/machineLearning/machineLearningService.ts
+++ b/src/services/machineLearning/machineLearningService.ts
@@ -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
diff --git a/src/services/publicCollectionService.ts b/src/services/publicCollectionService.ts
index 33164c7bc..faf14b349 100644
--- a/src/services/publicCollectionService.ts
+++ b/src/services/publicCollectionService.ts
@@ -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(
@@ -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(
- 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(PUBLIC_COLLECTIONS_TABLE)) ??
+ (await localForage.getItem(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
)
);
};
diff --git a/src/types/collection/index.ts b/src/types/collection/index.ts
index 0becd3778..83dffdda5 100644
--- a/src/types/collection/index.ts
+++ b/src/types/collection/index.ts
@@ -28,8 +28,8 @@ export interface PublicURL {
export interface CreatePublicAccessTokenRequest {
collectionID: number;
- validTill: number;
- deviceLimit: number;
+ validTill?: number;
+ deviceLimit?: number;
}
export interface EncryptedFileKey {
diff --git a/src/utils/error/index.ts b/src/utils/error/index.ts
index 85a417b50..85ff7ac1f 100644
--- a/src/utils/error/index.ts
+++ b/src/utils/error/index.ts
@@ -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 handleSharingErrors = (e) => {
- let errorMessage = null;
- if ('status' in e) {
- switch (e?.status) {
- case 400:
- errorMessage = constants.SHARING_BAD_REQUEST_ERROR;
+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 402:
- errorMessage = constants.SHARING_DISABLED_FOR_FREE_ACCOUNTS;
+ case ServerErrorCodes.PAYMENT_REQUIRED:
+ parsedMessage = CustomError.SUBSCRIPTION_NEEDED;
break;
- case 404:
- errorMessage = constants.USER_DOES_NOT_EXIST;
+ 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:
- errorMessage = `${constants.UNKNOWN_ERROR} statusCode:${e.status}`;
+ parsedMessage = `${constants.UNKNOWN_ERROR} statusCode:${errorCode}`;
}
} else {
- errorMessage = e.message;
+ parsedMessage = error.message;
+ }
+ return new Error(parsedMessage);
+};
+
+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 CustomError.SUBSCRIPTION_NEEDED:
+ errorMessage = constants.SHARING_DISABLED_FOR_FREE_ACCOUNTS;
+ break;
+ case CustomError.NOT_FOUND:
+ errorMessage = constants.USER_DOES_NOT_EXIST;
+ break;
+ default:
+ errorMessage = parsedError.message;
}
return errorMessage;
};
diff --git a/src/utils/strings/englishConstants.tsx b/src/utils/strings/englishConstants.tsx
index da3911e39..fe07e736a 100644
--- a/src/utils/strings/englishConstants.tsx
+++ b/src/utils/strings/englishConstants.tsx
@@ -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',