diff --git a/keyserver/src/responders/redux-state-responders.js b/keyserver/src/responders/redux-state-responders.js --- a/keyserver/src/responders/redux-state-responders.js +++ b/keyserver/src/responders/redux-state-responders.js @@ -8,6 +8,7 @@ import { freshMessageStore } from 'lib/reducers/message-reducer.js'; import { mostRecentlyReadThread } from 'lib/selectors/thread-selectors.js'; import { mostRecentMessageTimestamp } from 'lib/shared/message-utils.js'; +import { isStaff } from 'lib/shared/staff-utils.js'; import { threadHasPermission, threadIsPending, @@ -29,6 +30,7 @@ userInfosValidator, } from 'lib/types/user-types.js'; import { currentDateInTimeZone } from 'lib/utils/date-utils.js'; +import { isDev } from 'lib/utils/dev-utils.js'; import { ServerError } from 'lib/utils/errors.js'; import { promiseAll } from 'lib/utils/promises.js'; import { urlInfoValidator } from 'lib/utils/url-utils.js'; @@ -89,7 +91,9 @@ viewer: Viewer, request: InitialReduxStateRequest, ): Promise { - const { urlInfo } = request; + const { urlInfo, excludedData } = request; + const useDatabase = isDev || isStaff(viewer.userID); + const hasNotAcknowledgedPoliciesPromise = hasAnyNotAcknowledgedPolicies( viewer.id, baseLegalPolicies, @@ -153,6 +157,9 @@ })(); const threadStorePromise = (async () => { + if (excludedData.threadStore && useDatabase) { + return { threadInfos: {} }; + } const [{ threadInfos }, hasNotAcknowledgedPolicies] = await Promise.all([ threadInfoPromise, hasNotAcknowledgedPoliciesPromise, diff --git a/web/redux/initial-state-gate.js b/web/redux/initial-state-gate.js --- a/web/redux/initial-state-gate.js +++ b/web/redux/initial-state-gate.js @@ -6,7 +6,12 @@ import type { Persistor } from 'redux-persist/es/types'; import { setClientDBStoreActionType } from 'lib/actions/client-db-store-actions.js'; +import type { ThreadStoreOperation } from 'lib/ops/thread-store-ops.js'; +import { isStaff } from 'lib/shared/staff-utils.js'; +import type { RawThreadInfo } from 'lib/types/thread-types.js'; +import { isDev } from 'lib/utils/dev-utils.js'; import { convertIDToNewSchema } from 'lib/utils/migration-utils.js'; +import { entries } from 'lib/utils/objects.js'; import { infoFromURL } from 'lib/utils/url-utils.js'; import { ashoatKeyserverID } from 'lib/utils/validation-utils.js'; @@ -15,13 +20,17 @@ useGetInitialReduxState, } from './action-types.js'; import { useSelector } from './redux-utils.js'; -import { getClientStore } from '../database/utils/store.js'; +import { + getClientStore, + processDBStoreOperations, +} from '../database/utils/store.js'; import Loading from '../loading.react.js'; type Props = { +persistor: Persistor, +children: React.Node, }; + function InitialReduxStateGate(props: Props): React.Node { const { children, persistor } = props; const callGetInitialReduxState = useGetInitialReduxState(); @@ -49,23 +58,57 @@ thread: convertIDToNewSchema(urlInfo.thread, ashoatKeyserverID), }; } - const clientDBStore = await getClientStore(); const payload = await callGetInitialReduxState({ urlInfo, - excludedData: { threadStore: false }, + excludedData: { threadStore: !!clientDBStore.threadStore }, }); const currentLoggedInUserID = payload.currentUserInfo?.anonymous ? undefined : payload.currentUserInfo?.id; + const useDatabase = + currentLoggedInUserID && (isDev || isStaff(currentLoggedInUserID)); + + if (!currentLoggedInUserID || !useDatabase) { + dispatch({ type: setInitialReduxState, payload }); + return; + } - if (currentLoggedInUserID) { + if (clientDBStore.threadStore) { + // If there is data in the DB, populate the store dispatch({ type: setClientDBStoreActionType, payload: clientDBStore, }); + const { threadStore, ...rest } = payload; + dispatch({ type: setInitialReduxState, payload: rest }); + return; + } else { + // When there is no data in the DB, it's necessary to migrate data + // from the keyserver payload to the DB + const { + threadStore: { threadInfos }, + } = payload; + + const threadStoreOperations: ThreadStoreOperation[] = entries( + threadInfos, + ).map(([id, threadInfo]: [string, RawThreadInfo]) => ({ + type: 'replace', + payload: { + id, + threadInfo, + }, + })); + + await processDBStoreOperations({ + threadStoreOperations, + draftStoreOperations: [], + messageStoreOperations: [], + reportStoreOperations: [], + userStoreOperations: [], + }); } dispatch({ type: setInitialReduxState, payload }); } catch (err) {