Merge branch 'master' into 1906-feature-concept-for-gdd-creation-per-linkqr-code

This commit is contained in:
clauspeterhuebner 2022-06-22 00:48:23 +02:00 committed by GitHub
commit 610f6ee847
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 151 additions and 45 deletions

View File

@ -1,4 +1,4 @@
CONFIG_VERSION=v7.2022-06-15
CONFIG_VERSION=v8.2022-06-20
# Server
PORT=4000

View File

@ -43,6 +43,7 @@ EMAIL_SMTP_URL=$EMAIL_SMTP_URL
EMAIL_SMTP_PORT=587
EMAIL_LINK_VERIFICATION=$EMAIL_LINK_VERIFICATION
EMAIL_LINK_SETPASSWORD=$EMAIL_LINK_SETPASSWORD
EMAIL_LINK_FORGOTPASSWORD=$EMAIL_LINK_FORGOTPASSWORD
EMAIL_LINK_OVERVIEW=$EMAIL_LINK_OVERVIEW
EMAIL_CODE_VALID_TIME=$EMAIL_CODE_VALID_TIME
EMAIL_CODE_REQUEST_TIME=$EMAIL_CODE_REQUEST_TIME

View File

@ -17,7 +17,7 @@ const constants = {
LOG_LEVEL: process.env.LOG_LEVEL || 'info',
CONFIG_VERSION: {
DEFAULT: 'DEFAULT',
EXPECTED: 'v7.2022-06-15',
EXPECTED: 'v8.2022-06-20',
CURRENT: '',
},
}

View File

@ -11,6 +11,7 @@ import { LoginEmailOptIn } from '@entity/LoginEmailOptIn'
import { User } from '@entity/User'
import CONFIG from '@/config'
import { sendAccountActivationEmail } from '@/mailer/sendAccountActivationEmail'
import { sendAccountMultiRegistrationEmail } from '@/mailer/sendAccountMultiRegistrationEmail'
import { sendResetPasswordEmail } from '@/mailer/sendResetPasswordEmail'
import { printTimeDuration, activationLink } from './UserResolver'
import { contributionLinkFactory } from '@/seeds/factory/contributionLink'
@ -29,6 +30,13 @@ jest.mock('@/mailer/sendAccountActivationEmail', () => {
}
})
jest.mock('@/mailer/sendAccountMultiRegistrationEmail', () => {
return {
__esModule: true,
sendAccountMultiRegistrationEmail: jest.fn(),
}
})
jest.mock('@/mailer/sendResetPasswordEmail', () => {
return {
__esModule: true,
@ -156,14 +164,33 @@ describe('UserResolver', () => {
})
describe('email already exists', () => {
it('throws and logs an error', async () => {
const mutation = await mutate({ mutation: createUser, variables })
let mutation: User
beforeAll(async () => {
mutation = await mutate({ mutation: createUser, variables })
})
it('logs an info', async () => {
expect(logger.info).toBeCalledWith('User already exists with this email=peter@lustig.de')
})
it('sends an account multi registration email', () => {
expect(sendAccountMultiRegistrationEmail).toBeCalledWith({
firstName: 'Peter',
lastName: 'Lustig',
email: 'peter@lustig.de',
})
})
it('results with partly faked user with random "id"', async () => {
expect(mutation).toEqual(
expect.objectContaining({
errors: [new GraphQLError('User already exists.')],
data: {
createUser: {
id: expect.any(Number),
},
},
}),
)
expect(logger.error).toBeCalledWith('User already exists with this email=peter@lustig.de')
})
})

View File

@ -7,6 +7,7 @@ import { getConnection } from '@dbTools/typeorm'
import CONFIG from '@/config'
import { User } from '@model/User'
import { User as DbUser } from '@entity/User'
import { communityDbUser } from '@/util/communityUser'
import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink'
import { ContributionLink as dbContributionLink } from '@entity/ContributionLink'
import { encode } from '@/auth/JWT'
@ -18,6 +19,7 @@ import { OptInType } from '@enum/OptInType'
import { LoginEmailOptIn } from '@entity/LoginEmailOptIn'
import { sendResetPasswordEmail as sendResetPasswordEmailMailer } from '@/mailer/sendResetPasswordEmail'
import { sendAccountActivationEmail } from '@/mailer/sendAccountActivationEmail'
import { sendAccountMultiRegistrationEmail } from '@/mailer/sendAccountMultiRegistrationEmail'
import { klicktippSignIn } from '@/apis/KlicktippController'
import { RIGHTS } from '@/auth/RIGHTS'
import { hasElopageBuys } from '@/util/hasElopageBuys'
@ -328,10 +330,35 @@ export class UserResolver {
// TODO we cannot use repository.count(), since it does not allow to specify if you want to include the soft deletes
const userFound = await DbUser.findOne({ email }, { withDeleted: true })
logger.info(`DbUser.findOne(email=${email}) = ${userFound}`)
if (userFound) {
logger.error('User already exists with this email=' + email)
logger.info('User already exists with this email=' + email)
// TODO: this is unsecure, but the current implementation of the login server. This way it can be queried if the user with given EMail is existent.
throw new Error(`User already exists.`)
const user = new User(communityDbUser)
user.id = sodium.randombytes_random() % (2048 * 16) // TODO: for a better faking derive id from email so that it will be always the same id when the same email comes in?
user.email = email
user.firstName = firstName
user.lastName = lastName
user.language = language
user.publisherId = publisherId
logger.debug('partly faked user=' + user)
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const emailSent = await sendAccountMultiRegistrationEmail({
firstName,
lastName,
email,
})
logger.info(`sendAccountMultiRegistrationEmail of ${firstName}.${lastName} to ${email}`)
/* uncomment this, when you need the activation link on the console */
// In case EMails are disabled log the activation link for the user
if (!emailSent) {
logger.debug(`Email not send!`)
}
logger.info('createUser() faked and send multi registration mail...')
return user
}
const passphrase = PassphraseGenerate()
@ -417,6 +444,7 @@ export class UserResolver {
await queryRunner.release()
}
logger.info('createUser() successful...')
return new User(dbUser)
}

View File

@ -0,0 +1,31 @@
import CONFIG from '@/config'
import { sendAccountMultiRegistrationEmail } from './sendAccountMultiRegistrationEmail'
import { sendEMail } from './sendEMail'
jest.mock('./sendEMail', () => {
return {
__esModule: true,
sendEMail: jest.fn(),
}
})
describe('sendAccountMultiRegistrationEmail', () => {
beforeEach(async () => {
await sendAccountMultiRegistrationEmail({
firstName: 'Peter',
lastName: 'Lustig',
email: 'peter@lustig.de',
})
})
it('calls sendEMail', () => {
expect(sendEMail).toBeCalledWith({
to: `Peter Lustig <peter@lustig.de>`,
subject: 'Gradido: Erneuter Registrierungsversuch mit deiner E-Mail',
text:
expect.stringContaining('Hallo Peter Lustig') &&
expect.stringContaining(CONFIG.EMAIL_LINK_FORGOTPASSWORD) &&
expect.stringContaining('https://gradido.net/de/contact/'),
})
})
})

View File

@ -0,0 +1,18 @@
import { sendEMail } from './sendEMail'
import { accountMultiRegistration } from './text/accountMultiRegistration'
import CONFIG from '@/config'
export const sendAccountMultiRegistrationEmail = (data: {
firstName: string
lastName: string
email: string
}): Promise<boolean> => {
return sendEMail({
to: `${data.firstName} ${data.lastName} <${data.email}>`,
subject: accountMultiRegistration.de.subject,
text: accountMultiRegistration.de.text({
...data,
resendLink: CONFIG.EMAIL_LINK_FORGOTPASSWORD,
}),
})
}

View File

@ -31,6 +31,7 @@ describe('sendEMail', () => {
beforeEach(async () => {
result = await sendEMail({
to: 'receiver@mail.org',
cc: 'support@gradido.net',
subject: 'Subject',
text: 'Text text text',
})
@ -50,6 +51,7 @@ describe('sendEMail', () => {
CONFIG.EMAIL = true
result = await sendEMail({
to: 'receiver@mail.org',
cc: 'support@gradido.net',
subject: 'Subject',
text: 'Text text text',
})
@ -72,6 +74,7 @@ describe('sendEMail', () => {
expect((createTransport as jest.Mock).mock.results[0].value.sendMail).toBeCalledWith({
from: `Gradido (nicht antworten) <${CONFIG.EMAIL_SENDER}>`,
to: 'receiver@mail.org',
cc: 'support@gradido.net',
subject: 'Subject',
text: 'Text text text',
})

View File

@ -5,10 +5,15 @@ import CONFIG from '@/config'
export const sendEMail = async (emailDef: {
to: string
cc?: string
subject: string
text: string
}): Promise<boolean> => {
logger.info(`send Email: to=${emailDef.to}, subject=${emailDef.subject}, text=${emailDef.text}`)
logger.info(
`send Email: to=${emailDef.to}` +
(emailDef.cc ? `, cc=${emailDef.cc}` : '') +
`, subject=${emailDef.subject}, text=${emailDef.text}`,
)
if (!CONFIG.EMAIL) {
logger.info(`Emails are disabled via config...`)

View File

@ -0,0 +1,25 @@
export const accountMultiRegistration = {
de: {
subject: 'Gradido: Erneuter Registrierungsversuch mit deiner E-Mail',
text: (data: {
firstName: string
lastName: string
email: string
resendLink: string
}): string =>
`Hallo ${data.firstName} ${data.lastName},
Deine E-Mail-Adresse wurde soeben erneut benutzt, um bei Gradido ein Konto zu registrieren.
Es existiert jedoch zu deiner E-Mail-Adresse schon ein Konto.
Klicke bitte auf den folgenden Link, falls du dein Passwort vergessen haben solltest:
${data.resendLink}
oder kopiere den obigen Link in dein Browserfenster.
Wenn du nicht derjenige bist, der sich versucht hat erneut zu registrieren, wende dich bitte an unseren support:
https://gradido.net/de/contact/
Mit freundlichen Grüßen,
dein Gradido-Team`,
},
}

View File

@ -26,7 +26,7 @@ COMMUNITY_REDEEM_CONTRIBUTION_URL=https://stage1.gradido.net/redeem/CL-{code}
COMMUNITY_DESCRIPTION="Gradido Development Stage1 Test Community"
# backend
BACKEND_CONFIG_VERSION=v7.2022-06-15
BACKEND_CONFIG_VERSION=v8.2022-06-20
JWT_EXPIRES_IN=30m
GDT_API_URL=https://gdt.gradido.net

View File

@ -57,8 +57,7 @@
"no-transactionlist": "Es gab leider einen Fehler. Es wurden keine Transaktionen vom Server übermittelt.",
"no-user": "Kein Benutzer mit diesen Anmeldedaten.",
"session-expired": "Die Sitzung wurde aus Sicherheitsgründen beendet.",
"unknown-error": "Unbekanter Fehler: ",
"user-already-exists": "Ein Benutzer mit diesen Daten existiert bereits."
"unknown-error": "Unbekannter Fehler: "
},
"followUs": "folge uns:",
"footer": {

View File

@ -57,8 +57,7 @@
"no-transactionlist": "Unfortunately, there was an error. No transactions have been sent from the server.",
"no-user": "No user with this credentials.",
"session-expired": "The session was closed for security reasons.",
"unknown-error": "Unknown error: ",
"user-already-exists": "A user with this data already exists."
"unknown-error": "Unknown error: "
},
"followUs": "follow us:",
"footer": {

View File

@ -139,24 +139,6 @@ describe('Register', () => {
await flushPromises()
}
describe('server sends back error "User already exists."', () => {
beforeEach(async () => {
await createError('GraphQL error: User already exists.')
})
it('shows no error message on the page', () => {
// don't show any error on the page! against boots
expect(wrapper.vm.showPageMessage).toBe(false)
expect(wrapper.find('.test-message-headline').exists()).toBe(false)
expect(wrapper.find('.test-message-subtitle').exists()).toBe(false)
expect(wrapper.find('.test-message-button').exists()).toBe(false)
})
it('toasts the error message', () => {
expect(toastErrorSpy).toBeCalledWith('error.user-already-exists')
})
})
describe('server sends back error "Unknown error"', () => {
beforeEach(async () => {
await createError(' Unknown error.')

View File

@ -122,9 +122,6 @@ export default {
getValidationState({ dirty, validated, valid = null }) {
return dirty || validated ? valid : null
},
commitStorePublisherId(val) {
this.$store.commit('publisherId', val)
},
async onSubmit() {
this.$apollo
.mutate({
@ -142,16 +139,7 @@ export default {
this.showPageMessage = true
})
.catch((error) => {
let errorMessage
switch (error.message) {
case 'GraphQL error: User already exists.':
errorMessage = this.$t('error.user-already-exists')
break
default:
errorMessage = this.$t('error.unknown-error') + error.message
break
}
this.toastError(errorMessage)
this.toastError(this.$t('error.unknown-error') + error.message)
})
},
},