diff --git a/shared/src/proxies/users/verifyUserPendingEmailProxy.ts b/shared/src/proxies/users/verifyUserPendingEmailProxy.ts index 6908b54dfb9..4d42e34b8d4 100644 --- a/shared/src/proxies/users/verifyUserPendingEmailProxy.ts +++ b/shared/src/proxies/users/verifyUserPendingEmailProxy.ts @@ -10,14 +10,13 @@ import { put } from '../requests'; */ export const verifyUserPendingEmailInteractor = ( applicationContext, - { clientConnectionId, token }: { clientConnectionId: string; token: string }, + { token }: { token: string }, ): Promise => { return put({ applicationContext, body: { - clientConnectionId, token, }, - endpoint: '/async/users/verify-email', + endpoint: '/users/verify-email', }); }; diff --git a/web-api/src/app.ts b/web-api/src/app.ts index f4c826e73a5..a0fe5cc6a60 100644 --- a/web-api/src/app.ts +++ b/web-api/src/app.ts @@ -1034,10 +1034,7 @@ app.delete( lambdaWrapper(getUserPendingEmailStatusLambda), ); app.put('/users/pending-email', lambdaWrapper(updateUserPendingEmailLambda)); - app.put( - '/async/users/verify-email', - lambdaWrapper(verifyUserPendingEmailLambda, { isAsync: true }), - ); + app.put('/users/verify-email', lambdaWrapper(verifyUserPendingEmailLambda)); app.get( '/users/email-availability', lambdaWrapper(checkEmailAvailabilityLambda), diff --git a/web-api/src/business/useCases/user/verifyUserPendingEmailInteractor.ts b/web-api/src/business/useCases/user/verifyUserPendingEmailInteractor.ts index ee174e5b737..b545faec780 100644 --- a/web-api/src/business/useCases/user/verifyUserPendingEmailInteractor.ts +++ b/web-api/src/business/useCases/user/verifyUserPendingEmailInteractor.ts @@ -4,6 +4,7 @@ import { isAuthorized, } from '../../../../../shared/src/authorization/authorizationClientService'; import { ServerApplicationContext } from '@web-api/applicationContext'; +import { UnauthorizedError } from '@web-api/errors/errors'; import { UnknownAuthUser } from '@shared/business/entities/authUser/AuthUser'; import { calculateDifferenceInHours, @@ -29,21 +30,11 @@ export const userTokenHasExpired = ( export const verifyUserPendingEmailInteractor = async ( applicationContext: ServerApplicationContext, - { clientConnectionId, token }: { token: string; clientConnectionId: string }, + { token }: { token: string }, authorizedUser: UnknownAuthUser, ): Promise => { if (!isAuthorized(authorizedUser, ROLE_PERMISSIONS.EMAIL_MANAGEMENT)) { - return await applicationContext - .getNotificationGateway() - .sendNotificationToUser({ - applicationContext, - clientConnectionId, - message: { - action: 'set_verify_email_notification', - message: 'Unauthorized to manage emails', - }, - userId: (authorizedUser as UnknownAuthUser)?.userId!, - }); + throw new UnauthorizedError('Unauthorized to manage emails.'); } const user = await applicationContext @@ -61,35 +52,14 @@ export const verifyUserPendingEmailInteractor = async ( 'Unable to verify pending email, either the user clicked the verify link twice or their verification token did not match', { email: authorizedUser.email }, ); - return await applicationContext - .getNotificationGateway() - .sendNotificationToUser({ - applicationContext, - clientConnectionId, - message: { - action: 'set_verify_email_notification', - message: 'Tokens do not match', - }, - userId: user.userId, - }); + throw new UnauthorizedError('Tokens do not match'); } if (userTokenHasExpired(user.pendingEmailVerificationTokenTimestamp)) { applicationContext.logger.info('Pending email verification link expired', { email: authorizedUser.email, }); - return await applicationContext - .getNotificationGateway() - .sendNotificationToUser({ - applicationContext, - clientConnectionId, - message: { - action: 'set_verify_email_notification', - message: 'Link has expired', - messageType: 'expiredToken', - }, - userId: user.userId, - }); + throw new UnauthorizedError('Link has expired'); } const isEmailAvailable = await applicationContext @@ -100,17 +70,7 @@ export const verifyUserPendingEmailInteractor = async ( }); if (!isEmailAvailable) { - return await applicationContext - .getNotificationGateway() - .sendNotificationToUser({ - applicationContext, - clientConnectionId, - message: { - action: 'set_verify_email_notification', - message: 'Email is not available', - }, - userId: user.userId, - }); + throw new Error('Email is not available'); } const { updatedUser } = await updateUserPendingEmailRecord( @@ -170,17 +130,4 @@ export const verifyUserPendingEmailInteractor = async ( user: updatedUser, }); } - - return await applicationContext - .getNotificationGateway() - .sendNotificationToUser({ - applicationContext, - clientConnectionId, - message: { - action: 'set_verify_email_notification', - message: 'Email has been updated', - messageType: 'success', - }, - userId: user.userId, - }); }; diff --git a/web-client/src/presenter/actions/setInitialVerifyAlertMessageAction.ts b/web-client/src/presenter/actions/setInitialVerifyAlertMessageAction.ts new file mode 100644 index 00000000000..75a5658d7b6 --- /dev/null +++ b/web-client/src/presenter/actions/setInitialVerifyAlertMessageAction.ts @@ -0,0 +1,8 @@ +export const setInitialVerifyAlertMessageAction = () => { + return { + alertInfo: { + message: 'DAWSON is updating your email. Please wait.', + title: 'Updating email address', + }, + }; +}; diff --git a/web-client/src/presenter/actions/verifyUserPendingEmailAction.tsx b/web-client/src/presenter/actions/verifyUserPendingEmailAction.tsx index 50413dc18df..ecb80c58d06 100644 --- a/web-client/src/presenter/actions/verifyUserPendingEmailAction.tsx +++ b/web-client/src/presenter/actions/verifyUserPendingEmailAction.tsx @@ -1,12 +1,6 @@ import { TROUBLESHOOTING_INFO } from '@shared/business/entities/EntityConstants'; -import { state } from '@web-client/presenter/app.cerebral'; import React from 'react'; -const successAlertMessage = { - message: 'Your email address is verified. You can now log in to DAWSON.', - title: 'Email address verified', -}; - const expiredTokenAlertError = { message: ( <> @@ -17,6 +11,21 @@ const expiredTokenAlertError = { title: 'Verification email link expired', }; +const requestTimedOutAlertError = { + message: ( + <> + Request timed out. This potentially means another process is currently + updating this user. Your request cannot be completed. Please try to log + in. If you’re still having trouble, contact{' '} + + {TROUBLESHOOTING_INFO.APP_SUPPORT_EMAIL} + + . + + ), + title: 'Request Timed Out', +}; + export const genericAlertError = { message: ( <> @@ -31,51 +40,41 @@ export const genericAlertError = { title: 'Unable to complete your request', }; -type VerifyEmailNotificationType = 'success' | 'expiredToken'; - -const alertDictionary: { [key in VerifyEmailNotificationType]: any } = { - expiredToken: expiredTokenAlertError, - success: successAlertMessage, -}; - -const alertKeyDictionary: { [key in VerifyEmailNotificationType]: any } = { - expiredToken: 'alertWarning', - success: 'alertSuccess', -}; - export const verifyUserPendingEmailAction = async ({ applicationContext, - get, + path, props, }: ActionProps<{ token: string }>) => { - const clientConnectionId = get(state.clientConnectionId); const { token } = props; - await applicationContext - .getUseCases() - .verifyUserPendingEmailInteractor(applicationContext, { - clientConnectionId, - token, - }); + try { + await applicationContext + .getUseCases() + .verifyUserPendingEmailInteractor(applicationContext, { + token, + }); - return { - alertInfo: { - message: 'DAWSON is updating your email. Please wait.', - title: 'Updating email address', - }, - }; -}; - -export const setVerifyUserPendingEmailNotificationAction = ({ - props, - store, -}: ActionProps<{ messageType: VerifyEmailNotificationType }>) => { - const { messageType } = props; - store.unset(state.alertWarning); - store.unset(state.alertSuccess); - store.unset(state.alertInfo); + return path.success({ + alertSuccess: { + message: + 'Your email address is verified. You can now log in to DAWSON.', + title: 'Email address verified', + }, + }); + } catch (e: any) { + if (e.message === 'Link has expired') { + return path.error({ + alertError: expiredTokenAlertError, + }); + } + if (e.message === 'Endpoint request timed out') { + return path.error({ + alertError: requestTimedOutAlertError, + }); + } - const KEY = alertKeyDictionary[messageType] || 'alertWarning'; - const MESSAGE = alertDictionary[messageType] || genericAlertError; - store.set(state[KEY], MESSAGE); + return path.error({ + alertError: genericAlertError, + }); + } }; diff --git a/web-client/src/presenter/presenter.ts b/web-client/src/presenter/presenter.ts index 133a3e45b69..c93b7c4bf79 100644 --- a/web-client/src/presenter/presenter.ts +++ b/web-client/src/presenter/presenter.ts @@ -413,7 +413,6 @@ import { setSelectedMessagesSequence } from './sequences/setSelectedMessagesSequ import { setTrialSessionCalendarErrorSequence } from '@web-client/presenter/sequences/setTrialSessionCalendarErrorSequence'; import { setTrialSessionCalendarSequence } from './sequences/setTrialSessionCalendarSequence'; import { setTrialSessionsFiltersSequence } from '@web-client/presenter/sequences/setTrialSessionsFiltersSequence'; -import { setVerifyEmailNotificationSequence } from '@web-client/presenter/sequences/setVerifyEmailNotificationSequence'; import { setViewerCorrespondenceToDisplaySequence } from './sequences/setViewerCorrespondenceToDisplaySequence'; import { setViewerDocumentToDisplaySequence } from './sequences/setViewerDocumentToDisplaySequence'; import { setViewerDraftDocumentToDisplaySequence } from './sequences/setViewerDraftDocumentToDisplaySequence'; @@ -1272,7 +1271,6 @@ export const presenterSequences = { setTrialSessionCalendarErrorSequence, setTrialSessionCalendarSequence, setTrialSessionsFiltersSequence, - setVerifyEmailNotificationSequence, setViewerCorrespondenceToDisplaySequence: setViewerCorrespondenceToDisplaySequence as unknown as Function, setViewerDocumentToDisplaySequence: diff --git a/web-client/src/presenter/sequences/gotoVerifyEmailSequence.ts b/web-client/src/presenter/sequences/gotoVerifyEmailSequence.ts index 1fb69af8dfb..e00d9d76325 100644 --- a/web-client/src/presenter/sequences/gotoVerifyEmailSequence.ts +++ b/web-client/src/presenter/sequences/gotoVerifyEmailSequence.ts @@ -1,18 +1,19 @@ import { clearUserAction } from '../actions/clearUserAction'; import { navigateToLoginAction } from '@web-client/presenter/actions/Login/navigateToLoginAction'; -import { refreshTokenAction } from '@web-client/presenter/actions/Login/refreshTokenAction'; +import { setAlertErrorAction } from '@web-client/presenter/actions/setAlertErrorAction'; import { setAlertInfoAction } from '@web-client/presenter/actions/setAlertInfoAction'; -import { setNotLoggedInVerificationAction } from '@web-client/presenter/actions/setNotLoggedInVerificationAction'; -import { startWebSocketConnectionSequenceDecorator } from '@web-client/presenter/utilities/startWebSocketConnectionSequenceDecorator'; +import { setAlertSuccessAction } from '@web-client/presenter/actions/setAlertSuccessAction'; +import { setInitialVerifyAlertMessageAction } from '@web-client/presenter/actions/setInitialVerifyAlertMessageAction'; import { verifyUserPendingEmailAction } from '../actions/verifyUserPendingEmailAction'; -export const gotoVerifyEmailSequence = - startWebSocketConnectionSequenceDecorator([ - refreshTokenAction, - { - userIsLoggedIn: [verifyUserPendingEmailAction, setAlertInfoAction], - userIsNotLoggedIn: [setNotLoggedInVerificationAction], - }, - clearUserAction, - navigateToLoginAction, - ]) as unknown as (props: { token: string }) => void; +export const gotoVerifyEmailSequence = [ + setInitialVerifyAlertMessageAction, + setAlertInfoAction, + navigateToLoginAction, + verifyUserPendingEmailAction, + { + error: [setAlertErrorAction], + success: [setAlertSuccessAction], + }, + clearUserAction, +] as unknown as (props: { token: string }) => void; diff --git a/web-client/src/presenter/sequences/setVerifyEmailNotificationSequence.ts b/web-client/src/presenter/sequences/setVerifyEmailNotificationSequence.ts deleted file mode 100644 index b64370cd54e..00000000000 --- a/web-client/src/presenter/sequences/setVerifyEmailNotificationSequence.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { setVerifyUserPendingEmailNotificationAction } from '@web-client/presenter/actions/verifyUserPendingEmailAction'; - -export const setVerifyEmailNotificationSequence = [ - setVerifyUserPendingEmailNotificationAction, -] as unknown as (props: { messageType: string }) => void; diff --git a/web-client/src/providers/socketRouter.ts b/web-client/src/providers/socketRouter.ts index 8a925dc021b..2fe79a5de46 100644 --- a/web-client/src/providers/socketRouter.ts +++ b/web-client/src/providers/socketRouter.ts @@ -151,9 +151,6 @@ export const socketRouter = (app, onMessageCallbackFn?) => { case 'download_csv_file': await app.getSequence('downloadCsvFileSequence')(message); break; - case 'set_verify_email_notification': - await app.getSequence('setVerifyEmailNotificationSequence')(message); - break; } (onMessageCallbackFn || noop)(message);