fix(server): sign up emails sent out twice

This commit is contained in:
Kristaps Fabians Geikins
2024-10-23 15:16:32 +03:00
parent def74d1029
commit 34069a47ec
3 changed files with 18 additions and 60 deletions
+5 -40
View File
@@ -1,24 +1,11 @@
/* istanbul ignore file */
import { db } from '@/db/knex'
import { moduleLogger } from '@/logging/logging'
import { UsersEmitter } from '@/modules/core/events/usersEmitter'
import { getServerInfoFactory } from '@/modules/core/repositories/server'
import { findPrimaryEmailForUserFactory } from '@/modules/core/repositories/userEmails'
import { getUserFactory } from '@/modules/core/repositories/users'
import { deleteOldAndInsertNewVerificationFactory } from '@/modules/emails/repositories'
import { renderEmail } from '@/modules/emails/services/emailRendering'
import * as SendingService from '@/modules/emails/services/sending'
import {
initializeVerificationOnRegistrationFactory,
requestEmailVerificationFactory
} from '@/modules/emails/services/verification/request'
import { initializeTransporter } from '@/modules/emails/utils/transporter'
import { Optional, SpeckleModule } from '@/modules/shared/helpers/typeHelper'
let quitVerificationListeners: Optional<() => void> = undefined
import { SpeckleModule } from '@/modules/shared/helpers/typeHelper'
const emailsModule: SpeckleModule = {
init: async (app, isInitial) => {
init: async (app) => {
moduleLogger.info('📧 Init emails module')
// init transporter
@@ -26,34 +13,12 @@ const emailsModule: SpeckleModule = {
// init rest api
;(await import('./rest')).default(app)
// init event listeners
if (isInitial) {
const getUser = getUserFactory({ db })
const initializeVerificationOnRegistration =
initializeVerificationOnRegistrationFactory({
userEmitterListener: UsersEmitter.listen,
requestEmailVerification: requestEmailVerificationFactory({
getUser,
getServerInfo: getServerInfoFactory({ db }),
deleteOldAndInsertNewVerification: deleteOldAndInsertNewVerificationFactory(
{ db }
),
findPrimaryEmailForUser: findPrimaryEmailForUserFactory({ db }),
sendEmail: SendingService.sendEmail,
renderEmail
})
})
quitVerificationListeners = initializeVerificationOnRegistration()
}
},
shutdown() {
quitVerificationListeners?.()
}
}
/**
* @deprecated Use `sendEmail` from `@/modules/emails/services/sending` instead
*/
async function sendEmail({
from,
to,
@@ -3,7 +3,6 @@ import {
FindPrimaryEmailForUser
} from '@/modules/core/domain/userEmails/operations'
import { UserEmail } from '@/modules/core/domain/userEmails/types'
import { UsersEmitter, UsersEvents } from '@/modules/core/events/usersEmitter'
import { getEmailVerificationFinalizationRoute } from '@/modules/core/helpers/routeHelper'
import { ServerInfo, UserRecord } from '@/modules/core/helpers/types'
import { EmailVerificationRequestError } from '@/modules/emails/errors'
@@ -184,25 +183,11 @@ export const requestEmailVerificationFactory =
await sendVerificationEmailFactory(deps)(newVerificationState)
}
/**
* Listen for user:created events and trigger email verification initialization
*/
export const initializeVerificationOnRegistrationFactory =
(deps: {
userEmitterListener: typeof UsersEmitter.listen
requestEmailVerification: RequestEmailVerification
}) =>
() => {
return deps.userEmitterListener(UsersEvents.Created, async ({ user }) => {
// user might already be verified because of registration through an external identity provider
if (user.verified) return
await deps.requestEmailVerification(user.id)
})
}
type RequestNewEmailVerificationDeps = CreateNewEmailVerificationFactoryDeps
/**
* Request email verification for email with specified ID
*/
export const requestNewEmailVerificationFactory =
(
deps: RequestNewEmailVerificationDeps & SendVerificationEmailDeps
@@ -70,10 +70,15 @@ describe('Email verifications @emails', () => {
await cleanup()
})
it('sends out verification email immediatelly after new account creation', async () => {
afterEach(async () => {
mailerMock.resetMockedFunctions()
})
it('sends out 1 verification email immediately after new account creation', async () => {
const sendEmailInvocations = mailerMock.hijackFunction(
'sendEmail',
async () => true
async () => true,
{ times: 2 }
)
const newGuy: BasicTestUser = {
@@ -91,6 +96,9 @@ describe('Email verifications @emails', () => {
const verification = await getPendingToken({ email: newGuy.email })
expect(verification).to.be.ok
// There should be only 1 email!
expect(sendEmailInvocations.args.length).to.eq(1)
})
describe('when authenticated', () => {