[web] Public albums internal code improvements - Part 2 (#6430)
This commit is contained in:
@@ -68,7 +68,6 @@ import {
|
||||
} from "ente-new/photos/services/collection";
|
||||
import type { CollectionSummary } from "ente-new/photos/services/collection-summary";
|
||||
import { usePhotosAppContext } from "ente-new/photos/types/context";
|
||||
import { CustomError, parseSharingErrorCodes } from "ente-shared/error";
|
||||
import { wait } from "ente-utils/promise";
|
||||
import { useFormik } from "formik";
|
||||
import { t } from "i18next";
|
||||
@@ -300,25 +299,6 @@ const SharingDetails: React.FC<SharingDetailsProps> = ({
|
||||
);
|
||||
};
|
||||
|
||||
const handleSharingErrors = (error) => {
|
||||
const parsedError = parseSharingErrorCodes(error);
|
||||
let errorMessage = "";
|
||||
switch (parsedError.message) {
|
||||
case CustomError.BAD_REQUEST:
|
||||
errorMessage = t("sharing_album_not_allowed");
|
||||
break;
|
||||
case CustomError.SUBSCRIPTION_NEEDED:
|
||||
errorMessage = t("sharing_disabled_for_free_accounts");
|
||||
break;
|
||||
case CustomError.NOT_FOUND:
|
||||
errorMessage = t("sharing_user_does_not_exist");
|
||||
break;
|
||||
default:
|
||||
errorMessage = `${t("generic_error_retry")} ${parsedError.message}`;
|
||||
}
|
||||
return errorMessage;
|
||||
};
|
||||
|
||||
type EmailShareProps = {
|
||||
onRootClose: () => void;
|
||||
wrap: (f: () => Promise<void>) => () => void;
|
||||
@@ -956,51 +936,55 @@ const ManageParticipant: React.FC<ManageParticipantProps> = ({
|
||||
onClose();
|
||||
};
|
||||
|
||||
const handleRoleChange = (role: string) => () => {
|
||||
if (role !== selectedParticipant.role) {
|
||||
changeRolePermission(selectedParticipant.email, role);
|
||||
}
|
||||
};
|
||||
const confirmChangeRolePermission = useCallback(
|
||||
(
|
||||
selectedEmail: string,
|
||||
newRole: CollectionNewParticipantRole,
|
||||
action: () => Promise<void>,
|
||||
) => {
|
||||
let message: React.ReactNode;
|
||||
let buttonText: string;
|
||||
|
||||
const updateCollectionRole = async (selectedEmail, newRole) => {
|
||||
try {
|
||||
await shareCollection(collection, selectedEmail, newRole);
|
||||
selectedParticipant.role = newRole;
|
||||
await onRemotePull({ silent: true });
|
||||
} catch (e) {
|
||||
log.error(handleSharingErrors(e), e);
|
||||
}
|
||||
};
|
||||
if (newRole == "VIEWER") {
|
||||
message = (
|
||||
<Trans
|
||||
i18nKey="change_permission_to_viewer"
|
||||
values={{ selectedEmail }}
|
||||
/>
|
||||
);
|
||||
|
||||
const changeRolePermission = (selectedEmail, newRole) => {
|
||||
let contentText;
|
||||
let buttonText;
|
||||
buttonText = t("confirm_convert_to_viewer");
|
||||
} else if (newRole == "COLLABORATOR") {
|
||||
message = t("change_permission_to_collaborator", {
|
||||
selectedEmail,
|
||||
});
|
||||
buttonText = t("confirm_convert_to_collaborator");
|
||||
}
|
||||
|
||||
if (newRole == "VIEWER") {
|
||||
contentText = (
|
||||
<Trans
|
||||
i18nKey="change_permission_to_viewer"
|
||||
values={{ selectedEmail }}
|
||||
/>
|
||||
);
|
||||
|
||||
buttonText = t("confirm_convert_to_viewer");
|
||||
} else if (newRole == "COLLABORATOR") {
|
||||
contentText = t("change_permission_to_collaborator", {
|
||||
selectedEmail,
|
||||
showMiniDialog({
|
||||
title: t("change_permission_title"),
|
||||
message: message,
|
||||
continue: { text: buttonText, color: "critical", action },
|
||||
});
|
||||
buttonText = t("confirm_convert_to_collaborator");
|
||||
}
|
||||
},
|
||||
[showMiniDialog],
|
||||
);
|
||||
|
||||
showMiniDialog({
|
||||
title: t("change_permission_title"),
|
||||
message: contentText,
|
||||
continue: {
|
||||
text: buttonText,
|
||||
color: "critical",
|
||||
action: () => updateCollectionRole(selectedEmail, newRole),
|
||||
},
|
||||
});
|
||||
const updateCollectionRole = async (
|
||||
selectedEmail: string,
|
||||
newRole: CollectionNewParticipantRole,
|
||||
) => {
|
||||
await shareCollection(collection, selectedEmail, newRole);
|
||||
selectedParticipant.role = newRole;
|
||||
await onRemotePull({ silent: true });
|
||||
};
|
||||
|
||||
const createOnRoleChange = (role: CollectionNewParticipantRole) => () => {
|
||||
if (role == selectedParticipant.role) return;
|
||||
const { email } = selectedParticipant;
|
||||
confirmChangeRolePermission(email, role, () =>
|
||||
updateCollectionRole(email, role),
|
||||
);
|
||||
};
|
||||
|
||||
const removeParticipant = () => {
|
||||
@@ -1044,7 +1028,7 @@ const ManageParticipant: React.FC<ManageParticipantProps> = ({
|
||||
<RowButtonGroup>
|
||||
<RowButton
|
||||
fontWeight="regular"
|
||||
onClick={handleRoleChange("COLLABORATOR")}
|
||||
onClick={createOnRoleChange("COLLABORATOR")}
|
||||
label={"Collaborator"}
|
||||
startIcon={<ModeEditIcon />}
|
||||
endIcon={
|
||||
@@ -1057,7 +1041,7 @@ const ManageParticipant: React.FC<ManageParticipantProps> = ({
|
||||
|
||||
<RowButton
|
||||
fontWeight="regular"
|
||||
onClick={handleRoleChange("VIEWER")}
|
||||
onClick={createOnRoleChange("VIEWER")}
|
||||
label={"Viewer"}
|
||||
startIcon={<PhotoIcon />}
|
||||
endIcon={
|
||||
|
||||
@@ -51,8 +51,12 @@ import { sortFiles } from "ente-gallery/utils/file";
|
||||
import type { Collection } from "ente-media/collection";
|
||||
import { type EnteFile } from "ente-media/file";
|
||||
import {
|
||||
removePublicCollectionAccessTokenJWT,
|
||||
savedLastPublicCollectionReferralCode,
|
||||
savedPublicCollectionAccessTokenJWT,
|
||||
savedPublicCollectionByKey,
|
||||
savedPublicCollectionFiles,
|
||||
savePublicCollectionAccessTokenJWT,
|
||||
} from "ente-new/albums/services/public-albums-fdb";
|
||||
import { verifyPublicAlbumPassword } from "ente-new/albums/services/public-collection";
|
||||
import {
|
||||
@@ -68,13 +72,10 @@ import { useRouter } from "next/router";
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||
import { type FileWithPath } from "react-dropzone";
|
||||
import {
|
||||
getLocalPublicCollection,
|
||||
getLocalPublicCollectionPassword,
|
||||
getPublicCollection,
|
||||
getPublicCollectionUID,
|
||||
removePublicCollectionWithFiles,
|
||||
removePublicFiles,
|
||||
savePublicCollectionPassword,
|
||||
syncPublicFiles,
|
||||
} from "services/publicCollectionService";
|
||||
import { uploadManager } from "services/upload-manager";
|
||||
@@ -216,7 +217,7 @@ export default function PublicCollectionGallery() {
|
||||
}
|
||||
collectionKey.current = ck;
|
||||
url.current = window.location.href;
|
||||
const localCollection = await getLocalPublicCollection(
|
||||
const localCollection = await savedPublicCollectionByKey(
|
||||
collectionKey.current,
|
||||
);
|
||||
const accessToken = t;
|
||||
@@ -230,13 +231,12 @@ export default function PublicCollectionGallery() {
|
||||
const isPasswordProtected =
|
||||
localCollection?.publicURLs?.[0]?.passwordEnabled;
|
||||
setIsPasswordProtected(isPasswordProtected);
|
||||
const collectionUID = getPublicCollectionUID(accessToken);
|
||||
const localFiles =
|
||||
await savedPublicCollectionFiles(accessToken);
|
||||
const localPublicFiles = sortFiles(localFiles, sortAsc);
|
||||
setPublicFiles(localPublicFiles);
|
||||
accessTokenJWT =
|
||||
await getLocalPublicCollectionPassword(collectionUID);
|
||||
await savedPublicCollectionAccessTokenJWT(accessToken);
|
||||
}
|
||||
credentials.current = { accessToken, accessTokenJWT };
|
||||
downloadManager.setPublicAlbumsCredentials(credentials.current);
|
||||
@@ -316,7 +316,7 @@ export default function PublicCollectionGallery() {
|
||||
if (!isPasswordProtected && credentials.current.accessTokenJWT) {
|
||||
credentials.current.accessTokenJWT = undefined;
|
||||
downloadManager.setPublicAlbumsCredentials(credentials.current);
|
||||
savePublicCollectionPassword(collectionUID, null);
|
||||
removePublicCollectionAccessTokenJWT(collectionUID);
|
||||
}
|
||||
|
||||
if (
|
||||
@@ -395,7 +395,10 @@ export default function PublicCollectionGallery() {
|
||||
const collectionUID = getPublicCollectionUID(
|
||||
credentials.current.accessToken,
|
||||
);
|
||||
await savePublicCollectionPassword(collectionUID, accessTokenJWT);
|
||||
await savePublicCollectionAccessTokenJWT(
|
||||
collectionUID,
|
||||
accessTokenJWT,
|
||||
);
|
||||
} catch (e) {
|
||||
log.error("Failed to verifyLinkPassword", e);
|
||||
if (isHTTP401Error(e)) {
|
||||
|
||||
@@ -9,97 +9,29 @@ import type {
|
||||
import type { EnteFile, RemoteEnteFile } from "ente-media/file";
|
||||
import { decryptRemoteFile } from "ente-media/file";
|
||||
import {
|
||||
removePublicCollectionAccessTokenJWT,
|
||||
removePublicCollectionByKey,
|
||||
removePublicCollectionFiles,
|
||||
removePublicCollectionLastSyncTime,
|
||||
savedPublicCollectionFiles,
|
||||
savedPublicCollections,
|
||||
savedPublicCollectionLastSyncTime,
|
||||
saveLastPublicCollectionReferralCode,
|
||||
savePublicCollection,
|
||||
savePublicCollectionFiles,
|
||||
savePublicCollectionLastSyncTime,
|
||||
} from "ente-new/albums/services/public-albums-fdb";
|
||||
import { CustomError, parseSharingErrorCodes } from "ente-shared/error";
|
||||
import HTTPService from "ente-shared/network/HTTPService";
|
||||
import localForage from "ente-shared/storage/localForage";
|
||||
|
||||
const PUBLIC_COLLECTION_FILES_TABLE = "public-collection-files";
|
||||
const PUBLIC_COLLECTIONS_TABLE = "public-collections";
|
||||
|
||||
// Fix this once we can trust the types.
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-template-expression
|
||||
export const getPublicCollectionUID = (token: string) => `${token}`;
|
||||
|
||||
const getPublicCollectionLastSyncTimeKey = (collectionUID: string) =>
|
||||
`public-${collectionUID}-time`;
|
||||
|
||||
const getPublicCollectionPasswordKey = (collectionUID: string) =>
|
||||
`public-${collectionUID}-passkey`;
|
||||
|
||||
export interface LocalSavedPublicCollectionFiles {
|
||||
collectionUID: string;
|
||||
files: EnteFile[];
|
||||
}
|
||||
|
||||
export const getLocalPublicCollectionPassword = async (
|
||||
collectionUID: string,
|
||||
): Promise<string> => {
|
||||
return (
|
||||
(await localForage.getItem<string>(
|
||||
getPublicCollectionPasswordKey(collectionUID),
|
||||
)) || ""
|
||||
);
|
||||
};
|
||||
|
||||
export const savePublicCollectionPassword = async (
|
||||
collectionUID: string,
|
||||
passToken: string,
|
||||
): Promise<string> => {
|
||||
return await localForage.setItem<string>(
|
||||
getPublicCollectionPasswordKey(collectionUID),
|
||||
passToken,
|
||||
);
|
||||
};
|
||||
|
||||
export const getLocalPublicCollection = async (collectionKey: string) => {
|
||||
const localCollections = await savedPublicCollections();
|
||||
const publicCollection =
|
||||
localCollections.find(
|
||||
(localSavedPublicCollection) =>
|
||||
localSavedPublicCollection.key === collectionKey,
|
||||
) || null;
|
||||
return publicCollection;
|
||||
};
|
||||
|
||||
export const savePublicCollection = async (collection: Collection) => {
|
||||
const publicCollections = await savedPublicCollections();
|
||||
await localForage.setItem(
|
||||
PUBLIC_COLLECTIONS_TABLE,
|
||||
dedupeCollections([collection, ...publicCollections]),
|
||||
);
|
||||
};
|
||||
|
||||
const dedupeCollections = (collections: Collection[]) => {
|
||||
const keySet = new Set([]);
|
||||
return collections.filter((collection) => {
|
||||
if (!keySet.has(collection.key)) {
|
||||
keySet.add(collection.key);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const getPublicCollectionLastSyncTime = async (collectionUID: string) =>
|
||||
(await localForage.getItem<number>(
|
||||
getPublicCollectionLastSyncTimeKey(collectionUID),
|
||||
)) ?? 0;
|
||||
|
||||
const savePublicCollectionLastSyncTime = async (
|
||||
collectionUID: string,
|
||||
time: number,
|
||||
) =>
|
||||
await localForage.setItem(
|
||||
getPublicCollectionLastSyncTimeKey(collectionUID),
|
||||
time,
|
||||
);
|
||||
|
||||
export const syncPublicFiles = async (
|
||||
token: string,
|
||||
passwordToken: string,
|
||||
@@ -118,7 +50,7 @@ export const syncPublicFiles = async (
|
||||
return sortFiles(files, sortAsc);
|
||||
}
|
||||
const lastSyncTime =
|
||||
await getPublicCollectionLastSyncTime(collectionUID);
|
||||
(await savedPublicCollectionLastSyncTime(collectionUID)) ?? 0;
|
||||
if (collection.updationTime === lastSyncTime) {
|
||||
return sortFiles(files, sortAsc);
|
||||
}
|
||||
@@ -306,31 +238,12 @@ export const removePublicCollectionWithFiles = async (
|
||||
collectionUID: string,
|
||||
collectionKey: string,
|
||||
) => {
|
||||
const publicCollections = await savedPublicCollections();
|
||||
await localForage.setItem(
|
||||
PUBLIC_COLLECTIONS_TABLE,
|
||||
publicCollections.filter(
|
||||
(collection) => collection.key !== collectionKey,
|
||||
),
|
||||
);
|
||||
await removePublicCollectionByKey(collectionKey);
|
||||
await removePublicFiles(collectionUID);
|
||||
};
|
||||
|
||||
export const removePublicFiles = async (collectionUID: string) => {
|
||||
await localForage.removeItem(getPublicCollectionPasswordKey(collectionUID));
|
||||
await localForage.removeItem(
|
||||
getPublicCollectionLastSyncTimeKey(collectionUID),
|
||||
);
|
||||
|
||||
const publicCollectionFiles =
|
||||
(await localForage.getItem<LocalSavedPublicCollectionFiles[]>(
|
||||
PUBLIC_COLLECTION_FILES_TABLE,
|
||||
)) ?? [];
|
||||
await localForage.setItem(
|
||||
PUBLIC_COLLECTION_FILES_TABLE,
|
||||
publicCollectionFiles.filter(
|
||||
(collectionFiles) =>
|
||||
collectionFiles.collectionUID !== collectionUID,
|
||||
),
|
||||
);
|
||||
await removePublicCollectionAccessTokenJWT(collectionUID);
|
||||
await removePublicCollectionLastSyncTime(collectionUID);
|
||||
await removePublicCollectionFiles(collectionUID);
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
import {
|
||||
LocalCollections,
|
||||
LocalEnteFiles,
|
||||
LocalTimestamp,
|
||||
transformFilesIfNeeded,
|
||||
} from "ente-gallery/services/files-db";
|
||||
import { type Collection } from "ente-media/collection";
|
||||
@@ -18,7 +19,7 @@ import { z } from "zod/v4";
|
||||
*
|
||||
* Use {@link savePublicCollections} to update the database.
|
||||
*/
|
||||
export const savedPublicCollections = async (): Promise<Collection[]> =>
|
||||
const savedPublicCollections = async (): Promise<Collection[]> =>
|
||||
// TODO:
|
||||
//
|
||||
// See: [Note: strict mode migration]
|
||||
@@ -34,10 +35,57 @@ export const savedPublicCollections = async (): Promise<Collection[]> =>
|
||||
*
|
||||
* This is the setter corresponding to {@link savedPublicCollections}.
|
||||
*/
|
||||
export const savePublicCollections = (collections: Collection[]) =>
|
||||
const savePublicCollections = (collections: Collection[]) =>
|
||||
localForage.setItem("public-collections", collections);
|
||||
|
||||
const LocalReferralCode = z.string().nullish().transform(nullToUndefined);
|
||||
/**
|
||||
* Return the saved public collection with the given {@link key} if present in
|
||||
* our local database.
|
||||
*
|
||||
* Use {@link savePublicCollection} to save collections in our local database.
|
||||
*
|
||||
* @param key The collection key that can be used to identify the public album
|
||||
* we want from amongst all the locally saved public albums.
|
||||
*/
|
||||
export const savedPublicCollectionByKey = async (
|
||||
collectionKey: string,
|
||||
): Promise<Collection | undefined> =>
|
||||
savedPublicCollections().then((cs) =>
|
||||
cs.find((c) => c.key == collectionKey),
|
||||
);
|
||||
|
||||
/**
|
||||
* Save a public collection to our local database.
|
||||
*
|
||||
* The collection can later be retrieved using {@link savedPublicCollection}.
|
||||
* The collection can be removed using {@link removePublicCollection}.
|
||||
*/
|
||||
export const savePublicCollection = async (collection: Collection) => {
|
||||
const collections = await savedPublicCollections();
|
||||
await savePublicCollections([
|
||||
collection,
|
||||
...collections.filter((c) => c.id != collection.id),
|
||||
]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove a public collection, identified using its collection key, from our
|
||||
* local database.
|
||||
*
|
||||
* @param key The collection key that can be used to identify the public album
|
||||
* we want to remove.
|
||||
*/
|
||||
export const removePublicCollectionByKey = async (collectionKey: string) => {
|
||||
const collections = await savedPublicCollections();
|
||||
await savePublicCollections([
|
||||
...collections.filter((c) => c.key != collectionKey),
|
||||
]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Zod schema for a nullish string, with `null` transformed to `undefined`.
|
||||
*/
|
||||
const LocalString = z.string().nullish().transform(nullToUndefined);
|
||||
|
||||
/**
|
||||
* Return the last saved referral code present in our local database.
|
||||
@@ -55,7 +103,7 @@ const LocalReferralCode = z.string().nullish().transform(nullToUndefined);
|
||||
* out a new value using {@link saveLastPublicCollectionReferralCode}.
|
||||
*/
|
||||
export const savedLastPublicCollectionReferralCode = async () =>
|
||||
LocalReferralCode.parse(await localForage.getItem("public-referral-code"));
|
||||
LocalString.parse(await localForage.getItem("public-referral-code"));
|
||||
|
||||
/**
|
||||
* Update the referral code present in our local database.
|
||||
@@ -83,24 +131,35 @@ type LocalSavedPublicCollectionFilesEntry = z.infer<
|
||||
typeof LocalSavedPublicCollectionFilesEntry
|
||||
>;
|
||||
|
||||
// A purely synactic and local alias to avoid the code from looking scary.
|
||||
type ES = LocalSavedPublicCollectionFilesEntry[];
|
||||
|
||||
/**
|
||||
* Return all files for a public collection present in our local database.
|
||||
*
|
||||
* Use {@link savePublicCollectionFiles} to update the database.
|
||||
* Use {@link savePublicCollectionFiles} to update the list of files in the
|
||||
* database, and {@link removePublicCollectionFiles} to remove them.
|
||||
*
|
||||
* @param accessToken The access token of the public album whose files we want.
|
||||
* @param accessToken The access token that identifies the public album whose
|
||||
* files we want.
|
||||
*/
|
||||
export const savedPublicCollectionFiles = async (
|
||||
accessToken: string,
|
||||
): Promise<EnteFile[]> => {
|
||||
const entry = (await pcfEntries()).find(
|
||||
(e) => e.collectionUID == accessToken,
|
||||
);
|
||||
return transformFilesIfNeeded(entry ? entry.files : []);
|
||||
};
|
||||
|
||||
/**
|
||||
* A convenience routine to read the DB entries for "public-collection-files".
|
||||
*/
|
||||
const pcfEntries = async () => {
|
||||
// A local alias to avoid the code from looking scary.
|
||||
type ES = LocalSavedPublicCollectionFilesEntry[];
|
||||
|
||||
// See: [Note: Avoiding Zod parsing for large DB arrays] for why we use an
|
||||
// (implied) cast here instead of parsing using the Zod schema.
|
||||
const entries = await localForage.getItem<ES>("public-collection-files");
|
||||
const entry = (entries ?? []).find((e) => e.collectionUID == accessToken);
|
||||
return transformFilesIfNeeded(entry ? entry.files : []);
|
||||
return entries ?? [];
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -108,8 +167,8 @@ export const savedPublicCollectionFiles = async (
|
||||
*
|
||||
* This is the setter corresponding to {@link savedPublicCollectionFiles}.
|
||||
*
|
||||
* @param accessToken The access token of the public album whose files we want
|
||||
* to replace.
|
||||
* @param accessToken The access token that identifies the public album whose
|
||||
* files we want to update.
|
||||
*
|
||||
* @param files The files to save.
|
||||
*/
|
||||
@@ -117,15 +176,99 @@ export const savePublicCollectionFiles = async (
|
||||
accessToken: string,
|
||||
files: EnteFile[],
|
||||
): Promise<void> => {
|
||||
// See: [Note: Avoiding Zod parsing for large DB arrays].
|
||||
const entries = await localForage.getItem<ES>("public-collection-files");
|
||||
await localForage.setItem("public-collection-files", [
|
||||
{ collectionUID: accessToken, files },
|
||||
...(entries ?? []).filter((e) => e.collectionUID != accessToken),
|
||||
...(await pcfEntries()).filter((e) => e.collectionUID != accessToken),
|
||||
]);
|
||||
};
|
||||
|
||||
const LocalUploaderName = z.string().nullish().transform(nullToUndefined);
|
||||
/**
|
||||
* Remove the list of files, in any, in our local database for the given
|
||||
* collection (identified by its {@link accessToken}).
|
||||
*/
|
||||
export const removePublicCollectionFiles = async (
|
||||
accessToken: string,
|
||||
): Promise<void> => {
|
||||
await localForage.setItem("public-collection-files", [
|
||||
...(await pcfEntries()).filter((e) => e.collectionUID != accessToken),
|
||||
]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the locally persisted "last sync time" for a public collection that we
|
||||
* have pulled from remote. This can be used to perform a paginated delta pull
|
||||
* from the saved time onwards.
|
||||
*
|
||||
* Use {@link savePublic CollectionLastSyncTime} to update the value saved in
|
||||
* the database, and {@link removePublicCollectionLastSyncTime} to remove the
|
||||
* saved value from the database.
|
||||
*
|
||||
* @param accessToken The access token that identifies the public album whose
|
||||
* last sync time we want.
|
||||
*/
|
||||
export const savedPublicCollectionLastSyncTime = async (accessToken: string) =>
|
||||
LocalTimestamp.parse(
|
||||
await localForage.getItem(`public-${accessToken}-time`),
|
||||
);
|
||||
|
||||
/**
|
||||
* Update the locally persisted timestamp that will be returned by subsequent
|
||||
* calls to {@link savedPublicCollectionLastSyncTime}.
|
||||
*/
|
||||
export const savePublicCollectionLastSyncTime = async (
|
||||
accessToken: string,
|
||||
time: number,
|
||||
) => {
|
||||
await localForage.setItem(`public-${accessToken}-time`, time);
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove the locally persisted timestamp, if any, previously saved for a
|
||||
* collection using {@link savedPublicCollectionLastSyncTime}.
|
||||
*/
|
||||
export const removePublicCollectionLastSyncTime = async (
|
||||
accessToken: string,
|
||||
) => {
|
||||
await localForage.removeItem(`public-${accessToken}-time`);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the access token JWT, if any, present in our local database for the
|
||||
* given public collection (as identified by its {@link accessToken}).
|
||||
*
|
||||
* Use {@link savePublicCollectionAccessTokenJWT} to save the value, and
|
||||
* {@link removePublicCollectionAccessTokenJWT} to remove it.
|
||||
*/
|
||||
export const savedPublicCollectionAccessTokenJWT = async (
|
||||
accessToken: string,
|
||||
) =>
|
||||
LocalString.parse(
|
||||
await localForage.getItem(`public-${accessToken}-passkey`),
|
||||
);
|
||||
|
||||
/**
|
||||
* Update the access token JWT in our local database for the given public
|
||||
* collection (as identified by its {@link accessToken}).
|
||||
*
|
||||
* This is the setter corresponding to
|
||||
* {@link savedPublicCollectionAccessTokenJWT}.
|
||||
*/
|
||||
export const savePublicCollectionAccessTokenJWT = async (
|
||||
accessToken: string,
|
||||
passwordJWT: string,
|
||||
) => {
|
||||
await localForage.setItem(`public-${accessToken}-passkey`, passwordJWT);
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove the access token JWT in our local database for the given public
|
||||
* collection (as identified by its {@link accessToken}).
|
||||
*/
|
||||
export const removePublicCollectionAccessTokenJWT = async (
|
||||
accessToken: string,
|
||||
) => {
|
||||
await localForage.removeItem(`public-${accessToken}-passkey`);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the previously saved uploader name, if any, present in our local
|
||||
@@ -143,11 +286,11 @@ const LocalUploaderName = z.string().nullish().transform(nullToUndefined);
|
||||
* public collection, in the local database so that it can prefill it the next
|
||||
* time there is an upload from the same client.
|
||||
*
|
||||
* @param accessToken The access token of the public album whose persisted
|
||||
* uploader name we we want.
|
||||
* @param accessToken The access token that identifies the public album whose
|
||||
* saved uploader name we want.
|
||||
*/
|
||||
export const savedPublicCollectionUploaderName = async (accessToken: string) =>
|
||||
LocalUploaderName.parse(
|
||||
LocalString.parse(
|
||||
await localForage.getItem(`public-${accessToken}-uploaderName`),
|
||||
);
|
||||
|
||||
|
||||
@@ -188,8 +188,12 @@ export const saveCollectionFiles = async (files: EnteFile[]) => {
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the locally persisted {@link updationTime} of the latest file from the
|
||||
* given {@link collection} that we have pulled from remote.
|
||||
* Return the locally persisted "last sync time" for a collection that we have
|
||||
* pulled from remote. This can be used to perform a paginated delta pull from
|
||||
* the saved time onwards.
|
||||
*
|
||||
* > Specifically, this is the {@link updationTime} of the latest file from the
|
||||
* > {@link collection}, or the the collection itself if it is fully synced.
|
||||
*
|
||||
* Use {@link saveCollectionLastSyncTime} to update the value saved in the
|
||||
* database, and {@link removeCollectionIDLastSyncTime} to remove the saved
|
||||
|
||||
Reference in New Issue
Block a user