diff --git a/lib/actions/holder-actions.js b/lib/actions/holder-actions.js new file mode 100644 --- /dev/null +++ b/lib/actions/holder-actions.js @@ -0,0 +1,7 @@ +// @flow + +export const storeEstablishedHolderActionType = 'STORE_ESTABLISHED_HOLDER'; +export type StoreEstablishedHolderPayload = { + +blobHash: string, + +holder: string, +}; diff --git a/lib/actions/upload-actions.js b/lib/actions/upload-actions.js --- a/lib/actions/upload-actions.js +++ b/lib/actions/upload-actions.js @@ -4,6 +4,7 @@ import * as React from 'react'; import uuid from 'uuid'; +import { storeEstablishedHolderActionType } from './holder-actions.js'; import blobService from '../facts/blob-service.js'; import type { CallSingleKeyserverEndpoint } from '../keyserver-conn/call-single-keyserver-endpoint.js'; import { extractKeyserverIDFromIDOptional } from '../keyserver-conn/keyserver-call-utils.js'; @@ -14,6 +15,7 @@ import { IdentityClientContext } from '../shared/identity-client-context.js'; import type { AuthMetadata } from '../shared/identity-client-context.js'; import type { UploadMultimediaResult, Dimensions } from '../types/media-types'; +import type { Dispatch } from '../types/redux-types.js'; import { toBase64URL } from '../utils/base64.js'; import { blobServiceUploadHandler, @@ -25,6 +27,7 @@ generateBlobHolder, } from '../utils/blob-service.js'; import { getMessageForException } from '../utils/errors.js'; +import { useDispatch } from '../utils/redux-utils.js'; import { handleHTTPResponseError, createDefaultHTTPRequestHeaders, @@ -149,10 +152,10 @@ +loop?: boolean, }; -export type BlobServiceUploadResult = { +export type BlobServiceUploadResult = $ReadOnly<{ ...UploadMultimediaResult, - blobHolder: ?string, -}; + +blobHolder: string, +}>; export type BlobServiceUploadAction = (input: { +uploadInput: BlobServiceUploadInput, @@ -164,6 +167,7 @@ const blobServiceUpload = ( callKeyserverEndpoint: CallKeyserverEndpoint, + dispatch: Dispatch, authMetadata: AuthMetadata, ): BlobServiceUploadAction => async input => { @@ -242,6 +246,13 @@ blobInput.type === 'file' ? blobInput.file.type : blobInput.mimeType; if (!maybeKeyserverID) { + dispatch({ + type: storeEstablishedHolderActionType, + payload: { + blobHash, + holder: blobHolder, + }, + }); if (!dimensions) { throw new Error('dimensions are required for non-keyserver uploads'); } @@ -296,6 +307,8 @@ invariant(identityContext, 'Identity context should be set'); const { getAuthMetadata } = identityContext; + const dispatch = useDispatch(); + const blobUploadAction = React.useCallback( ( callSingleKeyserverEndpoint: CallSingleKeyserverEndpoint, @@ -304,11 +317,12 @@ const authMetadata = await getAuthMetadata(); const authenticatedUploadAction = blobServiceUpload( callSingleKeyserverEndpoint, + dispatch, authMetadata, ); return authenticatedUploadAction(input); }, - [getAuthMetadata], + [dispatch, getAuthMetadata], ); return useKeyserverCall(blobUploadAction); } diff --git a/lib/reducers/holder-reducer.js b/lib/reducers/holder-reducer.js new file mode 100644 --- /dev/null +++ b/lib/reducers/holder-reducer.js @@ -0,0 +1,28 @@ +// @flow + +import { storeEstablishedHolderActionType } from '../actions/holder-actions.js'; +import { type HolderStore } from '../types/holder-types.js'; +import type { BaseAction } from '../types/redux-types.js'; + +function reduceHolderStore( + store: HolderStore, + action: BaseAction, +): HolderStore { + if (action.type === storeEstablishedHolderActionType) { + const { blobHash, holder } = action.payload; + return { + ...store, + storedHolders: { + ...store.storedHolders, + [blobHash]: { + ...store.storedHolders[blobHash], + holder, + status: 'ESTABLISHED', + }, + }, + }; + } + return store; +} + +export { reduceHolderStore }; diff --git a/lib/reducers/holder-reducer.test.js b/lib/reducers/holder-reducer.test.js new file mode 100644 --- /dev/null +++ b/lib/reducers/holder-reducer.test.js @@ -0,0 +1,23 @@ +// @flow + +import { reduceHolderStore } from './holder-reducer.js'; +import { storeEstablishedHolderActionType } from '../actions/holder-actions.js'; +import { type HolderStore } from '../types/holder-types.js'; +import type { BaseAction } from '../types/redux-types.js'; + +describe('reduceHolderStore', () => { + it('STORE_ESTABLISHED_HOLDER', () => { + const store: HolderStore = { + storedHolders: {}, + }; + + const action: BaseAction = { + type: storeEstablishedHolderActionType, + payload: { blobHash: 'foo', holder: 'bar' }, + }; + + expect(reduceHolderStore(store, action).storedHolders).toStrictEqual({ + foo: { holder: 'bar', status: 'ESTABLISHED' }, + }); + }); +}); diff --git a/lib/reducers/master-reducer.js b/lib/reducers/master-reducer.js --- a/lib/reducers/master-reducer.js +++ b/lib/reducers/master-reducer.js @@ -11,6 +11,7 @@ import { reduceDraftStore } from './draft-reducer.js'; import reduceEnabledApps from './enabled-apps-reducer.js'; import { reduceEntryInfos } from './entry-reducer.js'; +import { reduceHolderStore } from './holder-reducer.js'; import { reduceIntegrityStore } from './integrity-reducer.js'; import reduceInviteLinks from './invite-links-reducer.js'; import reduceKeyserverStore from './keyserver-reducer.js'; @@ -252,6 +253,7 @@ state.queuedDMOperations, action, ), + holderStore: reduceHolderStore(state.holderStore, action), }, storeOperations, }; diff --git a/lib/types/redux-types.js b/lib/types/redux-types.js --- a/lib/types/redux-types.js +++ b/lib/types/redux-types.js @@ -164,6 +164,7 @@ SetDeviceTokenActionPayload, SetDeviceTokenStartedPayload, } from '../actions/device-actions.js'; +import type { StoreEstablishedHolderPayload } from '../actions/holder-actions.js'; import type { UpdateConnectionStatusPayload, SetLateResponsePayload, @@ -1608,6 +1609,10 @@ | { +type: 'CLEAR_QUEUED_MEMBERSHIP_DM_OPS', +payload: ClearQueuedMembershipDMOpsPayload, + } + | { + +type: 'STORE_ESTABLISHED_HOLDER', + +payload: StoreEstablishedHolderPayload, }, }>;