diff --git a/src/components/PhotoSwipe/PhotoSwipe.tsx b/src/components/PhotoSwipe/PhotoSwipe.tsx index 8e7f3546f..2f211d3f3 100644 --- a/src/components/PhotoSwipe/PhotoSwipe.tsx +++ b/src/components/PhotoSwipe/PhotoSwipe.tsx @@ -51,7 +51,6 @@ function PhotoSwipe(props: Iprops) { }, [isOpen]); function updateFavButton() { - console.log(this.currItem.id, props.favItemIds) setIsFav(isInFav(this?.currItem)); } @@ -113,14 +112,12 @@ function PhotoSwipe(props: Iprops) { if (!isInFav(file)) { favItemIds.add(file.id); await addToFavorites(file); - console.log("added to Favorites"); setIsFav(true); setFavItemIds(favItemIds); } else { favItemIds.delete(file.id); await removeFromFavorites(file) - console.log("removed from Favorites"); setIsFav(false); setFavItemIds(favItemIds); diff --git a/src/pages/gallery/components/CollectionDropZone.tsx b/src/pages/gallery/components/CollectionDropZone.tsx index 12f4501c0..6d466506d 100644 --- a/src/pages/gallery/components/CollectionDropZone.tsx +++ b/src/pages/gallery/components/CollectionDropZone.tsx @@ -9,7 +9,7 @@ function CollectionDropZone({ closeModal, showModal, refetchData, - collectionLatestFile, + collectionAndItsLatestFile, setProgressView, progressBarProps @@ -21,7 +21,7 @@ function CollectionDropZone({ progressBarProps.setPercentComplete(0); setProgressView(true); - await UploadService.uploadFiles(acceptedFiles, collectionLatestFile, token, progressBarProps); + await UploadService.uploadFiles(acceptedFiles, collectionAndItsLatestFile, token, progressBarProps); refetchData(); setProgressView(false); } diff --git a/src/pages/gallery/components/CollectionSelector.tsx b/src/pages/gallery/components/CollectionSelector.tsx index cde34ace8..2d5727020 100644 --- a/src/pages/gallery/components/CollectionSelector.tsx +++ b/src/pages/gallery/components/CollectionSelector.tsx @@ -10,17 +10,16 @@ function CollectionSelector(props) { uploadModalView, closeUploadModal, showUploadModal, - collectionLatestFile, + collectionAndItsLatestFile, ...rest } = props; - - const CollectionIcons = collectionLatestFile?.map((item) => ( + const CollectionIcons = collectionAndItsLatestFile?.map((item) => ( { }} forcedEnable /> diff --git a/src/pages/gallery/components/Collections.tsx b/src/pages/gallery/components/Collections.tsx index f824ec2f5..b992f7570 100644 --- a/src/pages/gallery/components/Collections.tsx +++ b/src/pages/gallery/components/Collections.tsx @@ -5,7 +5,7 @@ import styled from 'styled-components'; interface CollectionProps { collections: collection[]; selected?: string; - selectCollection: (id?: string) => void; + selectCollection: (id?: number) => void; } const Container = styled.div` @@ -51,7 +51,7 @@ const Chip = styled.button<{ active: boolean }>` export default function Collections(props: CollectionProps) { const { selected, collections, selectCollection } = props; - const clickHandler = (id?: string) => () => selectCollection(id); + const clickHandler = (id?: number) => () => selectCollection(id); return diff --git a/src/pages/gallery/components/CreateCollection.tsx b/src/pages/gallery/components/CreateCollection.tsx index 38fd96197..027edc5d7 100644 --- a/src/pages/gallery/components/CreateCollection.tsx +++ b/src/pages/gallery/components/CreateCollection.tsx @@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react'; import { Button, Form, Modal } from 'react-bootstrap'; import { createAlbum } from 'services/collectionService'; import UploadService from 'services/uploadService'; -import { collectionLatestFile } from 'services/collectionService' +import { CollectionAndItsLatestFile } from 'services/collectionService' import { getToken } from 'utils/common/key'; export default function CreateCollection(props) { @@ -35,12 +35,12 @@ export default function CreateCollection(props) { const collection = await createAlbum(albumName); - const collectionLatestFile: collectionLatestFile = { collection, file: null } + const collectionAndItsLatestFile: CollectionAndItsLatestFile = { collection, file: null } progressBarProps.setPercentComplete(0); setProgressView(true); - await UploadService.uploadFiles(acceptedFiles, collectionLatestFile, token, progressBarProps); + await UploadService.uploadFiles(acceptedFiles, collectionAndItsLatestFile, token, progressBarProps); refetchData(); setProgressView(false); } diff --git a/src/pages/gallery/index.tsx b/src/pages/gallery/index.tsx index dd5f8e874..3dbdd9440 100644 --- a/src/pages/gallery/index.tsx +++ b/src/pages/gallery/index.tsx @@ -6,7 +6,7 @@ import { file, getFile, getPreview, - fetchData, + syncData, localFiles, } from 'services/fileService'; import { getData, LS_KEYS } from 'utils/storage/localStorage'; @@ -22,9 +22,9 @@ import Collections from './components/Collections'; import Upload from './components/Upload'; import { collection, - fetchUpdatedCollections, - collectionLatestFile, - getCollectionLatestFile, + syncCollections, + CollectionAndItsLatestFile, + getCollectionAndItsLatestFile, getFavItemIds, getLocalCollections, } from 'services/collectionService'; @@ -108,9 +108,10 @@ export default function Gallery(props) { const router = useRouter(); const [loading, setLoading] = useState(false); const [collections, setCollections] = useState([]); - const [collectionLatestFile, setCollectionLatestFile] = useState< - collectionLatestFile[] - >([]); + const [ + collectionAndItsLatestFile, + setCollectionAndItsLatestFile, + ] = useState([]); const [data, setData] = useState(); const [favItemIds, setFavItemIds] = useState>(); const [open, setOpen] = useState(false); @@ -132,8 +133,16 @@ export default function Gallery(props) { setLoading(true); const data = await localFiles(); const collections = await getLocalCollections(); + const collectionAndItsLatestFile = await getCollectionAndItsLatestFile( + collections, + data + ); setData(data); setCollections(collections); + setCollectionAndItsLatestFile(collectionAndItsLatestFile); + const favItemIds = await getFavItemIds(data); + setFavItemIds(favItemIds); + setLoading(false); setProgress(80); await syncWithRemote(); @@ -146,22 +155,18 @@ export default function Gallery(props) { const syncWithRemote = async () => { const token = getToken(); const encryptionKey = await getActualKey(); - const updatedCollections = await fetchUpdatedCollections( - token, - encryptionKey - ); - const data = await fetchData(token, updatedCollections); - const collections = await getLocalCollections(); - const collectionLatestFile = await getCollectionLatestFile( + const collections = await syncCollections(token, encryptionKey); + const { data, isUpdated } = await syncData(token, collections); + const collectionAndItsLatestFile = await getCollectionAndItsLatestFile( collections, data ); const favItemIds = await getFavItemIds(data); - if (updatedCollections.length > 0) { - setCollections(collections); + setCollections(collections); + if (isUpdated) { setData(data); } - setCollectionLatestFile(collectionLatestFile); + setCollectionAndItsLatestFile(collectionAndItsLatestFile); setFavItemIds(favItemIds); setSinceTime(new Date().getTime()); props.setUploadButtonView(true); @@ -295,7 +300,7 @@ export default function Gallery(props) { ); } - const selectCollection = (id?: string) => { + const selectCollection = (id?: number) => { const href = `/gallery?collection=${id || ''}`; router.push(href, undefined, { shallow: true }); }; @@ -344,7 +349,7 @@ export default function Gallery(props) { uploadModalView={props.uploadModalView} closeUploadModal={props.closeUploadModal} showUploadModal={props.showUploadModal} - collectionLatestFile={collectionLatestFile} + collectionAndItsLatestFile={collectionAndItsLatestFile} refetchData={syncWithRemote} /> {filteredData.length ? ( diff --git a/src/services/collectionService.ts b/src/services/collectionService.ts index 2a06a8715..6b608605d 100644 --- a/src/services/collectionService.ts +++ b/src/services/collectionService.ts @@ -1,35 +1,37 @@ -import { getEndpoint } from "utils/common/apiUtil"; -import { getData, LS_KEYS } from "utils/storage/localStorage"; -import { file, user, getFiles } from "./fileService"; +import { getEndpoint } from 'utils/common/apiUtil'; +import { getData, LS_KEYS } from 'utils/storage/localStorage'; +import { file, user, getFiles } from './fileService'; import localForage from 'localforage'; -import HTTPService from "./HTTPService"; +import HTTPService from './HTTPService'; import * as Comlink from 'comlink'; -import { keyEncryptionResult } from "./uploadService"; -import { getActualKey, getToken } from "utils/common/key"; - +import { keyEncryptionResult } from './uploadService'; +import { getActualKey, getToken } from 'utils/common/key'; const CryptoWorker: any = typeof window !== 'undefined' && Comlink.wrap(new Worker('worker/crypto.worker.js', { type: 'module' })); const ENDPOINT = getEndpoint(); - enum CollectionType { - folder = "folder", - favorites = "favorites", - album = "album", + folder = 'folder', + favorites = 'favorites', + album = 'album', } +const COLLECTION_UPDATION_TIME = 'collection-updation-time'; +const FAV_COLLECTION = 'fav-collection'; +const COLLECTIONS = 'collections'; + export interface collection { - id: string; + id: number; owner: user; key?: string; name?: string; encryptedName?: string; nameDecryptionNonce?: string; type: string; - attributes: collectionAttributes + attributes: collectionAttributes; sharees: user[]; updationTime: number; encryptedKey: string; @@ -39,16 +41,18 @@ export interface collection { interface collectionAttributes { encryptedPath?: string; - pathDecryptionNonce?: string -}; + pathDecryptionNonce?: string; +} -export interface collectionLatestFile { - collection: collection +export interface CollectionAndItsLatestFile { + collection: collection; file: file; } - -const getCollectionSecrets = async (collection: collection, masterKey: string) => { +const getCollectionSecrets = async ( + collection: collection, + masterKey: string +) => { const worker = await new CryptoWorker(); const userID = getData(LS_KEYS.USER).id; let decryptedKey: string; @@ -58,7 +62,6 @@ const getCollectionSecrets = async (collection: collection, masterKey: string) = collection.keyDecryptionNonce, masterKey ); - } else { const keyAttributes = getData(LS_KEYS.KEY_ATTRIBUTES); const secretKey = await worker.decryptB64( @@ -72,10 +75,13 @@ const getCollectionSecrets = async (collection: collection, masterKey: string) = secretKey ); } - collection.name = collection.name || await worker.decryptString( - collection.encryptedName, - collection.nameDecryptionNonce, - decryptedKey); + collection.name = + collection.name || + (await worker.decryptString( + collection.encryptedName, + collection.nameDecryptionNonce, + decryptedKey + )); return { ...collection, key: decryptedKey, @@ -88,85 +94,131 @@ const getCollections = async ( key: string ): Promise => { try { - const resp = await HTTPService.get(`${ENDPOINT}/collections`, { - sinceTime: sinceTime, - }, { 'X-Auth-Token': token, }); + const resp = await HTTPService.get( + `${ENDPOINT}/collections`, + { + sinceTime: sinceTime, + }, + { 'X-Auth-Token': token } + ); const promises: Promise[] = resp.data.collections.map( (collection: collection) => getCollectionSecrets(collection, key) ); return await Promise.all(promises); - } - catch (e) { - console.log("getCollections failed- " + e); + } catch (e) { + console.log('getCollections failed- ' + e); } }; export const getLocalCollections = async (): Promise => { - const collections = await localForage.getItem('collections') as collection[] ?? []; + const collections: collection[] = + (await localForage.getItem(COLLECTIONS)) ?? []; return collections; -} -export const fetchUpdatedCollections = async (token: string, key: string) => { - const collectionUpdateTime = await localForage.getItem('collection-update-time') as string; - const updatedCollections = await getCollections(token, collectionUpdateTime ?? '0', key) || []; - const favCollection = await localForage.getItem('fav-collection') as collection[] ?? updatedCollections.filter(collection => collection.type === CollectionType.favorites); +}; + +export const syncCollections = async (token: string, key: string) => { const localCollections = await getLocalCollections(); - const allCollectionsInstances = [...localCollections, ...updatedCollections]; - var latestCollectionsInstances = new Map(); + const lastCollectionUpdationTime = + (await localForage.getItem(COLLECTION_UPDATION_TIME)) ?? '0'; + const updatedCollections = + (await getCollections(token, lastCollectionUpdationTime, key)) || []; + + if (updatedCollections.length == 0) { + return localCollections; + } + setLocalFavoriteCollection(updatedCollections); + const allCollectionsInstances = [ + ...localCollections, + ...updatedCollections, + ]; + var latestCollectionsInstances = new Map(); allCollectionsInstances.forEach((collection) => { - if (!latestCollectionsInstances.has(collection.id) || latestCollectionsInstances.get(collection.id).updationTime < collection.updationTime) { + if ( + !latestCollectionsInstances.has(collection.id) || + latestCollectionsInstances.get(collection.id).updationTime < + collection.updationTime + ) { latestCollectionsInstances.set(collection.id, collection); } }); - let collections = []; + + let collections = [], + updationTime = await localForage.getItem( + COLLECTION_UPDATION_TIME + ); for (const [_, collection] of latestCollectionsInstances) { - collections.push(collection); + if (!collection.isDeleted) { + collections.push(collection); + updationTime = Math.max(updationTime, collection.updationTime); + } } - await localForage.setItem('fav-collection', favCollection); - await localForage.setItem('collections', collections); - return updatedCollections; + await localForage.setItem(COLLECTION_UPDATION_TIME, updationTime); + await localForage.setItem(COLLECTIONS, collections); + return collections; }; -export const getCollectionLatestFile = ( +export const getCollectionAndItsLatestFile = ( collections: collection[], files: file[] -): collectionLatestFile[] => { +): CollectionAndItsLatestFile[] => { const latestFile = new Map(); const collectionMap = new Map(); - collections.forEach(collection => collectionMap.set(Number(collection.id), collection)); - files.forEach(file => { + collections.forEach((collection) => + collectionMap.set(collection.id, collection) + ); + files.forEach((file) => { if (!latestFile.has(file.collectionID)) { - latestFile.set(file.collectionID, file) + latestFile.set(file.collectionID, file); } }); - let allCollectionLatestFile: collectionLatestFile[] = []; + let allCollectionAndItsLatestFile: CollectionAndItsLatestFile[] = []; for (const [collectionID, file] of latestFile) { - allCollectionLatestFile.push({ collection: collectionMap.get(collectionID), file }); + allCollectionAndItsLatestFile.push({ + collection: collectionMap.get(collectionID), + file, + }); } - return allCollectionLatestFile; -} + return allCollectionAndItsLatestFile; +}; export const getFavItemIds = async (files: file[]): Promise> => { + let favCollection = await localForage.getItem(FAV_COLLECTION); + if (!favCollection) return new Set(); - let favCollection: collection = (await localForage.getItem('fav-collection'))[0]; - if (!favCollection) - return new Set(); - - return new Set(files.filter(file => file.collectionID === Number(favCollection.id)).map((file): number => file.id)); -} + return new Set( + files + .filter((file) => file.collectionID === favCollection.id) + .map((file): number => file.id) + ); +}; export const createAlbum = async (albumName: string) => { return AddCollection(albumName, CollectionType.album); -} +}; - -export const AddCollection = async (collectionName: string, type: CollectionType) => { +export const AddCollection = async ( + collectionName: string, + type: CollectionType +) => { const worker = await new CryptoWorker(); const encryptionKey = await getActualKey(); const token = getToken(); const collectionKey: string = await worker.generateMasterKey(); - const { encryptedData: encryptedKey, nonce: keyDecryptionNonce }: keyEncryptionResult = await worker.encryptToB64(collectionKey, encryptionKey); - const { encryptedData: encryptedName, nonce: nameDecryptionNonce }: keyEncryptionResult = await worker.encryptToB64(collectionName, collectionKey); + const { + encryptedData: encryptedKey, + nonce: keyDecryptionNonce, + }: keyEncryptionResult = await worker.encryptToB64( + collectionKey, + encryptionKey + ); + const { + encryptedData: encryptedName, + nonce: nameDecryptionNonce, + }: keyEncryptionResult = await worker.encryptToB64( + collectionName, + collectionKey + ); const newCollection: collection = { id: null, owner: null, @@ -178,76 +230,126 @@ export const AddCollection = async (collectionName: string, type: CollectionType attributes: {}, sharees: null, updationTime: null, - isDeleted: false + isDeleted: false, }; - let createdCollection: collection = await createCollection(newCollection, token); - createdCollection = await getCollectionSecrets(createdCollection, encryptionKey); + let createdCollection: collection = await createCollection( + newCollection, + token + ); + createdCollection = await getCollectionSecrets( + createdCollection, + encryptionKey + ); return createdCollection; -} +}; -const createCollection = async (collectionData: collection, token: string): Promise => { +const createCollection = async ( + collectionData: collection, + token: string +): Promise => { try { - const response = await HTTPService.post(`${ENDPOINT}/collections`, collectionData, null, { 'X-Auth-Token': token }); + const response = await HTTPService.post( + `${ENDPOINT}/collections`, + collectionData, + null, + { 'X-Auth-Token': token } + ); return response.data.collection; } catch (e) { - console.log("create Collection failed " + e); + console.log('create Collection failed ' + e); } -} +}; export const addToFavorites = async (file: file) => { - let favCollection: collection = (await localForage.getItem('fav-collection'))[0]; + let favCollection: collection = await localForage.getItem( + FAV_COLLECTION + ); if (!favCollection) { - favCollection = await AddCollection("Favorites", CollectionType.favorites); - await localForage.setItem('fav-collection', favCollection); + favCollection = await AddCollection( + 'Favorites', + CollectionType.favorites + ); + await localForage.setItem(FAV_COLLECTION, favCollection); } - await addtoCollection(favCollection, [file]) -} + await addToCollection(favCollection, [file]); +}; export const removeFromFavorites = async (file: file) => { - let favCollection: collection = (await localForage.getItem('fav-collection'))[0]; - await removeFromCollection(favCollection, [file]) -} + let favCollection: collection = await localForage.getItem( + FAV_COLLECTION + ); + await removeFromCollection(favCollection, [file]); +}; -const addtoCollection = async (collection: collection, files: file[]) => { +const addToCollection = async (collection: collection, files: file[]) => { try { const params = new Object(); const worker = await new CryptoWorker(); const token = getToken(); - params["collectionID"] = collection.id; - await Promise.all(files.map(async file => { - file.collectionID = Number(collection.id); - const newEncryptedKey: keyEncryptionResult = await worker.encryptToB64(file.key, collection.key); - file.encryptedKey = newEncryptedKey.encryptedData; - file.keyDecryptionNonce = newEncryptedKey.nonce; - if (params["files"] == undefined) { - params["files"] = []; - } - params["files"].push({ - id: file.id, - encryptedKey: file.encryptedKey, - keyDecryptionNonce: file.keyDecryptionNonce + params['collectionID'] = collection.id; + await Promise.all( + files.map(async (file) => { + file.collectionID = collection.id; + const newEncryptedKey: keyEncryptionResult = await worker.encryptToB64( + file.key, + collection.key + ); + file.encryptedKey = newEncryptedKey.encryptedData; + file.keyDecryptionNonce = newEncryptedKey.nonce; + if (params['files'] == undefined) { + params['files'] = []; + } + params['files'].push({ + id: file.id, + encryptedKey: file.encryptedKey, + keyDecryptionNonce: file.keyDecryptionNonce, + }); + return file; }) - return file; - })); - await HTTPService.post(`${ENDPOINT}/collections/add-files`, params, null, { 'X-Auth-Token': token }); + ); + await HTTPService.post( + `${ENDPOINT}/collections/add-files`, + params, + null, + { 'X-Auth-Token': token } + ); } catch (e) { - console.log("Add to collection Failed " + e); + console.log('Add to collection Failed ' + e); } -} +}; const removeFromCollection = async (collection: collection, files: file[]) => { try { const params = new Object(); const token = getToken(); - params["collectionID"] = collection.id; - await Promise.all(files.map(async file => { - if (params["fileIDs"] == undefined) { - params["fileIDs"] = []; - } - params["fileIDs"].push(file.id); - })); - await HTTPService.post(`${ENDPOINT}/collections/remove-files`, params, null, { 'X-Auth-Token': token }); + params['collectionID'] = collection.id; + await Promise.all( + files.map(async (file) => { + if (params['fileIDs'] == undefined) { + params['fileIDs'] = []; + } + params['fileIDs'].push(file.id); + }) + ); + await HTTPService.post( + `${ENDPOINT}/collections/remove-files`, + params, + null, + { 'X-Auth-Token': token } + ); } catch (e) { - console.log("remove from collection failed " + e); + console.log('remove from collection failed ' + e); } -} +}; +const setLocalFavoriteCollection = async (collections: collection[]) => { + const localFavCollection = await localForage.getItem(FAV_COLLECTION); + if (localFavCollection) { + return; + } + const favCollection = collections.filter( + (collection) => collection.type == CollectionType.favorites + ); + if (favCollection.length > 0) { + await localForage.setItem(FAV_COLLECTION, favCollection[0]); + } +}; diff --git a/src/services/fileService.ts b/src/services/fileService.ts index b9ae4263a..c3e1c47af 100644 --- a/src/services/fileService.ts +++ b/src/services/fileService.ts @@ -16,6 +16,8 @@ localForage.config({ storeName: 'files', }); +const FILES = 'files'; + export interface fileAttribute { encryptedData: Uint8Array | string; decryptionHeader: string; @@ -29,7 +31,6 @@ export interface user { email: string; } - export interface file { id: number; collectionID: number; @@ -49,92 +50,95 @@ export interface file { updationTime: number; } +export const syncData = async (token, collections) => { + const { files: resp, isUpdated } = await syncFiles(token, collections); - -export const fetchData = async (token, collections) => { - const resp = await fetchFiles( - token, - collections - ); - - return ( - resp.map((item) => ({ + return { + data: resp.map((item) => ({ ...item, w: window.innerWidth, h: window.innerHeight, - })) - ); -} + })), + isUpdated, + }; +}; export const localFiles = async () => { - let files: Array = (await localForage.getItem('files')) || []; - return files; -} - -export const fetchFiles = async ( - token: string, - collections: collection[] -) => { - let files = await localFiles(); - const collectionUpdationTime = new Map(); - let fetchedFiles = []; - for (let collection of collections) { - const files = await getFiles(collection, null, 100, token); - fetchedFiles.push(...files); - collectionUpdationTime.set(collection.id, files.length > 0 ? files.slice(-1)[0].updationTime.toString() : "0"); - } - files.push(...fetchedFiles); - var latestFiles = new Map(); - files.forEach((file) => { - let uid = `${file.collectionID}-${file.id}`; - if (!latestFiles.has(uid) || latestFiles.get(uid).updationTime < file.updationTime) { - latestFiles.set(uid, file); - } - }); - files = []; - for (const [_, file] of latestFiles) { - if (!file.isDeleted) - files.push(file); - } - files = files.sort( - (a, b) => b.metadata.creationTime - a.metadata.creationTime - ); - await localForage.setItem('files', files); - for (let [collectionID, updationTime] of collectionUpdationTime) { - await localForage.setItem(`${collectionID}-time`, updationTime); - } - let updationTime = await localForage.getItem('collection-update-time') as number; - for (let collection of collections) { - updationTime = Math.max(updationTime, collection.updationTime); - } - await localForage.setItem('collection-update-time', updationTime); + let files: Array = (await localForage.getItem(FILES)) || []; return files; }; -export const getFiles = async (collection: collection, sinceTime: string, limit: number, token: string): Promise => { +export const syncFiles = async (token: string, collections: collection[]) => { + let files = await localFiles(); + let isUpdated = false; + files = await removeDeletedCollectionFiles(collections, files); + for (let collection of collections) { + const lastSyncTime = + (await localForage.getItem(`${collection.id}-time`)) ?? 0; + if (collection.updationTime === lastSyncTime) { + continue; + } + isUpdated = true; + let fetchedFiles = + (await getFiles(collection, lastSyncTime, 100, token)) ?? []; + files.push(...fetchedFiles); + var latestVersionFiles = new Map(); + files.forEach((file) => { + if ( + !latestVersionFiles.has(file.id) || + latestVersionFiles.get(file.id).updationTime < file.updationTime + ) { + latestVersionFiles.set(file.id, file); + } + }); + files = []; + for (const [_, file] of latestVersionFiles) { + if (file.isDeleted) { + continue; + } + files.push(file); + } + files = files.sort( + (a, b) => b.metadata.creationTime - a.metadata.creationTime + ); + await localForage.setItem('files', files); + await localForage.setItem( + `${collection.id}-time`, + collection.updationTime + ); + } + return { files, isUpdated }; +}; + +export const getFiles = async ( + collection: collection, + sinceTime: number, + limit: number, + token: string +): Promise => { try { const worker = await new CryptoWorker(); let promises: Promise[] = []; - if (collection.isDeleted) { - // TODO: Remove files in this collection from localForage and cache - return; - } let time = - sinceTime || (await localForage.getItem(`${collection.id}-time`)) || "0"; + sinceTime || + (await localForage.getItem(`${collection.id}-time`)) || + 0; let resp; do { - resp = await HTTPService.get(`${ENDPOINT}/collections/diff`, { - collectionID: collection.id, - sinceTime: time, - limit: limit.toString(), - }, + resp = await HTTPService.get( + `${ENDPOINT}/collections/diff`, { - 'X-Auth-Token': token - }); - promises.push(...resp.data.diff.map( - async (file: file) => { + collectionID: collection.id.toString(), + sinceTime: time.toString(), + limit: limit.toString(), + }, + { + 'X-Auth-Token': token, + } + ); + promises.push( + ...resp.data.diff.map(async (file: file) => { if (!file.isDeleted) { - file.key = await worker.decryptB64( file.encryptedKey, file.keyDecryptionNonce, @@ -143,8 +147,8 @@ export const getFiles = async (collection: collection, sinceTime: string, limit: file.metadata = await worker.decryptMetadata(file); } return file; - } - )); + }) + ); if (resp.data.diff.length) { time = resp.data.diff.slice(-1)[0].updationTime.toString(); @@ -152,9 +156,9 @@ export const getFiles = async (collection: collection, sinceTime: string, limit: } while (resp.data.diff.length === limit); return await Promise.all(promises); } catch (e) { - console.log("Get files failed" + e); + console.log('Get files failed' + e); } -} +}; export const getPreview = async (token: string, file: file) => { try { const cache = await caches.open('thumbs'); @@ -175,13 +179,16 @@ export const getPreview = async (token: string, file: file) => { file.key ); try { - await cache.put(file.id.toString(), new Response(new Blob([decrypted]))); + await cache.put( + file.id.toString(), + new Response(new Blob([decrypted])) + ); } catch (e) { // TODO: handle storage full exception. } return URL.createObjectURL(new Blob([decrypted])); } catch (e) { - console.log("get preview Failed" + e); + console.log('get preview Failed' + e); } }; @@ -200,9 +207,19 @@ export const getFile = async (token: string, file: file) => { file.key ); return URL.createObjectURL(new Blob([decrypted])); - } - catch (e) { - console.log("get file failed " + e); + } catch (e) { + console.log('get file failed ' + e); } }; +const removeDeletedCollectionFiles = async ( + collections: collection[], + files: file[] +) => { + const syncedCollectionIds = new Set(); + for (let collection of collections) { + syncedCollectionIds.add(collection.id); + } + files = files.filter((file) => syncedCollectionIds.has(file.collectionID)); + return files; +}; diff --git a/src/services/uploadService.ts b/src/services/uploadService.ts index a69cdbacb..07799b04c 100644 --- a/src/services/uploadService.ts +++ b/src/services/uploadService.ts @@ -3,7 +3,7 @@ import HTTPService from './HTTPService'; import * as Comlink from 'comlink'; import EXIF from "exif-js"; import { fileAttribute } from './fileService'; -import { collection, collectionLatestFile } from "./collectionService" +import { collection, CollectionAndItsLatestFile } from "./collectionService" import { FILE_TYPE } from 'pages/gallery'; const CryptoWorker: any = typeof window !== 'undefined' && @@ -49,7 +49,7 @@ interface objectKeys { } interface uploadFile extends objectKeys { - collectionID: string, + collectionID: number, encryptedKey: string; keyDecryptionNonce: string; metadata?: { @@ -80,7 +80,7 @@ class UploadService { private totalFilesCount: number private metadataMap: Map; - public async uploadFiles(recievedFiles: File[], collectionLatestFile: collectionLatestFile, token: string, progressBarProps) { + public async uploadFiles(recievedFiles: File[], collectionAndItsLatestFile: CollectionAndItsLatestFile, token: string, progressBarProps) { try { const worker = await new CryptoWorker(); this.stepsCompleted = 0; @@ -107,7 +107,7 @@ class UploadService { while (actualFiles.length > 0) { var promises = []; for (var i = 0; i < 5 && actualFiles.length > 0; i++) - promises.push(this.uploadHelper(progressBarProps, actualFiles.pop(), collectionLatestFile.collection, token)); + promises.push(this.uploadHelper(progressBarProps, actualFiles.pop(), collectionAndItsLatestFile.collection, token)); uploadFilesWithoutMetaData.push(...await Promise.all(promises)); } @@ -364,7 +364,6 @@ class UploadService { resolve(blob); }), 'image/jpeg', 0.4 }); - console.log(URL.createObjectURL(thumbnailBlob)); const thumbnail = this.getUint8ArrayView(thumbnailBlob); return thumbnail; } catch (e) { diff --git a/src/utils/common/apiUtil.ts b/src/utils/common/apiUtil.ts index c1da535d5..d9da1e289 100644 --- a/src/utils/common/apiUtil.ts +++ b/src/utils/common/apiUtil.ts @@ -1,5 +1,4 @@ export const getEndpoint = () => { const endPoint = process.env.NEXT_PUBLIC_ENTE_ENDPOINT ?? "https://api.ente.io"; - console.log(endPoint); return endPoint; }