diff --git a/admin/src/components/UserTable.vue b/admin/src/components/UserTable.vue index b021ef754..3ad4b40cf 100644 --- a/admin/src/components/UserTable.vue +++ b/admin/src/components/UserTable.vue @@ -291,7 +291,7 @@ export default { }, }) .then(() => { - this.$emit('remove-confirm-result', item, 'remove') + this.$emit('remove-confirm-result', item, 'confirmed') }) .catch((error) => { this.$toasted.error(error.message) diff --git a/admin/src/graphql/createPendingCreation.js b/admin/src/graphql/createPendingCreation.js index 72c3249de..183fa5b15 100644 --- a/admin/src/graphql/createPendingCreation.js +++ b/admin/src/graphql/createPendingCreation.js @@ -3,7 +3,7 @@ import gql from 'graphql-tag' export const createPendingCreation = gql` mutation ( $email: String! - $amount: Int! + $amount: Float! $memo: String! $creationDate: String! $moderator: Int! diff --git a/admin/src/graphql/updatePendingCreation.js b/admin/src/graphql/updatePendingCreation.js index b137d961c..77668f15b 100644 --- a/admin/src/graphql/updatePendingCreation.js +++ b/admin/src/graphql/updatePendingCreation.js @@ -4,7 +4,7 @@ export const updatePendingCreation = gql` mutation ( $id: Int! $email: String! - $amount: Int! + $amount: Float! $memo: String! $creationDate: String! $moderator: Int! diff --git a/admin/src/pages/CreationConfirm.spec.js b/admin/src/pages/CreationConfirm.spec.js index 90db3a93f..fb59d1598 100644 --- a/admin/src/pages/CreationConfirm.spec.js +++ b/admin/src/pages/CreationConfirm.spec.js @@ -81,7 +81,7 @@ describe('CreationConfirm', () => { }) }) - describe('confirm creation delete with success', () => { + describe('delete creation delete with success', () => { beforeEach(async () => { apolloQueryMock.mockResolvedValue({ data: { @@ -130,7 +130,7 @@ describe('CreationConfirm', () => { }) }) - describe('confirm creation delete with error', () => { + describe('delete creation delete with error', () => { beforeEach(async () => { apolloMutateMock.mockRejectedValue({ message: 'Ouchhh!' }) await wrapper @@ -143,6 +143,67 @@ describe('CreationConfirm', () => { }) }) + describe('confirm creation delete with success', () => { + beforeEach(async () => { + apolloQueryMock.mockResolvedValue({ + data: { + getPendingCreations: [ + { + id: 1, + firstName: 'Bibi', + lastName: 'Bloxberg', + email: 'bibi@bloxberg.de', + amount: 500, + memo: 'Danke für alles', + date: new Date(), + moderator: 0, + }, + { + id: 2, + firstName: 'Räuber', + lastName: 'Hotzenplotz', + email: 'raeuber@hotzenplotz.de', + amount: 1000000, + memo: 'Gut Ergatert', + date: new Date(), + moderator: 0, + }, + ], + }, + }) + await wrapper + .findComponent({ name: 'UserTable' }) + .vm.$emit('remove-confirm-result', { id: 1 }, 'confirmed') + }) + + it('calls the deletePendingCreation mutation', () => { + expect(apolloMutateMock).not.toBeCalledWith({ + mutation: deletePendingCreation, + variables: { id: 1 }, + }) + }) + + it('commits openCreationsMinus to store', () => { + expect(storeCommitMock).toBeCalledWith('openCreationsMinus', 1) + }) + + it('toasts a success message', () => { + expect(toastedSuccessMock).toBeCalledWith('Pending Creation has been deleted') + }) + }) + + describe('delete creation delete with error', () => { + beforeEach(async () => { + await wrapper + .findComponent({ name: 'UserTable' }) + .vm.$emit('remove-confirm-result', { id: 1 }, 'confirm') + }) + + it('toasts an error message', () => { + expect(toastedErrorMock).toBeCalledWith('Case confirm is not supported') + }) + }) + describe('server response is error', () => { beforeEach(() => { jest.clearAllMocks() diff --git a/admin/src/pages/CreationConfirm.vue b/admin/src/pages/CreationConfirm.vue index 0f180ffbc..578c9b23f 100644 --- a/admin/src/pages/CreationConfirm.vue +++ b/admin/src/pages/CreationConfirm.vue @@ -51,25 +51,34 @@ export default { }, methods: { removeConfirmResult(e, event) { - if (event === 'remove') { - let index = 0 - const findArr = this.confirmResult.find((arr) => arr.id === e.id) - this.$apollo - .mutate({ - mutation: deletePendingCreation, - variables: { - id: findArr.id, - }, - }) - .then((result) => { - index = this.confirmResult.indexOf(findArr) - this.confirmResult.splice(index, 1) - this.$store.commit('openCreationsMinus', 1) - this.$toasted.success('Pending Creation has been deleted') - }) - .catch((error) => { - this.$toasted.error(error.message) - }) + let index = 0 + const findArr = this.confirmResult.find((arr) => arr.id === e.id) + switch (event) { + case 'remove': + this.$apollo + .mutate({ + mutation: deletePendingCreation, + variables: { + id: findArr.id, + }, + }) + .then((result) => { + index = this.confirmResult.indexOf(findArr) + this.confirmResult.splice(index, 1) + this.$store.commit('openCreationsMinus', 1) + this.$toasted.success('Pending Creation has been deleted') + }) + .catch((error) => { + this.$toasted.error(error.message) + }) + break + case 'confirmed': + this.confirmResult.splice(index, 1) + this.$store.commit('openCreationsMinus', 1) + this.$toasted.success('Pending Creation has been deleted') + break + default: + this.$toasted.error('Case ' + event + ' is not supported') } }, getPendingCreations() { @@ -80,7 +89,7 @@ export default { }) .then((result) => { this.$store.commit('resetOpenCreations') - this.confirmResult = result.data.getPendingCreations.reverse() + this.confirmResult = result.data.getPendingCreations this.$store.commit('setOpenCreations', result.data.getPendingCreations.length) }) .catch((error) => { diff --git a/backend/src/graphql/arg/CreatePendingCreationArgs.ts b/backend/src/graphql/arg/CreatePendingCreationArgs.ts index d2c17abf1..dfd4a4e85 100644 --- a/backend/src/graphql/arg/CreatePendingCreationArgs.ts +++ b/backend/src/graphql/arg/CreatePendingCreationArgs.ts @@ -1,11 +1,11 @@ -import { ArgsType, Field, Int } from 'type-graphql' +import { ArgsType, Field, Float, Int } from 'type-graphql' @ArgsType() export default class CreatePendingCreationArgs { @Field(() => String) email: string - @Field(() => Int) + @Field(() => Float) amount: number @Field(() => String) diff --git a/backend/src/graphql/arg/CreateUserArgs.ts b/backend/src/graphql/arg/CreateUserArgs.ts index 3a8914200..0d63e76bb 100644 --- a/backend/src/graphql/arg/CreateUserArgs.ts +++ b/backend/src/graphql/arg/CreateUserArgs.ts @@ -11,9 +11,6 @@ export default class CreateUserArgs { @Field(() => String) lastName: string - @Field(() => String) - password: string - @Field(() => String) language?: string // Will default to DEFAULT_LANGUAGE diff --git a/backend/src/graphql/arg/UpdatePendingCreationArgs.ts b/backend/src/graphql/arg/UpdatePendingCreationArgs.ts index bde7133aa..8cd9ccc4c 100644 --- a/backend/src/graphql/arg/UpdatePendingCreationArgs.ts +++ b/backend/src/graphql/arg/UpdatePendingCreationArgs.ts @@ -1,4 +1,4 @@ -import { ArgsType, Field, Int } from 'type-graphql' +import { ArgsType, Field, Float, Int } from 'type-graphql' @ArgsType() export default class CreatePendingCreationArgs { @@ -8,7 +8,7 @@ export default class CreatePendingCreationArgs { @Field(() => String) email: string - @Field(() => Int) + @Field(() => Float) amount: number @Field(() => String) diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index 31c720716..f1f570b71 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -136,7 +136,7 @@ export class AdminResolver { return newPendingCreation }), ) - return pendingCreationsPromise + return pendingCreationsPromise.reverse() } @Mutation(() => Boolean) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 00a50f97e..20bd01cec 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -148,6 +148,66 @@ const SecretKeyCryptographyDecrypt = (encryptedMessage: Buffer, encryptionKey: B return message } +const createEmailOptIn = async ( + loginUserId: number, + queryRunner: QueryRunner, +): Promise => { + const loginEmailOptInRepository = await getRepository(LoginEmailOptIn) + let emailOptIn = await loginEmailOptInRepository.findOne({ + userId: loginUserId, + emailOptInTypeId: EMAIL_OPT_IN_REGISTER, + }) + if (emailOptIn) { + const timeElapsed = Date.now() - new Date(emailOptIn.updatedAt).getTime() + if (timeElapsed <= parseInt(CONFIG.RESEND_TIME.toString()) * 60 * 1000) { + throw new Error( + 'email already sent less than ' + parseInt(CONFIG.RESEND_TIME.toString()) + ' minutes ago', + ) + } else { + emailOptIn.updatedAt = new Date() + emailOptIn.resendCount++ + } + } else { + emailOptIn = new LoginEmailOptIn() + emailOptIn.verificationCode = random(64) + emailOptIn.userId = loginUserId + emailOptIn.emailOptInTypeId = EMAIL_OPT_IN_REGISTER + } + await queryRunner.manager.save(emailOptIn).catch((error) => { + // eslint-disable-next-line no-console + console.log('Error while saving emailOptIn', error) + throw new Error('error saving email opt in') + }) + return emailOptIn +} + +const getOptInCode = async (loginUser: LoginUser): Promise => { + const loginEmailOptInRepository = await getRepository(LoginEmailOptIn) + let optInCode = await loginEmailOptInRepository.findOne({ + userId: loginUser.id, + emailOptInTypeId: EMAIL_OPT_IN_RESET_PASSWORD, + }) + + // Check for 10 minute delay + if (optInCode) { + const timeElapsed = Date.now() - new Date(optInCode.updatedAt).getTime() + if (timeElapsed <= parseInt(CONFIG.RESEND_TIME.toString()) * 60 * 1000) { + throw new Error( + 'email already sent less than ' + parseInt(CONFIG.RESEND_TIME.toString()) + ' minutes ago', + ) + } else { + optInCode.updatedAt = new Date() + optInCode.resendCount++ + } + } else { + optInCode = new LoginEmailOptIn() + optInCode.verificationCode = random(64) + optInCode.userId = loginUser.id + optInCode.emailOptInTypeId = EMAIL_OPT_IN_RESET_PASSWORD + } + await loginEmailOptInRepository.save(optInCode) + return optInCode +} @Resolver() export class UserResolver { @@ -383,7 +443,7 @@ export class UserResolver { // Store EmailOptIn in DB // TODO: this has duplicate code with sendResetPasswordEmail - const emailOptIn = await this.createEmailOptIn(loginUserId, queryRunner) + const emailOptIn = await createEmailOptIn(loginUserId, queryRunner) const activationLink = CONFIG.EMAIL_LINK_VERIFICATION.replace( /\$1/g, @@ -445,7 +505,7 @@ export class UserResolver { await queryRunner.startTransaction('READ UNCOMMITTED') try { - const emailOptIn = await this.createEmailOptIn(loginUser.id, queryRunner) + const emailOptIn = await createEmailOptIn(loginUser.id, queryRunner) const activationLink = CONFIG.EMAIL_LINK_VERIFICATION.replace( /\$1/g, @@ -474,66 +534,6 @@ export class UserResolver { return true } - private async createEmailOptIn(loginUserId: number, queryRunner: QueryRunner) { - const loginEmailOptInRepository = await getRepository(LoginEmailOptIn) - let emailOptIn = await loginEmailOptInRepository.findOne({ - userId: loginUserId, - emailOptInTypeId: EMAIL_OPT_IN_REGISTER, - }) - if (emailOptIn) { - const timeElapsed = Date.now() - new Date(emailOptIn.updatedAt).getTime() - if (timeElapsed <= parseInt(CONFIG.RESEND_TIME.toString()) * 60 * 1000) { - throw new Error( - 'email already sent less than ' + - parseInt(CONFIG.RESEND_TIME.toString()) + - ' minutes ago', - ) - } else { - emailOptIn.updatedAt = new Date() - emailOptIn.resendCount++ - } - } else { - emailOptIn = new LoginEmailOptIn() - emailOptIn.verificationCode = random(64) - emailOptIn.userId = loginUserId - emailOptIn.emailOptInTypeId = EMAIL_OPT_IN_REGISTER - } - await queryRunner.manager.save(emailOptIn).catch((error) => { - // eslint-disable-next-line no-console - console.log('Error while saving emailOptIn', error) - throw new Error('error saving email opt in') - }) - return emailOptIn - } - - private async getOptInCode(loginUser: LoginUser) { - const loginEmailOptInRepository = await getRepository(LoginEmailOptIn) - let optInCode = await loginEmailOptInRepository.findOne({ - userId: loginUser.id, - emailOptInTypeId: EMAIL_OPT_IN_RESET_PASSWORD, - }) - if (optInCode) { - const timeElapsed = Date.now() - new Date(optInCode.updatedAt).getTime() - if (timeElapsed <= parseInt(CONFIG.RESEND_TIME.toString()) * 60 * 1000) { - throw new Error( - 'email already sent less than ' + - parseInt(CONFIG.RESEND_TIME.toString()) + - ' minutes ago', - ) - } else { - optInCode.updatedAt = new Date() - optInCode.resendCount++ - } - } else { - optInCode = new LoginEmailOptIn() - optInCode.verificationCode = random(64) - optInCode.userId = loginUser.id - optInCode.emailOptInTypeId = EMAIL_OPT_IN_RESET_PASSWORD - } - await loginEmailOptInRepository.save(optInCode) - return optInCode - } - @Authorized([RIGHTS.SEND_RESET_PASSWORD_EMAIL]) @Query(() => Boolean) async sendResetPasswordEmail(@Arg('email') email: string): Promise { @@ -542,7 +542,7 @@ export class UserResolver { const loginUserRepository = await getCustomRepository(LoginUserRepository) const loginUser = await loginUserRepository.findOneOrFail({ email }) - const optInCode = await this.getOptInCode(loginUser) + const optInCode = await getOptInCode(loginUser) const link = CONFIG.EMAIL_LINK_SETPASSWORD.replace( /\$1/g, diff --git a/backend/src/webhook/elopage.ts b/backend/src/webhook/elopage.ts index eb46b10e8..80fa90933 100644 --- a/backend/src/webhook/elopage.ts +++ b/backend/src/webhook/elopage.ts @@ -146,7 +146,6 @@ export const elopageWebhook = async (req: any, res: any): Promise => { firstName, lastName, publisherId: loginElopgaeBuy.publisherId, - password: '123', // TODO remove }) } catch (error) { // eslint-disable-next-line no-console