From ca67726de57218884a26000738c368dde04e31ef Mon Sep 17 00:00:00 2001 From: Nozomi Ichihara Date: Mon, 2 Dec 2024 17:51:59 -0500 Subject: [PATCH 01/11] (edit) add a new 'acceptedTerms' context state and user token validation in RefinebioContext (during the initial load of the application - replacing the useToken hook) ,and adjusted the other hooks that utilize token --- src/api/interfaces/token.js | 4 +-- src/contexts/DatasetManagerContext.js | 9 ++---- src/contexts/RefinebioContext.js | 34 ++++++++++++++++++-- src/hooks/useDatasetManager.js | 17 ++++------ src/hooks/useDownloadCompendium.js | 10 +++--- src/hooks/useRefinebio.js | 7 ++-- src/hooks/useToken.js | 46 --------------------------- 7 files changed, 53 insertions(+), 74 deletions(-) delete mode 100644 src/hooks/useToken.js diff --git a/src/api/interfaces/token.js b/src/api/interfaces/token.js index 32efd484..5e87860a 100644 --- a/src/api/interfaces/token.js +++ b/src/api/interfaces/token.js @@ -7,13 +7,13 @@ export default { return http.post(url) }, get: (id) => { - const path = `${url}${id}` + const path = `${url}${id}/` return http.get(path) }, update: (id, params) => { const path = `${url}${id}` - return http.put(path, params || { is_activated: true }) + return http.put(path, params) } } diff --git a/src/contexts/DatasetManagerContext.js b/src/contexts/DatasetManagerContext.js index 350f34e9..e62dce62 100644 --- a/src/contexts/DatasetManagerContext.js +++ b/src/contexts/DatasetManagerContext.js @@ -16,8 +16,7 @@ export const DatasetManagerContextProvider = ({ children }) => { email, setEmail, processingDatasets, - setProcessingDatasets, - token + setProcessingDatasets } = useRefinebio() const value = useMemo( @@ -33,8 +32,7 @@ export const DatasetManagerContextProvider = ({ children }) => { email, setEmail, processingDatasets, - setProcessingDatasets, - token + setProcessingDatasets }), [ dataset, @@ -48,8 +46,7 @@ export const DatasetManagerContextProvider = ({ children }) => { email, setEmail, processingDatasets, - setProcessingDatasets, - token + setProcessingDatasets ] ) diff --git a/src/contexts/RefinebioContext.js b/src/contexts/RefinebioContext.js index ce12a6cb..a985bc30 100644 --- a/src/contexts/RefinebioContext.js +++ b/src/contexts/RefinebioContext.js @@ -4,6 +4,7 @@ import { getOldLocalStorageKey, removeOldLocalStorageKey } from 'helpers/migrateLocalStorage' +import { api } from 'api' export const RefinebioContext = createContext({}) @@ -24,8 +25,28 @@ export const RefinebioContextProvider = ({ children }) => { 'requested-experiments', [] ) + const [acceptedTerms, setAcceptedTerms] = useLocalStorage( + 'accepted-terms', + false + ) const [token, setToken] = useLocalStorage('token', null) + const createToken = async () => { + const { id } = await api.token.create() + await api.token.update(id, { is_activated: true }) + setToken(id) + setAcceptedTerms(true) + + return id + } + + const validateToken = async () => { + const response = await api.token.get(token) + // create a new token if validation fails + // (e.g., a corrupted token value, API version changes) + if (!response.ok) await createToken() + } + // NOTE: migration support is removed 12 months after the site swap useEffect(() => { // after the code swap, if the old key exists in the users' browsers, assign that @@ -39,6 +60,13 @@ export const RefinebioContextProvider = ({ children }) => { } }, []) + // validates the stored token only if the user has accepted the terms + useEffect(() => { + if (acceptedTerms && token) { + validateToken() + } + }, [acceptedTerms, token]) + const value = useMemo( () => ({ dataset, @@ -55,8 +83,9 @@ export const RefinebioContextProvider = ({ children }) => { setProcessingDatasets, requestedExperiments, setRequestedExperiments, + acceptedTerms, token, - setToken + createToken }), [ dataset, @@ -73,8 +102,9 @@ export const RefinebioContextProvider = ({ children }) => { setProcessingDatasets, requestedExperiments, setRequestedExperiments, + acceptedTerms, token, - setToken + createToken ] ) diff --git a/src/hooks/useDatasetManager.js b/src/hooks/useDatasetManager.js index dda4a2f7..5178bb55 100644 --- a/src/hooks/useDatasetManager.js +++ b/src/hooks/useDatasetManager.js @@ -1,6 +1,6 @@ import { useContext, useState } from 'react' import { DatasetManagerContext } from 'contexts/DatasetManagerContext' -import { useToken } from 'hooks/useToken' +import { useRefinebio } from 'hooks/useRefinebio' import differenceOfArrays from 'helpers/differenceOfArrays' import formatString from 'helpers/formatString' import isEmptyObject from 'helpers/isEmptyObject' @@ -21,10 +21,9 @@ export const useDatasetManager = () => { email, setEmail, processingDatasets, - setProcessingDatasets, - token + setProcessingDatasets } = useContext(DatasetManagerContext) - const { createToken, resetToken, validateToken } = useToken() + const { token, createToken } = useRefinebio() const [error, setError] = useState(null) const [loading, setLoading] = useState(false) @@ -88,12 +87,11 @@ export const useDatasetManager = () => { const downloadDataset = async (id, downloadUrl) => { let href = '' - if ((await validateToken()) && downloadUrl) { + if (token && downloadUrl) { href = downloadUrl } else { // creates a new token and requests a download url with API-Key - const tokenId = await createToken() - const { download_url: url } = await getDataset(id, tokenId) + const { download_url: url } = await getDataset(id, await createToken()) href = url } @@ -143,15 +141,13 @@ export const useDatasetManager = () => { accessionCode = null ) => { const isMyDatasetId = id && id === datasetId - // validates the existing token or create a new one - const tokenId = (await validateToken()) ? token : await resetToken() const { emailAddress, receiveUpdates } = options const params = { ...getDownloadOptions(options), email_address: emailAddress, ...(receiveUpdates ? { email_ccdl_ok: true } : {}), start: true, - token_id: tokenId + token_id: token || (await createToken()) } const processingDatasetId = id || (await createDataset()) // creates new dataset ID for one-off download const response = await updateDataset(processingDatasetId, params) @@ -299,7 +295,6 @@ export const useDatasetManager = () => { loading, processingDatasets, setProcessingDatasets, - token, // Processing Dataset getProcessingDatasetByAccession, // Common diff --git a/src/hooks/useDownloadCompendium.js b/src/hooks/useDownloadCompendium.js index 99464967..46f8352b 100644 --- a/src/hooks/useDownloadCompendium.js +++ b/src/hooks/useDownloadCompendium.js @@ -1,18 +1,20 @@ import { useEffect, useState } from 'react' -import { useToken } from 'hooks/useToken' +import { useRefinebio } from 'hooks/useRefinebio' import { api } from 'api' import gtag from 'analytics/gtag' export const useDownloadCompendium = (compendium) => { - const { token, resetToken, validateToken } = useToken() + const { token, createToken } = useRefinebio() const [error, setError] = useState(null) const [downloadUrl, setDownloadUrl] = useState('') // fetchs the download URL for the selected compendium with a valid token useEffect(() => { const fetchDownloadUrl = async () => { - const tokenToUse = !validateToken() ? await resetToken() : token - const response = await api.compendia.download(compendium.id, tokenToUse) + const response = await api.compendia.download( + compendium.id, + token || (await createToken()) + ) const { ok, statusCode } = response setError(!ok ? statusCode : null) setDownloadUrl(ok ? response.computed_file.download_url : null) diff --git a/src/hooks/useRefinebio.js b/src/hooks/useRefinebio.js index d1b07161..cd3a9e58 100644 --- a/src/hooks/useRefinebio.js +++ b/src/hooks/useRefinebio.js @@ -15,11 +15,11 @@ export const useRefinebio = () => { setEmail, processingDatasets, setProcessingDatasets, - requestedExperiments, setRequestedExperiments, + acceptedTerms, token, - setToken + createToken } = useContext(RefinebioContext) return { @@ -37,7 +37,8 @@ export const useRefinebio = () => { setProcessingDatasets, requestedExperiments, setRequestedExperiments, + acceptedTerms, token, - setToken + createToken } } diff --git a/src/hooks/useToken.js b/src/hooks/useToken.js deleted file mode 100644 index 3985646b..00000000 --- a/src/hooks/useToken.js +++ /dev/null @@ -1,46 +0,0 @@ -import { useRefinebio } from 'hooks/useRefinebio' -import { api } from 'api' - -export const useToken = () => { - const { token: tokenState, setToken: setTokenState } = useRefinebio() - const token = tokenState - const setToken = setTokenState - - const createToken = async () => { - const { id } = await api.token.create() - await api.token.update(id) - setToken(id) - - return id - } - - const getToken = async () => { - const { id } = await api.token.get(token) - setToken(id) - - return id - } - - // clears the existing token and re-generate a new one - // (e.g., in the case of a corrupted token (403)) - const resetToken = async () => { - await setToken(null) - const id = await createToken() - - return id - } - - const validateToken = async () => { - const response = await api.token.get(token) - - return response.is_activated - } - - return { - token, - createToken, - getToken, - resetToken, - validateToken - } -} From 6b50dd35b1c5ba8e3d133be10838fc864802d74d Mon Sep 17 00:00:00 2001 From: Nozomi Ichihara Date: Mon, 2 Dec 2024 17:54:36 -0500 Subject: [PATCH 02/11] (edit) adjust the components (download forms) that utilize the token --- src/components/Compendia/DownloadBlockForm.js | 9 ++--- src/components/Dataset/DatasetReady.js | 24 ++++------- .../Download/DownloadDatasetModal.js | 28 ++++++++----- .../StartProcessingForm/TermsOfUseCheckBox.js | 40 +++++++++---------- .../Download/StartProcessingForm/index.js | 37 +++++++++-------- .../SearchCardAction/DownloadNowModal.js | 28 ++++++++----- 6 files changed, 84 insertions(+), 82 deletions(-) diff --git a/src/components/Compendia/DownloadBlockForm.js b/src/components/Compendia/DownloadBlockForm.js index 40291ade..21b600c7 100644 --- a/src/components/Compendia/DownloadBlockForm.js +++ b/src/components/Compendia/DownloadBlockForm.js @@ -2,8 +2,8 @@ import { useRef, useState, memo } from 'react' import { Box, Heading, Text } from 'grommet' import styled, { css } from 'styled-components' import { useCompendiaContext } from 'hooks/useCompendiaContext' +import { useRefinebio } from 'hooks/useRefinebio' import { useResponsive } from 'hooks/useResponsive' -import { useToken } from 'hooks/useToken' import formatBytes from 'helpers/formatBytes' import formatString from 'helpers/formatString' import fuzzyFilterOnKey from 'helpers/fuzzyFilterOnKey' @@ -55,9 +55,8 @@ const DropdownOption = ({ label, selected, onClick }) => ( export const DownloadBlockForm = () => { const { setResponsive } = useResponsive() - const { validateToken } = useToken() - const hasToken = validateToken() - const [acceptTerms, setAcceptTerms] = useState(hasToken) + const { acceptedTerms } = useRefinebio() + const [acceptTerms, setAcceptTerms] = useState(acceptedTerms) const { compendia, type, goToDownloadCompendium } = useCompendiaContext() const [compendium, setCompendium] = useState(null) const [showOptions, setShowOptions] = useState(false) @@ -176,7 +175,7 @@ export const DownloadBlockForm = () => { /> )} - {!hasToken && ( + {!acceptedTerms && ( { - const { downloadDataset } = useDatasetManager() const { setResponsive } = useResponsive() - const { validateToken } = useToken() - const [acceptedTerms, setAcceptedTerms] = useState(false) + const { downloadDataset } = useDatasetManager() + const { acceptedTerms } = useRefinebio() + const [acceptTerms, setAcceptTerms] = useState(acceptedTerms) const handleDownloadNow = async () => { await downloadDataset(dataset.id, dataset.download_url) gtag.trackDatasetDownload(dataset) } - const getTokenStatus = async () => { - const isActivated = await validateToken() - setAcceptedTerms(isActivated) - } - - // sets acceptedTerms based on the token validity - useEffect(() => { - getTokenStatus() - }, []) - return ( <> @@ -72,7 +62,7 @@ export const DatasetReady = ({ dataset }) => { /> } - onClick={() => setAcceptedTerms(!acceptedTerms)} + onClick={() => setAcceptTerms(!acceptTerms)} /> )} @@ -87,7 +77,7 @@ export const DatasetReady = ({ dataset }) => { >