move EmailBuilder out to separat branch

This commit is contained in:
einhornimmond 2023-11-13 17:49:27 +01:00
parent 7a4604f173
commit 634a7a7b8b
7 changed files with 224 additions and 383 deletions

View File

@ -1,235 +0,0 @@
import { Contribution } from '@entity/Contribution'
import { User } from '@entity/User'
import { CONFIG } from '@/config'
import { LogError } from '@/server/LogError'
import { TimeDuration } from '@/util/time'
import { decimalSeparatorByLanguage, resetInterface } from '@/util/utilities'
import { sendEmailTranslated } from './sendEmailTranslated'
import { Decimal } from 'decimal.js-light'
export interface EmailLocals {
firstName: string
lastName: string
locale: string
supportEmail: string
communityURL: string
senderFirstName?: string
senderLastName?: string
senderEmail?: string
contributionMemo?: string
contributionAmount?: string
overviewURL?: string
activationLink?: string
timeDurationObject?: TimeDuration
resendLink?: string
resetLink?: string
transactionMemo?: string
transactionAmount?: string
contributionMemoUpdated?: string
[key: string]: string | TimeDuration | undefined
}
export enum EmailType {
NONE = 'none',
ACCOUNT_ACTIVATION = 'accountActivation',
ACCOUNT_MULTI_REGISTRATION = 'accountMultiRegistration',
ADDED_CONTRIBUTION_MESSAGE = 'addedContributionMessage',
CONTRIBUTION_CONFIRMED = 'contributionConfirmed',
CONTRIBUTION_DELETED = 'contributionDeleted',
CONTRIBUTION_DENIED = 'contributionDenied',
CONTRIBUTION_CHANGED_BY_MODERATOR = 'contributionChangedByModerator',
RESET_PASSWORD = 'resetPassword',
TRANSACTION_LINK_REDEEMED = 'transactionLinkRedeemed',
TRANSACTION_RECEIVED = 'transactionReceived',
}
// eslint-disable-next-line @typescript-eslint/no-extraneous-class
export class EmailBuilder {
private receiver: { to: string }
private type: EmailType
private locals: EmailLocals
// https://refactoring.guru/design-patterns/builder/typescript/example
/**
* A fresh builder instance should contain a blank product object, which is
* used in further assembly.
*/
constructor() {
this.reset()
}
public reset(): void {
this.receiver.to = ''
this.type = EmailType.NONE
this.locals = resetInterface(this.locals)
}
protected setLocalsFromConfig(): void {
this.locals.overviewURL = CONFIG.EMAIL_LINK_OVERVIEW
this.locals.supportEmail = CONFIG.COMMUNITY_SUPPORT_MAIL
this.locals.communityURL = CONFIG.COMMUNITY_URL
switch (this.type) {
case EmailType.ACCOUNT_ACTIVATION:
case EmailType.ACCOUNT_MULTI_REGISTRATION:
case EmailType.RESET_PASSWORD:
this.locals.resendLink = CONFIG.EMAIL_LINK_FORGOTPASSWORD
}
}
protected checkIfFieldsSet(names: string[]): void {
for (const name of names) {
// eslint-disable-next-line security/detect-object-injection
if (!this.locals[name]) {
throw new LogError(`missing field with ${name}`)
}
}
}
/**
* check if non default fields a set for type
*/
protected checkRequiredFields(): void {
switch (this.type) {
case EmailType.NONE:
throw new LogError('please call setType before to set email type')
case EmailType.ACCOUNT_ACTIVATION:
this.checkIfFieldsSet(['activationLink', 'timeDurationObject', 'resendLink'])
break
case EmailType.ACCOUNT_MULTI_REGISTRATION:
this.checkIfFieldsSet(['resendLink'])
break
// CONTRIBUTION_CONFIRMED has same required fields as ADDED_CONTRIBUTION_MESSAGE plus contributionAmount
case EmailType.CONTRIBUTION_CONFIRMED:
this.checkIfFieldsSet(['contributionAmount'])
// eslint-disable-next-line no-fallthrough
case EmailType.ADDED_CONTRIBUTION_MESSAGE:
case EmailType.CONTRIBUTION_DELETED:
case EmailType.CONTRIBUTION_DENIED:
this.checkIfFieldsSet(['senderFirstName', 'senderLastName', 'contributionMemo'])
break
case EmailType.CONTRIBUTION_CHANGED_BY_MODERATOR:
this.checkIfFieldsSet([
'contributionMemoUpdated',
'senderFirstName',
'senderLastName',
'contributionMemo',
])
break
case EmailType.RESET_PASSWORD:
this.checkIfFieldsSet(['resetLink', 'timeDurationObject', 'resendLink'])
break
// TRANSACTION_LINK_REDEEMED has same required fields as TRANSACTION_RECEIVED plus transactionMemo
case EmailType.TRANSACTION_LINK_REDEEMED:
this.checkIfFieldsSet(['transactionMemo'])
// eslint-disable-next-line no-fallthrough
case EmailType.TRANSACTION_RECEIVED:
this.checkIfFieldsSet([
'senderFirstName',
'senderLastName',
'senderEmail',
'transactionAmount',
])
break
}
}
/**
* Concrete Builders are supposed to provide their own methods for
* retrieving results. That's because various types of builders may create
* entirely different products that don't follow the same interface.
* Therefore, such methods cannot be declared in the base Builder interface
* (at least in a statically typed programming language).
*
* Usually, after returning the end result to the client, a builder instance
* is expected to be ready to start producing another product. That's why
* it's a usual practice to call the reset method at the end of the
* `getProduct` method body. However, this behavior is not mandatory, and
* you can make your builders wait for an explicit reset call from the
* client code before disposing of the previous result.
*/
public sendEmail(): Promise<Record<string, unknown> | boolean | null> {
this.setLocalsFromConfig()
// will throw if a field is missing
this.checkRequiredFields()
const result = sendEmailTranslated({
receiver: this.receiver,
template: this.type.toString(),
locals: this.locals,
})
this.reset()
return result
}
public setRecipient(recipient: User): this {
this.receiver.to = `${recipient.firstName} ${recipient.lastName} <${recipient.emailContact.email}>`
this.locals.firstName = recipient.firstName
this.locals.lastName = recipient.lastName
this.locals.locale = recipient.language
return this
}
public setSender(sender: User): this {
this.locals.senderEmail = sender.emailContact.email
this.locals.senderFirstName = sender.firstName
this.locals.senderLastName = sender.lastName
return this
}
public setType(type: EmailType): this {
this.type = type
return this
}
public setResetLink(resetLink: string): this {
this.locals.resentLink = resetLink
return this
}
public setContribution(contribution: Contribution): this {
this.locals.contributionMemo = contribution.memo
if (!this.locals.locale || this.locals.locale === '') {
throw new LogError('missing locale please call setRecipient before')
}
this.locals.contributionAmount = decimalSeparatorByLanguage(
contribution.amount,
this.locals.locale,
)
return this
}
public setUpdatedContributionMemo(updatedMemo: string): this {
this.locals.contributionMemoUpdated = updatedMemo
return this
}
public setTransaction(amount: Decimal, memo: string): this {
this.setTransactionMemo(memo)
this.setTransactionAmount(amount)
return this
}
public setTransactionAmount(amount: Decimal): this {
if (!this.locals.locale || this.locals.locale === '') {
throw new LogError('missing locale please call setRecipient before')
}
this.locals.transactionAmount = decimalSeparatorByLanguage(amount, this.locals.locale)
return this
}
public setTransactionMemo(memo: string): this {
this.locals.transactionMemo = memo
return this
}
public setActivationLink(activationLink: string): this {
this.locals.activationLink = activationLink
return this
}
public setTimeDurationObject(timeDurationObject: TimeDuration): this {
this.locals.timeDurationObject = timeDurationObject
return this
}
}

View File

@ -2,17 +2,43 @@
/* eslint-disable @typescript-eslint/no-unsafe-return */
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
import { Connection } from '@dbTools/typeorm'
import { ApolloServerTestClient } from 'apollo-server-testing'
import { Decimal } from 'decimal.js-light'
import { testEnvironment } from '@test/helpers'
import { logger, i18n as localization } from '@test/testSetup'
import { CONFIG } from '@/config'
import { sendEmailTranslated } from './sendEmailTranslated'
import { User } from '@entity/User'
import { UserContact } from '@entity/UserContact'
import { Contribution } from '@entity/Contribution'
import { EmailBuilder, EmailType } from './Email.builder'
import {
sendAddedContributionMessageEmail,
sendAccountActivationEmail,
sendAccountMultiRegistrationEmail,
sendContributionConfirmedEmail,
sendContributionDeniedEmail,
sendContributionDeletedEmail,
sendResetPasswordEmail,
sendTransactionLinkRedeemedEmail,
sendTransactionReceivedEmail,
} from './sendEmailVariants'
let con: Connection
let testEnv: {
mutate: ApolloServerTestClient['mutate']
query: ApolloServerTestClient['query']
con: Connection
}
beforeAll(async () => {
testEnv = await testEnvironment(logger, localization)
con = testEnv.con
})
afterAll(async () => {
await con.close()
})
jest.mock('./sendEmailTranslated', () => {
const originalModule = jest.requireActual('./sendEmailTranslated')
@ -25,34 +51,18 @@ jest.mock('./sendEmailTranslated', () => {
describe('sendEmailVariants', () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let result: any
const recipientUser = User.create()
recipientUser.firstName = 'Peter'
recipientUser.lastName = 'Lustig'
recipientUser.language = 'en'
const recipientUserContact = UserContact.create()
recipientUserContact.email = 'peter@lustig.de'
recipientUser.emailContact = recipientUserContact
const senderUser = User.create()
senderUser.firstName = 'Bibi'
senderUser.lastName = 'Bloxberg'
const senderUserContact = UserContact.create()
senderUserContact.email = 'bibi@bloxberg.de'
const contribution = Contribution.create()
contribution.memo = 'My contribution.'
contribution.amount = new Decimal(23.54)
const emailBuilder = new EmailBuilder()
describe('sendAddedContributionMessageEmail', () => {
beforeAll(async () => {
result = await emailBuilder
.setSender(senderUser)
.setRecipient(recipientUser)
.setContribution(contribution)
.setType(EmailType.ADDED_CONTRIBUTION_MESSAGE)
.sendEmail()
result = await sendAddedContributionMessageEmail({
firstName: 'Peter',
lastName: 'Lustig',
email: 'peter@lustig.de',
language: 'en',
senderFirstName: 'Bibi',
senderLastName: 'Bloxberg',
contributionMemo: 'My contribution.',
})
})
describe('calls "sendEmailTranslated"', () => {
@ -104,13 +114,14 @@ describe('sendEmailVariants', () => {
describe('sendAccountActivationEmail', () => {
beforeAll(async () => {
result = await emailBuilder
.setRecipient(recipientUser)
.setSender(senderUser)
.setActivationLink('http://localhost/checkEmail/6627633878930542284')
.setTimeDurationObject({ hours: 23, minutes: 30 })
.setType(EmailType.ACCOUNT_ACTIVATION)
.sendEmail()
result = await sendAccountActivationEmail({
firstName: 'Peter',
lastName: 'Lustig',
email: 'peter@lustig.de',
language: 'en',
activationLink: 'http://localhost/checkEmail/6627633878930542284',
timeDurationObject: { hours: 23, minutes: 30 },
})
})
describe('calls "sendEmailTranslated"', () => {
@ -161,10 +172,12 @@ describe('sendEmailVariants', () => {
describe('sendAccountMultiRegistrationEmail', () => {
beforeAll(async () => {
result = await emailBuilder
.setRecipient(recipientUser)
.setType(EmailType.ACCOUNT_MULTI_REGISTRATION)
.sendEmail()
result = await sendAccountMultiRegistrationEmail({
firstName: 'Peter',
lastName: 'Lustig',
email: 'peter@lustig.de',
language: 'en',
})
})
describe('calls "sendEmailTranslated"', () => {
@ -213,12 +226,16 @@ describe('sendEmailVariants', () => {
describe('sendContributionConfirmedEmail', () => {
beforeAll(async () => {
result = await emailBuilder
.setRecipient(recipientUser)
.setSender(senderUser)
.setContribution(contribution)
.setType(EmailType.CONTRIBUTION_CONFIRMED)
.sendEmail()
result = await sendContributionConfirmedEmail({
firstName: 'Peter',
lastName: 'Lustig',
email: 'peter@lustig.de',
language: 'en',
senderFirstName: 'Bibi',
senderLastName: 'Bloxberg',
contributionMemo: 'My contribution.',
contributionAmount: new Decimal(23.54),
})
})
describe('calls "sendEmailTranslated"', () => {
@ -271,12 +288,15 @@ describe('sendEmailVariants', () => {
describe('sendContributionDeniedEmail', () => {
beforeAll(async () => {
result = await emailBuilder
.setRecipient(recipientUser)
.setSender(senderUser)
.setContribution(contribution)
.setType(EmailType.CONTRIBUTION_DENIED)
.sendEmail()
result = await sendContributionDeniedEmail({
firstName: 'Peter',
lastName: 'Lustig',
email: 'peter@lustig.de',
language: 'en',
senderFirstName: 'Bibi',
senderLastName: 'Bloxberg',
contributionMemo: 'My contribution.',
})
})
describe('calls "sendEmailTranslated"', () => {
@ -328,12 +348,15 @@ describe('sendEmailVariants', () => {
describe('sendContributionDeletedEmail', () => {
beforeAll(async () => {
result = await emailBuilder
.setRecipient(recipientUser)
.setSender(senderUser)
.setContribution(contribution)
.setType(EmailType.CONTRIBUTION_DELETED)
.sendEmail()
result = await sendContributionDeletedEmail({
firstName: 'Peter',
lastName: 'Lustig',
email: 'peter@lustig.de',
language: 'en',
senderFirstName: 'Bibi',
senderLastName: 'Bloxberg',
contributionMemo: 'My contribution.',
})
})
describe('calls "sendEmailTranslated"', () => {
@ -385,12 +408,14 @@ describe('sendEmailVariants', () => {
describe('sendResetPasswordEmail', () => {
beforeAll(async () => {
result = await emailBuilder
.setRecipient(recipientUser)
.setResetLink('http://localhost/reset-password/3762660021544901417')
.setTimeDurationObject({ hours: 23, minutes: 30 })
.setType(EmailType.RESET_PASSWORD)
.sendEmail()
result = await sendResetPasswordEmail({
firstName: 'Peter',
lastName: 'Lustig',
email: 'peter@lustig.de',
language: 'en',
resetLink: 'http://localhost/reset-password/3762660021544901417',
timeDurationObject: { hours: 23, minutes: 30 },
})
})
describe('calls "sendEmailTranslated"', () => {
@ -441,12 +466,17 @@ describe('sendEmailVariants', () => {
describe('sendTransactionLinkRedeemedEmail', () => {
beforeAll(async () => {
result = await emailBuilder
.setRecipient(recipientUser)
.setSender(senderUser)
.setTransaction(new Decimal(17.65), 'You deserve it! 🙏🏼')
.setType(EmailType.TRANSACTION_LINK_REDEEMED)
.sendEmail()
result = await sendTransactionLinkRedeemedEmail({
firstName: 'Peter',
lastName: 'Lustig',
email: 'peter@lustig.de',
language: 'en',
senderFirstName: 'Bibi',
senderLastName: 'Bloxberg',
senderEmail: 'bibi@bloxberg.de',
transactionMemo: 'You deserve it! 🙏🏼',
transactionAmount: new Decimal(17.65),
})
})
describe('calls "sendEmailTranslated"', () => {
@ -500,12 +530,16 @@ describe('sendEmailVariants', () => {
describe('sendTransactionReceivedEmail', () => {
beforeAll(async () => {
result = await emailBuilder
.setRecipient(recipientUser)
.setSender(senderUser)
.setTransactionAmount(new Decimal(37.4))
.setType(EmailType.TRANSACTION_RECEIVED)
.sendEmail()
result = await sendTransactionReceivedEmail({
firstName: 'Peter',
lastName: 'Lustig',
email: 'peter@lustig.de',
language: 'en',
senderFirstName: 'Bibi',
senderLastName: 'Bloxberg',
senderEmail: 'bibi@bloxberg.de',
transactionAmount: new Decimal(37.4),
})
})
describe('calls "sendEmailTranslated"', () => {

View File

@ -497,6 +497,28 @@ describe('ContributionResolver', () => {
})
})
it('throws an error', async () => {
jest.clearAllMocks()
const { errors: errorObjects } = await mutate({
mutation: adminUpdateContribution,
variables: {
id: pendingContribution.data.createContribution.id,
amount: 10.0,
memo: 'Test env contribution',
creationDate: new Date().toString(),
},
})
expect(errorObjects).toEqual([
new GraphQLError('An admin is not allowed to update an user contribution'),
])
})
it('logs the error "An admin is not allowed to update an user contribution"', () => {
expect(logger.error).toBeCalledWith(
'An admin is not allowed to update an user contribution',
)
})
describe('contribution has wrong status', () => {
beforeAll(async () => {
const contribution = await Contribution.findOneOrFail({
@ -2802,7 +2824,7 @@ describe('ContributionResolver', () => {
} = await query({
query: adminListContributions,
})
// console.log('17 contributions: %s', JSON.stringify(contributionListObject, null, 2))
expect(contributionListObject.contributionList).toHaveLength(18)
expect(contributionListObject).toMatchObject({
contributionCount: 18,
@ -2885,7 +2907,7 @@ describe('ContributionResolver', () => {
id: expect.any(Number),
lastName: 'Lustig',
memo: 'Das war leider zu Viel!',
messagesCount: 1,
messagesCount: 0,
status: 'DELETED',
}),
expect.objectContaining({
@ -3070,7 +3092,7 @@ describe('ContributionResolver', () => {
id: expect.any(Number),
lastName: 'Lustig',
memo: 'Das war leider zu Viel!',
messagesCount: 1,
messagesCount: 0,
status: 'DELETED',
}),
]),
@ -3115,7 +3137,7 @@ describe('ContributionResolver', () => {
id: expect.any(Number),
lastName: 'Lustig',
memo: 'Das war leider zu Viel!',
messagesCount: 1,
messagesCount: 0,
status: 'DELETED',
}),
]),

View File

@ -22,7 +22,6 @@ import { OpenCreation } from '@model/OpenCreation'
import { UnconfirmedContribution } from '@model/UnconfirmedContribution'
import { RIGHTS } from '@/auth/RIGHTS'
import { EmailBuilder, EmailType } from '@/emails/Email.builder'
import {
EVENT_CONTRIBUTION_CREATE,
EVENT_CONTRIBUTION_DELETE,
@ -46,6 +45,7 @@ import { getUserCreation, validateContribution, getOpenCreations } from './util/
import { findContributions } from './util/findContributions'
import { getLastTransaction } from './util/getLastTransaction'
import { sendTransactionsToDltConnector } from './util/sendTransactionsToDltConnector'
import { sendContributionConfirmedEmail, sendContributionDeletedEmail, sendContributionDeniedEmail } from '@/emails/sendEmailVariants'
@Resolver()
export class ContributionResolver {
@ -332,13 +332,15 @@ export class ContributionResolver {
contribution,
contribution.amount,
)
const emailBuilder = new EmailBuilder()
void emailBuilder
.setRecipient(user)
.setSender(moderator)
.setContribution(contribution)
.setType(EmailType.CONTRIBUTION_DELETED)
.sendEmail()
void sendContributionDeletedEmail({
firstName: user.firstName,
lastName: user.lastName,
email: user.emailContact.email,
language: user.language,
senderFirstName: moderator.firstName,
senderLastName: moderator.lastName,
contributionMemo: contribution.memo,
})
return !!res
}
@ -431,13 +433,16 @@ export class ContributionResolver {
void sendTransactionsToDltConnector()
logger.info('creation commited successfuly.')
const emailBuilder = new EmailBuilder()
void emailBuilder
.setRecipient(user)
.setSender(moderatorUser)
.setContribution(contribution)
.setType(EmailType.CONTRIBUTION_CONFIRMED)
.sendEmail()
void sendContributionConfirmedEmail({
firstName: user.firstName,
lastName: user.lastName,
email: user.emailContact.email,
language: user.language,
senderFirstName: moderatorUser.firstName,
senderLastName: moderatorUser.lastName,
contributionMemo: contribution.memo,
contributionAmount: contribution.amount,
})
} catch (e) {
await queryRunner.rollbackTransaction()
throw new LogError('Creation was not successful', e)
@ -511,13 +516,15 @@ export class ContributionResolver {
contributionToUpdate.amount,
)
const emailBuilder = new EmailBuilder()
void emailBuilder
.setRecipient(user)
.setSender(moderator)
.setContribution(contributionToUpdate)
.setType(EmailType.CONTRIBUTION_DENIED)
.sendEmail()
void sendContributionDeniedEmail({
firstName: user.firstName,
lastName: user.lastName,
email: user.emailContact.email,
language: user.language,
senderFirstName: moderator.firstName,
senderLastName: moderator.lastName,
contributionMemo: contributionToUpdate.memo,
})
return !!res
}

View File

@ -22,7 +22,6 @@ import { User } from '@model/User'
import { RIGHTS } from '@/auth/RIGHTS'
import { CONFIG } from '@/config'
import { EmailBuilder, EmailType } from '@/emails/Email.builder'
import {
sendTransactionLinkRedeemedEmail,
sendTransactionReceivedEmail,
@ -181,21 +180,28 @@ export const executeTransaction = async (
} finally {
await queryRunner.release()
}
const emailBuilder = new EmailBuilder()
void emailBuilder
.setRecipient(recipient)
.setSender(sender)
.setTransactionAmount(amount)
.setType(EmailType.TRANSACTION_RECEIVED)
.sendEmail()
void sendTransactionReceivedEmail({
firstName: recipient.firstName,
lastName: recipient.lastName,
email: recipient.emailContact.email,
language: recipient.language,
senderFirstName: sender.firstName,
senderLastName: sender.lastName,
senderEmail: sender.emailContact.email,
transactionAmount: amount,
})
if (transactionLink) {
void emailBuilder
.setRecipient(sender)
.setSender(recipient)
.setTransaction(amount, memo)
.setType(EmailType.TRANSACTION_LINK_REDEEMED)
.sendEmail()
void sendTransactionLinkRedeemedEmail({
firstName: sender.firstName,
lastName: sender.lastName,
email: sender.emailContact.email,
language: sender.language,
senderFirstName: recipient.firstName,
senderLastName: recipient.lastName,
senderEmail: recipient.emailContact.email,
transactionAmount: amount,
transactionMemo: memo,
})
}
logger.info(`finished executeTransaction successfully`)
} finally {

View File

@ -31,8 +31,11 @@ import { subscribe } from '@/apis/KlicktippController'
import { encode } from '@/auth/JWT'
import { RIGHTS } from '@/auth/RIGHTS'
import { CONFIG } from '@/config'
import { EmailBuilder, EmailType } from '@/emails/Email.builder'
import { sendResetPasswordEmail } from '@/emails/sendEmailVariants'
import {
sendAccountActivationEmail,
sendAccountMultiRegistrationEmail,
sendResetPasswordEmail,
} from '@/emails/sendEmailVariants'
import {
Event,
EventType,
@ -245,12 +248,12 @@ export class UserResolver {
}
logger.debug('partly faked user', user)
const emailBuilder = new EmailBuilder()
void emailBuilder
.setRecipient(foundUser) // this is the real name of the email owner, but just "firstName" and "lastName" would be the name of the new registrant which shall not be passed to the outside
.setType(EmailType.ACCOUNT_MULTI_REGISTRATION)
.sendEmail()
void sendAccountMultiRegistrationEmail({
firstName: foundUser.firstName, // this is the real name of the email owner, but just "firstName" would be the name of the new registrant which shall not be passed to the outside
lastName: foundUser.lastName, // this is the real name of the email owner, but just "lastName" would be the name of the new registrant which shall not be passed to the outside
email,
language: foundUser.language, // use language of the emails owner for sending
})
await EVENT_EMAIL_ACCOUNT_MULTIREGISTRATION(foundUser)
logger.info(
@ -329,14 +332,14 @@ export class UserResolver {
emailContact.emailVerificationCode.toString(),
).replace(/{code}/g, redeemCode ? '/' + redeemCode : '')
const emailBuilder = new EmailBuilder()
void emailBuilder
.setRecipient(dbUser)
.setActivationLink(activationLink)
.setTimeDurationObject(getTimeDurationObject(CONFIG.EMAIL_CODE_VALID_TIME))
.setType(EmailType.ACCOUNT_ACTIVATION)
.sendEmail()
void sendAccountActivationEmail({
firstName,
lastName,
email,
language,
activationLink,
timeDurationObject: getTimeDurationObject(CONFIG.EMAIL_CODE_VALID_TIME),
})
logger.info(`sendAccountActivationEmail of ${firstName}.${lastName} to ${email}`)
await EVENT_EMAIL_CONFIRMATION(dbUser)
@ -391,13 +394,15 @@ export class UserResolver {
})
logger.info('optInCode for', email, user.emailContact)
const emailBuilder = new EmailBuilder()
void emailBuilder
.setRecipient(user)
.setResetLink(activationLink(user.emailContact.emailVerificationCode))
.setTimeDurationObject(getTimeDurationObject(CONFIG.EMAIL_CODE_VALID_TIME))
.setType(EmailType.RESET_PASSWORD)
.sendEmail()
void sendResetPasswordEmail({
firstName: user.firstName,
lastName: user.lastName,
email,
language: user.language,
resetLink: activationLink(user.emailContact.emailVerificationCode),
timeDurationObject: getTimeDurationObject(CONFIG.EMAIL_CODE_VALID_TIME),
})
logger.info(`forgotPassword(${email}) successful...`)
await EVENT_EMAIL_FORGOT_PASSWORD(user)
@ -793,13 +798,15 @@ export class UserResolver {
user.emailContact.emailResendCount++
await user.emailContact.save()
const emailBuilder = new EmailBuilder()
void emailBuilder
.setRecipient(user)
.setActivationLink(activationLink(user.emailContact.emailVerificationCode))
.setTimeDurationObject(getTimeDurationObject(CONFIG.EMAIL_CODE_VALID_TIME))
.setType(EmailType.ACCOUNT_ACTIVATION)
.sendEmail()
// eslint-disable-next-line @typescript-eslint/no-unused-vars
void sendAccountActivationEmail({
firstName: user.firstName,
lastName: user.lastName,
email,
language: user.language,
activationLink: activationLink(user.emailContact.emailVerificationCode),
timeDurationObject: getTimeDurationObject(CONFIG.EMAIL_CODE_VALID_TIME),
})
await EVENT_EMAIL_ADMIN_CONFIRMATION(user, getUser(context))

View File

@ -1 +1 @@
export { Contribution } from './0074-add_updated_by_contribution/Contribution'
export { Contribution } from './0075-add_updated_by_contribution/Contribution'