From 27006be4ae2d7057590b3d8124d5f4896436563b Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 26 Jun 2023 14:21:35 +0200 Subject: [PATCH 1/7] undo changed comming from user query for find contributions --- .../resolver/ContributionResolver.test.ts | 58 ------------------- .../graphql/resolver/ContributionResolver.ts | 3 - .../resolver/util/findContributions.ts | 33 ++--------- 3 files changed, 6 insertions(+), 88 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index 81e913dde..d4c84b4f3 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -2890,64 +2890,6 @@ describe('ContributionResolver', () => { ]), }) }) - - describe('with query', () => { - it('returns the creations of queried user', async () => { - const result = await query({ - query: adminListContributions, - variables: { - currentPage: 1, - pageSize: 2, - order: Order.DESC, - query: 'peter', - }, - }) - const { - data: { adminListContributions: contributionListObject }, - } = await query({ - query: adminListContributions, - variables: { - currentPage: 1, - pageSize: 2, - order: Order.DESC, - query: 'peter', - }, - }) - expect(contributionListObject.contributionList).toHaveLength(3) - expect(contributionListObject).toMatchObject({ - contributionCount: 3, - contributionList: expect.arrayContaining([ - expect.objectContaining({ - amount: expect.decimalEqual(400), - firstName: 'Peter', - id: expect.any(Number), - lastName: 'Lustig', - memo: 'Herzlich Willkommen bei Gradido!', - messagesCount: 0, - state: 'PENDING', - }), - expect.objectContaining({ - amount: expect.decimalEqual(100), - firstName: 'Peter', - id: expect.any(Number), - lastName: 'Lustig', - memo: 'Test env contribution', - messagesCount: 0, - state: 'PENDING', - }), - expect.objectContaining({ - amount: expect.decimalEqual(200), - firstName: 'Peter', - id: expect.any(Number), - lastName: 'Lustig', - memo: 'Das war leider zu Viel!', - messagesCount: 0, - state: 'DELETED', - }), - ]), - }) - }) - }) }) }) }) diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 9727d6015..2e36eba3f 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -372,8 +372,6 @@ export class ContributionResolver { statusFilter?: ContributionStatus[] | null, @Arg('userId', () => Int, { nullable: true }) userId?: number | null, - @Arg('query', () => String, { nullable: true }) - query?: string | null, ): Promise { const [dbContributions, count] = await findContributions({ order, @@ -383,7 +381,6 @@ export class ContributionResolver { userId, relations: ['user', 'messages'], statusFilter, - query, }) return new ContributionListResult( diff --git a/backend/src/graphql/resolver/util/findContributions.ts b/backend/src/graphql/resolver/util/findContributions.ts index 66038538a..28984d5b1 100644 --- a/backend/src/graphql/resolver/util/findContributions.ts +++ b/backend/src/graphql/resolver/util/findContributions.ts @@ -1,4 +1,4 @@ -import { In, Like, FindOperator } from '@dbTools/typeorm' +import { In } from '@dbTools/typeorm' import { Contribution as DbContribution } from '@entity/Contribution' import { ContributionStatus } from '@enum/ContributionStatus' @@ -12,48 +12,27 @@ interface FindContributionsOptions { relations?: string[] userId?: number | null statusFilter?: ContributionStatus[] | null - query?: string | null } export const findContributions = async ( options: FindContributionsOptions, ): Promise<[DbContribution[], number]> => { - const { order, currentPage, pageSize, withDeleted, relations, userId, statusFilter, query } = { + const { order, currentPage, pageSize, withDeleted, relations, userId, statusFilter } = { withDeleted: false, relations: [], - query: '', ...options, } - const where: { - userId?: number | undefined - contributionStatus?: FindOperator | undefined - user?: Record>[] | undefined - } = { - ...(statusFilter?.length && { contributionStatus: In(statusFilter) }), - ...(userId && { userId }), - } - - if (query) { - where.user = [ - { firstName: Like(`%${query}%`) }, - { lastName: Like(`%${query}%`) }, - // emailContact: { email: Like(`%${query}%`) }, - ] - } - return DbContribution.findAndCount({ - relations: { - user: { - emailContact: true, - }, - messages: true, + where: { + ...(statusFilter?.length && { contributionStatus: In(statusFilter) }), + ...(userId && { userId }), }, withDeleted, - where, order: { createdAt: order, id: order, }, + relations, skip: (currentPage - 1) * pageSize, take: pageSize, }) From 95e7888d90e8703ce0e7c8880097d5a301d966c4 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 26 Jun 2023 15:57:43 +0200 Subject: [PATCH 2/7] try to get unit tests and seeds running again --- .../resolver/ContributionResolver.test.ts | 8 +- .../resolver/TransactionResolver.test.ts | 12 +- .../src/graphql/resolver/UserResolver.test.ts | 163 +++++++++--------- backend/src/graphql/resolver/UserResolver.ts | 12 +- backend/src/seeds/factory/creation.ts | 9 +- backend/src/seeds/factory/transactionLink.ts | 2 +- backend/src/seeds/factory/user.ts | 4 +- backend/src/seeds/index.ts | 12 +- backend/test/helpers.ts | 15 +- .../UserContact.ts | 2 +- 10 files changed, 131 insertions(+), 108 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index d4c84b4f3..42fe79ff0 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { Connection } from '@dbTools/typeorm' +import { Connection, Equal } from '@dbTools/typeorm' import { Contribution } from '@entity/Contribution' import { Event as DbEvent } from '@entity/Event' import { Transaction as DbTransaction } from '@entity/Transaction' @@ -457,7 +457,7 @@ describe('ContributionResolver', () => { describe('contribution has wrong status', () => { beforeAll(async () => { const contribution = await Contribution.findOneOrFail({ - id: pendingContribution.data.createContribution.id, + where: { id: pendingContribution.data.createContribution.id }, }) contribution.contributionStatus = ContributionStatus.DELETED await contribution.save() @@ -469,7 +469,7 @@ describe('ContributionResolver', () => { afterAll(async () => { const contribution = await Contribution.findOneOrFail({ - id: pendingContribution.data.createContribution.id, + where: { id: pendingContribution.data.createContribution.id }, }) contribution.contributionStatus = ContributionStatus.PENDING await contribution.save() @@ -1828,7 +1828,7 @@ describe('ContributionResolver', () => { creation = await Contribution.findOneOrFail({ where: { memo: 'Herzlich Willkommen bei Gradido!', - amount: 400, + amount: Equal(new Decimal('400')), }, }) }) diff --git a/backend/src/graphql/resolver/TransactionResolver.test.ts b/backend/src/graphql/resolver/TransactionResolver.test.ts index 96d434a29..60445e239 100644 --- a/backend/src/graphql/resolver/TransactionResolver.test.ts +++ b/backend/src/graphql/resolver/TransactionResolver.test.ts @@ -346,8 +346,10 @@ describe('send coins', () => { it('stores the TRANSACTION_SEND event in the database', async () => { // Find the exact transaction (sent one is the one with user[1] as user) const transaction = await Transaction.find({ - userId: user[1].id, - memo: 'unrepeatable memo', + where: { + userId: user[1].id, + memo: 'unrepeatable memo', + }, }) await expect(DbEvent.find()).resolves.toContainEqual( @@ -364,8 +366,10 @@ describe('send coins', () => { it('stores the TRANSACTION_RECEIVE event in the database', async () => { // Find the exact transaction (received one is the one with user[0] as user) const transaction = await Transaction.find({ - userId: user[0].id, - memo: 'unrepeatable memo', + where: { + userId: user[0].id, + memo: 'unrepeatable memo', + }, }) await expect(DbEvent.find()).resolves.toContainEqual( diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index 0384b64c5..bebaa912c 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -195,10 +195,12 @@ describe('UserResolver', () => { }) it('stores the USER_REGISTER event in the database', async () => { - const userConatct = await UserContact.findOneOrFail( - { email: 'peter@lustig.de' }, - { relations: ['user'] }, - ) + const userConatct = await UserContact.findOneOrFail({ + where: { + email: 'peter@lustig.de', + }, + relations: ['user'], + }) await expect(DbEvent.find()).resolves.toContainEqual( expect.objectContaining({ type: EventType.USER_REGISTER, @@ -271,10 +273,10 @@ describe('UserResolver', () => { }) it('stores the EMAIL_ACCOUNT_MULTIREGISTRATION event in the database', async () => { - const userConatct = await UserContact.findOneOrFail( - { email: 'peter@lustig.de' }, - { relations: ['user'] }, - ) + const userConatct = await UserContact.findOneOrFail({ + where: { email: 'peter@lustig.de' }, + relations: ['user'], + }) await expect(DbEvent.find()).resolves.toContainEqual( expect.objectContaining({ type: EventType.EMAIL_ACCOUNT_MULTIREGISTRATION, @@ -292,7 +294,7 @@ describe('UserResolver', () => { variables: { ...variables, email: 'bibi@bloxberg.de', language: 'it' }, }) await expect( - UserContact.findOne({ email: 'bibi@bloxberg.de' }, { relations: ['user'] }), + UserContact.findOne({ where: { email: 'bibi@bloxberg.de' }, relations: ['user'] }), ).resolves.toEqual( expect.objectContaining({ email: 'bibi@bloxberg.de', @@ -334,7 +336,7 @@ describe('UserResolver', () => { }) // make Peter Lustig Admin - const peter = await User.findOneOrFail({ id: user[0].id }) + const peter = await User.findOneOrFail({ where: { id: user[0].id } }) peter.isAdmin = new Date() await peter.save() @@ -365,7 +367,7 @@ describe('UserResolver', () => { it('sets the contribution link id', async () => { await expect( - UserContact.findOne({ email: 'ein@besucher.de' }, { relations: ['user'] }), + UserContact.findOne({ where: { email: 'ein@besucher.de' }, relations: ['user'] }), ).resolves.toEqual( expect.objectContaining({ user: expect.objectContaining({ @@ -445,7 +447,7 @@ describe('UserResolver', () => { memo: `testing transaction link`, }) - transactionLink = await TransactionLink.findOneOrFail() + transactionLink = await TransactionLink.findOneOrFail({}) resetToken() @@ -462,7 +464,7 @@ describe('UserResolver', () => { it('sets the referrer id to bob baumeister id', async () => { await expect( - UserContact.findOne({ email: 'which@ever.de' }, { relations: ['user'] }), + UserContact.findOne({ where: { email: 'which@ever.de' }, relations: ['user'] }), ).resolves.toEqual( expect.objectContaining({ user: expect.objectContaining({ referrerId: bob.data.login.id }), @@ -529,16 +531,18 @@ describe('UserResolver', () => { beforeAll(async () => { await mutate({ mutation: createUser, variables: createUserVariables }) - const emailContact = await UserContact.findOneOrFail({ email: createUserVariables.email }) + const emailContact = await UserContact.findOneOrFail({ + where: { email: createUserVariables.email }, + }) emailVerificationCode = emailContact.emailVerificationCode.toString() result = await mutate({ mutation: setPassword, variables: { code: emailVerificationCode, password: 'Aa12345_' }, }) - newUser = await User.findOneOrFail( - { id: emailContact.userId }, - { relations: ['emailContact'] }, - ) + newUser = await User.findOneOrFail({ + where: { id: emailContact.userId }, + relations: ['emailContact'], + }) }) afterAll(async () => { @@ -571,7 +575,9 @@ describe('UserResolver', () => { describe('no valid password', () => { beforeAll(async () => { await mutate({ mutation: createUser, variables: createUserVariables }) - const emailContact = await UserContact.findOneOrFail({ email: createUserVariables.email }) + const emailContact = await UserContact.findOneOrFail({ + where: { email: createUserVariables.email }, + }) emailVerificationCode = emailContact.emailVerificationCode.toString() }) @@ -697,10 +703,10 @@ describe('UserResolver', () => { }) it('stores the USER_LOGIN event in the database', async () => { - const userConatct = await UserContact.findOneOrFail( - { email: 'bibi@bloxberg.de' }, - { relations: ['user'] }, - ) + const userConatct = await UserContact.findOneOrFail({ + where: { email: 'bibi@bloxberg.de' }, + relations: ['user'], + }) await expect(DbEvent.find()).resolves.toContainEqual( expect.objectContaining({ type: EventType.USER_LOGIN, @@ -879,10 +885,10 @@ describe('UserResolver', () => { }) it('stores the USER_LOGOUT event in the database', async () => { - const userConatct = await UserContact.findOneOrFail( - { email: 'bibi@bloxberg.de' }, - { relations: ['user'] }, - ) + const userConatct = await UserContact.findOneOrFail({ + where: { email: 'bibi@bloxberg.de' }, + relations: ['user'], + }) await expect(DbEvent.find()).resolves.toContainEqual( expect.objectContaining({ type: EventType.USER_LOGOUT, @@ -1047,10 +1053,10 @@ describe('UserResolver', () => { }) it('stores the EMAIL_FORGOT_PASSWORD event in the database', async () => { - const userConatct = await UserContact.findOneOrFail( - { email: 'bibi@bloxberg.de' }, - { relations: ['user'] }, - ) + const userConatct = await UserContact.findOneOrFail({ + where: { email: 'bibi@bloxberg.de' }, + relations: ['user'], + }) await expect(DbEvent.find()).resolves.toContainEqual( expect.objectContaining({ type: EventType.EMAIL_FORGOT_PASSWORD, @@ -1083,7 +1089,7 @@ describe('UserResolver', () => { beforeAll(async () => { await userFactory(testEnv, bibiBloxberg) - emailContact = await UserContact.findOneOrFail({ email: bibiBloxberg.email }) + emailContact = await UserContact.findOneOrFail({ where: { email: bibiBloxberg.email } }) }) afterAll(async () => { @@ -1175,7 +1181,7 @@ describe('UserResolver', () => { locale: 'en', }, }) - await expect(User.findOne()).resolves.toEqual( + await expect(User.findOne({})).resolves.toEqual( expect.objectContaining({ firstName: 'Benjamin', lastName: 'Blümchen', @@ -1185,10 +1191,10 @@ describe('UserResolver', () => { }) it('stores the USER_INFO_UPDATE event in the database', async () => { - const userConatct = await UserContact.findOneOrFail( - { email: 'bibi@bloxberg.de' }, - { relations: ['user'] }, - ) + const userConatct = await UserContact.findOneOrFail({ + where: { email: 'bibi@bloxberg.de' }, + relations: ['user'], + }) await expect(DbEvent.find()).resolves.toContainEqual( expect.objectContaining({ type: EventType.USER_INFO_UPDATE, @@ -1212,7 +1218,7 @@ describe('UserResolver', () => { alias: 'bibi_Bloxberg', }, }) - await expect(User.findOne()).resolves.toEqual( + await expect(User.findOne({})).resolves.toEqual( expect.objectContaining({ alias: 'bibi_Bloxberg', }), @@ -1433,10 +1439,10 @@ describe('UserResolver', () => { let bibi: User beforeAll(async () => { - const usercontact = await UserContact.findOneOrFail( - { email: 'bibi@bloxberg.de' }, - { relations: ['user'] }, - ) + const usercontact = await UserContact.findOneOrFail({ + where: { email: 'bibi@bloxberg.de' }, + relations: ['user'], + }) bibi = usercontact.user bibi.passwordEncryptionType = PasswordEncryptionType.EMAIL bibi.password = SecretKeyCryptographyCreateKey( @@ -1450,10 +1456,10 @@ describe('UserResolver', () => { it('changes to gradidoID on login', async () => { await mutate({ mutation: login, variables }) - const usercontact = await UserContact.findOneOrFail( - { email: 'bibi@bloxberg.de' }, - { relations: ['user'] }, - ) + const usercontact = await UserContact.findOneOrFail({ + where: { email: 'bibi@bloxberg.de' }, + relations: ['user'], + }) bibi = usercontact.user expect(bibi).toEqual( @@ -1590,14 +1596,14 @@ describe('UserResolver', () => { }) it('stores the ADMIN_USER_ROLE_SET event in the database', async () => { - const userConatct = await UserContact.findOneOrFail( - { email: 'bibi@bloxberg.de' }, - { relations: ['user'] }, - ) - const adminConatct = await UserContact.findOneOrFail( - { email: 'peter@lustig.de' }, - { relations: ['user'] }, - ) + const userConatct = await UserContact.findOneOrFail({ + where: { email: 'bibi@bloxberg.de' }, + relations: ['user'], + }) + const adminConatct = await UserContact.findOneOrFail({ + where: { email: 'peter@lustig.de' }, + relations: ['user'], + }) await expect(DbEvent.find()).resolves.toContainEqual( expect.objectContaining({ type: EventType.ADMIN_USER_ROLE_SET, @@ -1792,14 +1798,15 @@ describe('UserResolver', () => { }) it('stores the ADMIN_USER_DELETE event in the database', async () => { - const userConatct = await UserContact.findOneOrFail( - { email: 'bibi@bloxberg.de' }, - { relations: ['user'], withDeleted: true }, - ) - const adminConatct = await UserContact.findOneOrFail( - { email: 'peter@lustig.de' }, - { relations: ['user'] }, - ) + const userConatct = await UserContact.findOneOrFail({ + where: { email: 'bibi@bloxberg.de' }, + relations: ['user'], + withDeleted: true, + }) + const adminConatct = await UserContact.findOneOrFail({ + where: { email: 'peter@lustig.de' }, + relations: ['user'], + }) await expect(DbEvent.find()).resolves.toContainEqual( expect.objectContaining({ type: EventType.ADMIN_USER_DELETE, @@ -1943,10 +1950,10 @@ describe('UserResolver', () => { }) it('sends an account activation email', async () => { - const userConatct = await UserContact.findOneOrFail( - { email: 'bibi@bloxberg.de' }, - { relations: ['user'] }, - ) + const userConatct = await UserContact.findOneOrFail({ + where: { email: 'bibi@bloxberg.de' }, + relations: ['user'], + }) const activationLink = CONFIG.EMAIL_LINK_VERIFICATION.replace( /{optin}/g, userConatct.emailVerificationCode.toString(), @@ -1965,10 +1972,10 @@ describe('UserResolver', () => { }) it('stores the EMAIL_ADMIN_CONFIRMATION event in the database', async () => { - const userConatct = await UserContact.findOneOrFail( - { email: 'bibi@bloxberg.de' }, - { relations: ['user'] }, - ) + const userConatct = await UserContact.findOneOrFail({ + where: { email: 'bibi@bloxberg.de' }, + relations: ['user'], + }) await expect(DbEvent.find()).resolves.toContainEqual( expect.objectContaining({ type: EventType.EMAIL_ADMIN_CONFIRMATION, @@ -2086,14 +2093,14 @@ describe('UserResolver', () => { }) it('stores the ADMIN_USER_UNDELETE event in the database', async () => { - const userConatct = await UserContact.findOneOrFail( - { email: 'bibi@bloxberg.de' }, - { relations: ['user'] }, - ) - const adminConatct = await UserContact.findOneOrFail( - { email: 'peter@lustig.de' }, - { relations: ['user'] }, - ) + const userConatct = await UserContact.findOneOrFail({ + where: { email: 'bibi@bloxberg.de' }, + relations: ['user'], + }) + const adminConatct = await UserContact.findOneOrFail({ + where: { email: 'peter@lustig.de' }, + relations: ['user'], + }) await expect(DbEvent.find()).resolves.toContainEqual( expect.objectContaining({ type: EventType.ADMIN_USER_UNDELETE, diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 840bb43c9..214da858d 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -2,7 +2,7 @@ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/restrict-template-expressions */ -import { getConnection, getCustomRepository, IsNull, Not, Equal } from '@dbTools/typeorm' +import { getConnection, getCustomRepository, IsNull, Not } from '@dbTools/typeorm' import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' import { TransactionLink as DbTransactionLink } from '@entity/TransactionLink' import { User as DbUser } from '@entity/User' @@ -82,13 +82,13 @@ const newEmailContact = (email: string, userId: number): DbUserContact => { emailContact.type = UserContactType.USER_CONTACT_EMAIL emailContact.emailChecked = false emailContact.emailOptInTypeId = OptInType.EMAIL_OPT_IN_REGISTER - emailContact.emailVerificationCode = random(64) + emailContact.emailVerificationCode = random(64).toString() logger.debug('newEmailContact...successful', emailContact) return emailContact } // eslint-disable-next-line @typescript-eslint/ban-types -export const activationLink = (verificationCode: BigInt): string => { +export const activationLink = (verificationCode: string): string => { logger.debug(`activationLink(${verificationCode})...`) return CONFIG.EMAIL_LINK_SETPASSWORD.replace(/{optin}/g, verificationCode.toString()) } @@ -365,7 +365,7 @@ export class UserResolver { user.emailContact.updatedAt = new Date() user.emailContact.emailResendCount++ - user.emailContact.emailVerificationCode = random(64) + user.emailContact.emailVerificationCode = random(64).toString() user.emailContact.emailOptInTypeId = OptInType.EMAIL_OPT_IN_RESET_PASSWORD await user.emailContact.save().catch(() => { throw new LogError('Unable to save email verification code', user.emailContact) @@ -404,7 +404,7 @@ export class UserResolver { // load code const userContact = await DbUserContact.findOneOrFail({ - where: { emailVerificationCode: Equal(BigInt(code)) }, + where: { emailVerificationCode: code }, relations: ['user'], }).catch(() => { throw new LogError('Could not login with emailVerificationCode') @@ -475,7 +475,7 @@ export class UserResolver { async queryOptIn(@Arg('optIn') optIn: string): Promise { logger.info(`queryOptIn(${optIn})...`) const userContact = await DbUserContact.findOneOrFail({ - where: { emailVerificationCode: Equal(BigInt(optIn)) }, + where: { emailVerificationCode: optIn }, }) logger.debug('found optInCode', userContact) // Code is only valid for `CONFIG.EMAIL_CODE_VALID_TIME` minutes diff --git a/backend/src/seeds/factory/creation.ts b/backend/src/seeds/factory/creation.ts index 5b4c56c57..5ad1b2e4e 100644 --- a/backend/src/seeds/factory/creation.ts +++ b/backend/src/seeds/factory/creation.ts @@ -19,7 +19,10 @@ export const creationFactory = async ( creation: CreationInterface, ): Promise => { const { mutate } = client - await mutate({ mutation: login, variables: { email: creation.email, password: 'Aa12345_' } }) + await mutate({ + mutation: login, + variables: { email: creation.email, password: 'Aa12345_' }, + }) const { data: { createContribution: contribution }, @@ -30,7 +33,9 @@ export const creationFactory = async ( await mutate({ mutation: login, variables: { email: 'peter@lustig.de', password: 'Aa12345_' } }) await mutate({ mutation: confirmContribution, variables: { id: contribution.id } }) - const confirmedContribution = await Contribution.findOneOrFail({ id: contribution.id }) + const confirmedContribution = await Contribution.findOneOrFail({ + where: { id: contribution.id }, + }) if (creation.moveCreationDate) { const transaction = await Transaction.findOneOrFail({ diff --git a/backend/src/seeds/factory/transactionLink.ts b/backend/src/seeds/factory/transactionLink.ts index cab478c4b..b44fe349c 100644 --- a/backend/src/seeds/factory/transactionLink.ts +++ b/backend/src/seeds/factory/transactionLink.ts @@ -32,7 +32,7 @@ export const transactionLinkFactory = async ( } = await mutate({ mutation: createTransactionLink, variables }) if (transactionLink.createdAt || transactionLink.deletedAt) { - const dbTransactionLink = await TransactionLink.findOneOrFail({ id }) + const dbTransactionLink = await TransactionLink.findOneOrFail({ where: { id } }) if (transactionLink.createdAt) { dbTransactionLink.createdAt = transactionLink.createdAt diff --git a/backend/src/seeds/factory/user.ts b/backend/src/seeds/factory/user.ts index 13a274911..d40154e12 100644 --- a/backend/src/seeds/factory/user.ts +++ b/backend/src/seeds/factory/user.ts @@ -19,7 +19,7 @@ export const userFactory = async ( } = await mutate({ mutation: createUser, variables: user }) // console.log('creatUser:', { id }, { user }) // get user from database - let dbUser = await User.findOneOrFail({ id }, { relations: ['emailContact'] }) + let dbUser = await User.findOneOrFail({ where: { id }, relations: ['emailContact'] }) // console.log('dbUser:', dbUser) const emailContact = dbUser.emailContact @@ -33,7 +33,7 @@ export const userFactory = async ( } // get last changes of user from database - dbUser = await User.findOneOrFail({ id }) + dbUser = await User.findOneOrFail({ where: { id } }) if (user.createdAt || user.deletedAt || user.isAdmin) { if (user.createdAt) dbUser.createdAt = user.createdAt diff --git a/backend/src/seeds/index.ts b/backend/src/seeds/index.ts index 77fa51990..bc7950f26 100644 --- a/backend/src/seeds/index.ts +++ b/backend/src/seeds/index.ts @@ -1,3 +1,9 @@ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-unsafe-call */ +/* eslint-disable @typescript-eslint/no-unsafe-return */ + import { entities } from '@entity/index' import { createTestClient } from 'apollo-server-testing' import { name, internet, datatype } from 'faker' @@ -36,12 +42,10 @@ export const cleanDB = async () => { } } -const [entityTypes] = entities - -const resetEntity = async (entity: typeof entityTypes) => { +const resetEntity = async (entity: any) => { const items = await entity.find({ withDeleted: true }) if (items.length > 0) { - const ids = items.map((i) => i.id) + const ids = items.map((e: any) => e.id) await entity.delete(ids) } } diff --git a/backend/test/helpers.ts b/backend/test/helpers.ts index 7f55b3c70..ec9c14795 100644 --- a/backend/test/helpers.ts +++ b/backend/test/helpers.ts @@ -1,4 +1,10 @@ /* eslint-disable @typescript-eslint/unbound-method */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/no-unsafe-call */ +/* eslint-disable @typescript-eslint/no-unsafe-return */ + import { entities } from '@entity/index' import { createTestClient } from 'apollo-server-testing' @@ -7,7 +13,6 @@ import { createServer } from '@/server/createServer' import { i18n, logger } from './testSetup' export const headerPushMock = jest.fn((t) => { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access context.token = t.value }) @@ -21,7 +26,7 @@ const context = { } export const cleanDB = async () => { - // this only works as lond we do not have foreign key constraints + // this only works as long we do not have foreign key constraints for (const entity of entities) { await resetEntity(entity) } @@ -36,12 +41,10 @@ export const testEnvironment = async (testLogger = logger, testI18n = i18n) => { return { mutate, query, con } } -const [entityTypes] = entities - -export const resetEntity = async (entity: typeof entityTypes) => { +export const resetEntity = async (entity: anny) => { const items = await entity.find({ withDeleted: true }) if (items.length > 0) { - const ids = items.map((i) => i.id) + const ids = items.map((e: any) => e.id) await entity.delete(ids) } } diff --git a/database/entity/0057-clear_old_password_junk/UserContact.ts b/database/entity/0057-clear_old_password_junk/UserContact.ts index dd06d3bbc..6064a3ea3 100644 --- a/database/entity/0057-clear_old_password_junk/UserContact.ts +++ b/database/entity/0057-clear_old_password_junk/UserContact.ts @@ -32,7 +32,7 @@ export class UserContact extends BaseEntity { email: string @Column({ name: 'email_verification_code', type: 'bigint', unsigned: true, unique: true }) - emailVerificationCode: BigInt + emailVerificationCode: string @Column({ name: 'email_opt_in_type_id' }) emailOptInTypeId: number From 642d2202bf80c5386aeef381eb4e5e675dde8dbd Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 26 Jun 2023 17:34:32 +0200 Subject: [PATCH 3/7] try to get repository working again --- .../src/graphql/resolver/BalanceResolver.ts | 3 +- .../resolver/TransactionLinkResolver.ts | 8 ++ .../graphql/resolver/TransactionResolver.ts | 3 +- backend/src/seeds/factory/transactionLink.ts | 5 +- backend/src/seeds/index.ts | 1 + backend/src/server/createServer.ts | 1 + .../src/typeorm/repository/TransactionLink.ts | 73 ++++++++++--------- backend/src/util/validate.ts | 5 +- backend/test/helpers.ts | 2 +- 9 files changed, 57 insertions(+), 44 deletions(-) diff --git a/backend/src/graphql/resolver/BalanceResolver.ts b/backend/src/graphql/resolver/BalanceResolver.ts index 9cd133181..9a11093b8 100644 --- a/backend/src/graphql/resolver/BalanceResolver.ts +++ b/backend/src/graphql/resolver/BalanceResolver.ts @@ -6,7 +6,7 @@ import { Decimal } from 'decimal.js-light' import { Resolver, Query, Ctx, Authorized } from 'type-graphql' import { Balance } from '@model/Balance' -import { TransactionLinkRepository } from '@repository/TransactionLink' +import { transactionLinkRepository } from '@repository/TransactionLink' import { RIGHTS } from '@/auth/RIGHTS' import { Context, getUser } from '@/server/context' @@ -77,7 +77,6 @@ export class BalanceResolver { ) // The final balance is reduced by the link amount withheld - const transactionLinkRepository = getCustomRepository(TransactionLinkRepository) const { sumHoldAvailableAmount } = context.sumHoldAvailableAmount ? { sumHoldAvailableAmount: context.sumHoldAvailableAmount } : await transactionLinkRepository.summary(user.id, now) diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.ts b/backend/src/graphql/resolver/TransactionLinkResolver.ts index 0ff606fa5..b198a2335 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.ts @@ -76,14 +76,22 @@ export class TransactionLinkResolver { throw new LogError('Amount must be a positive number', amount) } + console.log('Hallo') + const holdAvailableAmount = amount.minus(calculateDecay(amount, createdDate, validUntil).decay) + console.log(holdAvailableAmount) + // validate amount const sendBalance = await calculateBalance(user.id, holdAvailableAmount.mul(-1), createdDate) + console.log('sendBalance', sendBalance) + if (!sendBalance) { throw new LogError('User has not enough GDD', user.id) } + console.log(sendBalance) + const transactionLink = DbTransactionLink.create() transactionLink.userId = user.id transactionLink.amount = amount diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index 40e9ec2dd..8a1097b99 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -16,7 +16,7 @@ import { TransactionTypeId } from '@enum/TransactionTypeId' import { Transaction } from '@model/Transaction' import { TransactionList } from '@model/TransactionList' import { User } from '@model/User' -import { TransactionLinkRepository } from '@repository/TransactionLink' +import { transactionLinkRepository } from '@repository/TransactionLink' import { RIGHTS } from '@/auth/RIGHTS' import { @@ -245,7 +245,6 @@ export class TransactionResolver { const self = new User(user) const transactions: Transaction[] = [] - const transactionLinkRepository = getCustomRepository(TransactionLinkRepository) const { sumHoldAvailableAmount, sumAmount, lastDate, firstDate, transactionLinkcount } = await transactionLinkRepository.summary(user.id, now) context.linkCount = transactionLinkcount diff --git a/backend/src/seeds/factory/transactionLink.ts b/backend/src/seeds/factory/transactionLink.ts index b44fe349c..8bbdb64c4 100644 --- a/backend/src/seeds/factory/transactionLink.ts +++ b/backend/src/seeds/factory/transactionLink.ts @@ -24,12 +24,15 @@ export const transactionLinkFactory = async ( memo: transactionLink.memo, } + const result = await mutate({ mutation: createTransactionLink, variables }) + console.log(result) + // get the transaction links's id const { data: { createTransactionLink: { id }, }, - } = await mutate({ mutation: createTransactionLink, variables }) + } = result if (transactionLink.createdAt || transactionLink.deletedAt) { const dbTransactionLink = await TransactionLink.findOneOrFail({ where: { id } }) diff --git a/backend/src/seeds/index.ts b/backend/src/seeds/index.ts index bc7950f26..2560aa883 100644 --- a/backend/src/seeds/index.ts +++ b/backend/src/seeds/index.ts @@ -52,6 +52,7 @@ const resetEntity = async (entity: any) => { const run = async () => { const server = await createServer(context) + console.log(server) const seedClient = createTestClient(server.apollo) const { con } = server await cleanDB() diff --git a/backend/src/server/createServer.ts b/backend/src/server/createServer.ts index c162d9f6f..36a5bd5e0 100644 --- a/backend/src/server/createServer.ts +++ b/backend/src/server/createServer.ts @@ -37,6 +37,7 @@ export const createServer = async ( logger.debug('createServer...') // open mysql connection + console.log('Connection.getInstance') const con = await Connection.getInstance() if (!con?.isConnected) { logger.fatal(`Couldn't open connection to database!`) diff --git a/backend/src/typeorm/repository/TransactionLink.ts b/backend/src/typeorm/repository/TransactionLink.ts index 8a66aa7cf..45586c538 100644 --- a/backend/src/typeorm/repository/TransactionLink.ts +++ b/backend/src/typeorm/repository/TransactionLink.ts @@ -1,41 +1,42 @@ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-argument */ -import { Repository, EntityRepository } from '@dbTools/typeorm' +import { getConnection } from '@dbTools/typeorm' import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink' import { Decimal } from 'decimal.js-light' -@EntityRepository(dbTransactionLink) -export class TransactionLinkRepository extends Repository { - async summary( - userId: number, - date: Date, - ): Promise<{ - sumHoldAvailableAmount: Decimal - sumAmount: Decimal - lastDate: Date | null - firstDate: Date | null - transactionLinkcount: number - }> { - const { sumHoldAvailableAmount, sumAmount, lastDate, firstDate, count } = - await this.createQueryBuilder('transactionLinks') - .select('SUM(transactionLinks.holdAvailableAmount)', 'sumHoldAvailableAmount') - .addSelect('SUM(transactionLinks.amount)', 'sumAmount') - .addSelect('MAX(transactionLinks.validUntil)', 'lastDate') - .addSelect('MIN(transactionLinks.createdAt)', 'firstDate') - .addSelect('COUNT(*)', 'count') - .where('transactionLinks.userId = :userId', { userId }) - .andWhere('transactionLinks.redeemedAt is NULL') - .andWhere('transactionLinks.validUntil > :date', { date }) - .orderBy('transactionLinks.createdAt', 'DESC') - .getRawOne() - return { - sumHoldAvailableAmount: sumHoldAvailableAmount - ? new Decimal(sumHoldAvailableAmount) - : new Decimal(0), - sumAmount: sumAmount ? new Decimal(sumAmount) : new Decimal(0), - lastDate: lastDate || null, - firstDate: firstDate || null, - transactionLinkcount: count || 0, - } - } -} +export const transactionLinkRepository = getConnection() + .getRepository(dbTransactionLink) + .extend({ + async summary( + userId: number, + date: Date, + ): Promise<{ + sumHoldAvailableAmount: Decimal + sumAmount: Decimal + lastDate: Date | null + firstDate: Date | null + transactionLinkcount: number + }> { + const { sumHoldAvailableAmount, sumAmount, lastDate, firstDate, count } = + await this.createQueryBuilder('transactionLinks') + .select('SUM(transactionLinks.holdAvailableAmount)', 'sumHoldAvailableAmount') + .addSelect('SUM(transactionLinks.amount)', 'sumAmount') + .addSelect('MAX(transactionLinks.validUntil)', 'lastDate') + .addSelect('MIN(transactionLinks.createdAt)', 'firstDate') + .addSelect('COUNT(*)', 'count') + .where('transactionLinks.userId = :userId', { userId }) + .andWhere('transactionLinks.redeemedAt is NULL') + .andWhere('transactionLinks.validUntil > :date', { date }) + .orderBy('transactionLinks.createdAt', 'DESC') + .getRawOne() + return { + sumHoldAvailableAmount: sumHoldAvailableAmount + ? new Decimal(sumHoldAvailableAmount) + : new Decimal(0), + sumAmount: sumAmount ? new Decimal(sumAmount) : new Decimal(0), + lastDate: lastDate || null, + firstDate: firstDate || null, + transactionLinkcount: count || 0, + } + }, + }) diff --git a/backend/src/util/validate.ts b/backend/src/util/validate.ts index 22a6ee5db..8c84b06b2 100644 --- a/backend/src/util/validate.ts +++ b/backend/src/util/validate.ts @@ -3,7 +3,7 @@ import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink' import { Decimal } from 'decimal.js-light' import { Decay } from '@model/Decay' -import { TransactionLinkRepository } from '@repository/TransactionLink' +import { transactionLinkRepository } from '@repository/TransactionLink' import { getLastTransaction } from '@/graphql/resolver/util/getLastTransaction' @@ -26,10 +26,11 @@ async function calculateBalance( const lastTransaction = await getLastTransaction(userId) if (!lastTransaction) return null + console.log(lastTransaction) + const decay = calculateDecay(lastTransaction.balance, lastTransaction.balanceDate, time) const balance = decay.balance.add(amount.toString()) - const transactionLinkRepository = getCustomRepository(TransactionLinkRepository) const { sumHoldAvailableAmount } = await transactionLinkRepository.summary(userId, time) // If we want to redeem a link we need to make sure that the link amount is not considered as blocked diff --git a/backend/test/helpers.ts b/backend/test/helpers.ts index ec9c14795..8a541e3e4 100644 --- a/backend/test/helpers.ts +++ b/backend/test/helpers.ts @@ -41,7 +41,7 @@ export const testEnvironment = async (testLogger = logger, testI18n = i18n) => { return { mutate, query, con } } -export const resetEntity = async (entity: anny) => { +export const resetEntity = async (entity: any) => { const items = await entity.find({ withDeleted: true }) if (items.length > 0) { const ids = items.map((e: any) => e.id) From 44dedacce5d8caaaa38d8fb589102be4867e56bf Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Wed, 28 Jun 2023 12:16:38 +0200 Subject: [PATCH 4/7] transaction link summary as function, seeds are working again --- .../src/graphql/resolver/BalanceResolver.ts | 6 +-- .../resolver/TransactionLinkResolver.ts | 7 --- .../graphql/resolver/TransactionResolver.ts | 6 +-- .../resolver/util/transactionLinkSummary.ts | 49 +++++++++++++++++++ backend/src/seeds/factory/transactionLink.ts | 5 +- backend/src/seeds/index.ts | 1 - backend/src/server/createServer.ts | 1 - .../src/typeorm/repository/TransactionLink.ts | 42 ---------------- backend/src/util/validate.ts | 7 +-- 9 files changed, 58 insertions(+), 66 deletions(-) create mode 100644 backend/src/graphql/resolver/util/transactionLinkSummary.ts delete mode 100644 backend/src/typeorm/repository/TransactionLink.ts diff --git a/backend/src/graphql/resolver/BalanceResolver.ts b/backend/src/graphql/resolver/BalanceResolver.ts index 9a11093b8..87de0e0f7 100644 --- a/backend/src/graphql/resolver/BalanceResolver.ts +++ b/backend/src/graphql/resolver/BalanceResolver.ts @@ -1,12 +1,11 @@ /* eslint-disable @typescript-eslint/restrict-template-expressions */ -import { getCustomRepository, IsNull } from '@dbTools/typeorm' +import { IsNull } from '@dbTools/typeorm' import { Transaction as dbTransaction } from '@entity/Transaction' import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink' import { Decimal } from 'decimal.js-light' import { Resolver, Query, Ctx, Authorized } from 'type-graphql' import { Balance } from '@model/Balance' -import { transactionLinkRepository } from '@repository/TransactionLink' import { RIGHTS } from '@/auth/RIGHTS' import { Context, getUser } from '@/server/context' @@ -15,6 +14,7 @@ import { calculateDecay } from '@/util/decay' import { GdtResolver } from './GdtResolver' import { getLastTransaction } from './util/getLastTransaction' +import { transactionLinkSummary } from './util/transactionLinkSummary' @Resolver() export class BalanceResolver { @@ -79,7 +79,7 @@ export class BalanceResolver { // The final balance is reduced by the link amount withheld const { sumHoldAvailableAmount } = context.sumHoldAvailableAmount ? { sumHoldAvailableAmount: context.sumHoldAvailableAmount } - : await transactionLinkRepository.summary(user.id, now) + : await transactionLinkSummary(user.id, now) logger.debug(`context.sumHoldAvailableAmount=${context.sumHoldAvailableAmount}`) logger.debug(`sumHoldAvailableAmount=${sumHoldAvailableAmount}`) diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.ts b/backend/src/graphql/resolver/TransactionLinkResolver.ts index b198a2335..c987dc0a0 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.ts @@ -76,22 +76,15 @@ export class TransactionLinkResolver { throw new LogError('Amount must be a positive number', amount) } - console.log('Hallo') - const holdAvailableAmount = amount.minus(calculateDecay(amount, createdDate, validUntil).decay) - console.log(holdAvailableAmount) - // validate amount const sendBalance = await calculateBalance(user.id, holdAvailableAmount.mul(-1), createdDate) - console.log('sendBalance', sendBalance) if (!sendBalance) { throw new LogError('User has not enough GDD', user.id) } - console.log(sendBalance) - const transactionLink = DbTransactionLink.create() transactionLink.userId = user.id transactionLink.amount = amount diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index 8a1097b99..5f42fb36e 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -2,7 +2,7 @@ /* eslint-disable new-cap */ /* eslint-disable @typescript-eslint/no-non-null-assertion */ -import { getCustomRepository, getConnection, In } from '@dbTools/typeorm' +import { getConnection, In } from '@dbTools/typeorm' import { Transaction as dbTransaction } from '@entity/Transaction' import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink' import { User as dbUser } from '@entity/User' @@ -16,7 +16,6 @@ import { TransactionTypeId } from '@enum/TransactionTypeId' import { Transaction } from '@model/Transaction' import { TransactionList } from '@model/TransactionList' import { User } from '@model/User' -import { transactionLinkRepository } from '@repository/TransactionLink' import { RIGHTS } from '@/auth/RIGHTS' import { @@ -38,6 +37,7 @@ import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const' import { findUserByIdentifier } from './util/findUserByIdentifier' import { getLastTransaction } from './util/getLastTransaction' import { getTransactionList } from './util/getTransactionList' +import { transactionLinkSummary } from './util/transactionLinkSummary' export const executeTransaction = async ( amount: Decimal, @@ -246,7 +246,7 @@ export class TransactionResolver { const transactions: Transaction[] = [] const { sumHoldAvailableAmount, sumAmount, lastDate, firstDate, transactionLinkcount } = - await transactionLinkRepository.summary(user.id, now) + await transactionLinkSummary(user.id, now) context.linkCount = transactionLinkcount logger.debug(`transactionLinkcount=${transactionLinkcount}`) context.sumHoldAvailableAmount = sumHoldAvailableAmount diff --git a/backend/src/graphql/resolver/util/transactionLinkSummary.ts b/backend/src/graphql/resolver/util/transactionLinkSummary.ts new file mode 100644 index 000000000..8f5f41f15 --- /dev/null +++ b/backend/src/graphql/resolver/util/transactionLinkSummary.ts @@ -0,0 +1,49 @@ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ +import { getConnection } from '@dbTools/typeorm' +import { TransactionLink as DbTransactionLink } from '@entity/TransactionLink' +import { Decimal } from 'decimal.js-light' + +import { LogError } from '@/server/LogError' + +export const transactionLinkSummary = async ( + userId: number, + date: Date, +): Promise<{ + sumHoldAvailableAmount: Decimal + sumAmount: Decimal + lastDate: Date | null + firstDate: Date | null + transactionLinkcount: number +}> => { + const queryRunner = getConnection().createQueryRunner() + try { + await queryRunner.connect() + const { sumHoldAvailableAmount, sumAmount, lastDate, firstDate, count } = + await queryRunner.manager + .createQueryBuilder(DbTransactionLink, 'transactionLink') + .select('SUM(transactionLink.holdAvailableAmount)', 'sumHoldAvailableAmount') + .addSelect('SUM(transactionLink.amount)', 'sumAmount') + .addSelect('MAX(transactionLink.validUntil)', 'lastDate') + .addSelect('MIN(transactionLink.createdAt)', 'firstDate') + .addSelect('COUNT(*)', 'count') + .where('transactionLink.userId = :userId', { userId }) + .andWhere('transactionLink.redeemedAt is NULL') + .andWhere('transactionLink.validUntil > :date', { date }) + .orderBy('transactionLink.createdAt', 'DESC') + .getRawOne() + return { + sumHoldAvailableAmount: sumHoldAvailableAmount + ? new Decimal(sumHoldAvailableAmount) + : new Decimal(0), + sumAmount: sumAmount ? new Decimal(sumAmount) : new Decimal(0), + lastDate: lastDate || null, + firstDate: firstDate || null, + transactionLinkcount: count || 0, + } + } catch (err) { + throw new LogError('Unable to get transaction link summary', err) + } finally { + await queryRunner.release() + } +} diff --git a/backend/src/seeds/factory/transactionLink.ts b/backend/src/seeds/factory/transactionLink.ts index 8bbdb64c4..b44fe349c 100644 --- a/backend/src/seeds/factory/transactionLink.ts +++ b/backend/src/seeds/factory/transactionLink.ts @@ -24,15 +24,12 @@ export const transactionLinkFactory = async ( memo: transactionLink.memo, } - const result = await mutate({ mutation: createTransactionLink, variables }) - console.log(result) - // get the transaction links's id const { data: { createTransactionLink: { id }, }, - } = result + } = await mutate({ mutation: createTransactionLink, variables }) if (transactionLink.createdAt || transactionLink.deletedAt) { const dbTransactionLink = await TransactionLink.findOneOrFail({ where: { id } }) diff --git a/backend/src/seeds/index.ts b/backend/src/seeds/index.ts index 2560aa883..bc7950f26 100644 --- a/backend/src/seeds/index.ts +++ b/backend/src/seeds/index.ts @@ -52,7 +52,6 @@ const resetEntity = async (entity: any) => { const run = async () => { const server = await createServer(context) - console.log(server) const seedClient = createTestClient(server.apollo) const { con } = server await cleanDB() diff --git a/backend/src/server/createServer.ts b/backend/src/server/createServer.ts index 36a5bd5e0..c162d9f6f 100644 --- a/backend/src/server/createServer.ts +++ b/backend/src/server/createServer.ts @@ -37,7 +37,6 @@ export const createServer = async ( logger.debug('createServer...') // open mysql connection - console.log('Connection.getInstance') const con = await Connection.getInstance() if (!con?.isConnected) { logger.fatal(`Couldn't open connection to database!`) diff --git a/backend/src/typeorm/repository/TransactionLink.ts b/backend/src/typeorm/repository/TransactionLink.ts deleted file mode 100644 index 45586c538..000000000 --- a/backend/src/typeorm/repository/TransactionLink.ts +++ /dev/null @@ -1,42 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -/* eslint-disable @typescript-eslint/no-unsafe-argument */ -import { getConnection } from '@dbTools/typeorm' -import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink' -import { Decimal } from 'decimal.js-light' - -export const transactionLinkRepository = getConnection() - .getRepository(dbTransactionLink) - .extend({ - async summary( - userId: number, - date: Date, - ): Promise<{ - sumHoldAvailableAmount: Decimal - sumAmount: Decimal - lastDate: Date | null - firstDate: Date | null - transactionLinkcount: number - }> { - const { sumHoldAvailableAmount, sumAmount, lastDate, firstDate, count } = - await this.createQueryBuilder('transactionLinks') - .select('SUM(transactionLinks.holdAvailableAmount)', 'sumHoldAvailableAmount') - .addSelect('SUM(transactionLinks.amount)', 'sumAmount') - .addSelect('MAX(transactionLinks.validUntil)', 'lastDate') - .addSelect('MIN(transactionLinks.createdAt)', 'firstDate') - .addSelect('COUNT(*)', 'count') - .where('transactionLinks.userId = :userId', { userId }) - .andWhere('transactionLinks.redeemedAt is NULL') - .andWhere('transactionLinks.validUntil > :date', { date }) - .orderBy('transactionLinks.createdAt', 'DESC') - .getRawOne() - return { - sumHoldAvailableAmount: sumHoldAvailableAmount - ? new Decimal(sumHoldAvailableAmount) - : new Decimal(0), - sumAmount: sumAmount ? new Decimal(sumAmount) : new Decimal(0), - lastDate: lastDate || null, - firstDate: firstDate || null, - transactionLinkcount: count || 0, - } - }, - }) diff --git a/backend/src/util/validate.ts b/backend/src/util/validate.ts index 8c84b06b2..4780c94e8 100644 --- a/backend/src/util/validate.ts +++ b/backend/src/util/validate.ts @@ -1,11 +1,10 @@ -import { getCustomRepository } from '@dbTools/typeorm' import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink' import { Decimal } from 'decimal.js-light' import { Decay } from '@model/Decay' -import { transactionLinkRepository } from '@repository/TransactionLink' import { getLastTransaction } from '@/graphql/resolver/util/getLastTransaction' +import { transactionLinkSummary } from '@/graphql/resolver/util/transactionLinkSummary' import { calculateDecay } from './decay' @@ -26,12 +25,10 @@ async function calculateBalance( const lastTransaction = await getLastTransaction(userId) if (!lastTransaction) return null - console.log(lastTransaction) - const decay = calculateDecay(lastTransaction.balance, lastTransaction.balanceDate, time) const balance = decay.balance.add(amount.toString()) - const { sumHoldAvailableAmount } = await transactionLinkRepository.summary(userId, time) + const { sumHoldAvailableAmount } = await transactionLinkSummary(userId, time) // If we want to redeem a link we need to make sure that the link amount is not considered as blocked // else we cannot redeem links which are more or equal to half of what an account actually owns From c44807dd506f0c3aa7240ddd59e1fe7cbcab475f Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Wed, 28 Jun 2023 13:04:41 +0200 Subject: [PATCH 5/7] get most tests working again --- .../resolver/ContributionLinkResolver.test.ts | 2 +- .../resolver/KlicktippResolver.test.ts | 16 +++--- .../resolver/TransactionLinkResolver.test.ts | 40 ++++++------- .../src/graphql/resolver/UserResolver.test.ts | 14 +++-- backend/src/graphql/resolver/UserResolver.ts | 11 ++-- .../src/graphql/resolver/util/findUsers.ts | 57 +++++++++++++++++++ .../resolver/util/validateAlias.test.ts | 2 +- 7 files changed, 99 insertions(+), 43 deletions(-) create mode 100644 backend/src/graphql/resolver/util/findUsers.ts diff --git a/backend/src/graphql/resolver/ContributionLinkResolver.test.ts b/backend/src/graphql/resolver/ContributionLinkResolver.test.ts index 801e4560b..9605378e2 100644 --- a/backend/src/graphql/resolver/ContributionLinkResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionLinkResolver.test.ts @@ -542,7 +542,7 @@ describe('Contribution Links', () => { }) it('updated the DB record', async () => { - await expect(DbContributionLink.findOne(linkId)).resolves.toEqual( + await expect(DbContributionLink.findOne({ where: { id: linkId } })).resolves.toEqual( expect.objectContaining({ id: linkId, name: 'Dokumenta 2023', diff --git a/backend/src/graphql/resolver/KlicktippResolver.test.ts b/backend/src/graphql/resolver/KlicktippResolver.test.ts index 6a2250bc9..2c819f070 100644 --- a/backend/src/graphql/resolver/KlicktippResolver.test.ts +++ b/backend/src/graphql/resolver/KlicktippResolver.test.ts @@ -72,10 +72,10 @@ describe('KlicktippResolver', () => { }) it('stores the NEWSLETTER_SUBSCRIBE event in the database', async () => { - const userConatct = await UserContact.findOneOrFail( - { email: 'bibi@bloxberg.de' }, - { relations: ['user'] }, - ) + const userConatct = await UserContact.findOneOrFail({ + where: { email: 'bibi@bloxberg.de' }, + relations: ['user'], + }) await expect(DbEvent.find()).resolves.toContainEqual( expect.objectContaining({ type: EventType.NEWSLETTER_SUBSCRIBE, @@ -121,10 +121,10 @@ describe('KlicktippResolver', () => { }) it('stores the NEWSLETTER_UNSUBSCRIBE event in the database', async () => { - const userConatct = await UserContact.findOneOrFail( - { email: 'bibi@bloxberg.de' }, - { relations: ['user'] }, - ) + const userConatct = await UserContact.findOneOrFail({ + where: { email: 'bibi@bloxberg.de' }, + relations: ['user'], + }) await expect(DbEvent.find()).resolves.toContainEqual( expect.objectContaining({ type: EventType.NEWSLETTER_UNSUBSCRIBE, diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.test.ts b/backend/src/graphql/resolver/TransactionLinkResolver.test.ts index 3c6ba31ab..ac76bdecf 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.test.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.test.ts @@ -456,10 +456,10 @@ describe('TransactionLinkResolver', () => { }) it('stores the CONTRIBUTION_LINK_REDEEM event in the database', async () => { - const userConatct = await UserContact.findOneOrFail( - { email: 'bibi@bloxberg.de' }, - { relations: ['user'] }, - ) + const userConatct = await UserContact.findOneOrFail({ + where: { email: 'bibi@bloxberg.de' }, + relations: ['user'], + }) await expect(DbEvent.find()).resolves.toContainEqual( expect.objectContaining({ type: EventType.CONTRIBUTION_LINK_REDEEM, @@ -611,10 +611,10 @@ describe('TransactionLinkResolver', () => { }) it('stores the TRANSACTION_LINK_CREATE event in the database', async () => { - const userConatct = await UserContact.findOneOrFail( - { email: 'bibi@bloxberg.de' }, - { relations: ['user'] }, - ) + const userConatct = await UserContact.findOneOrFail({ + where: { email: 'bibi@bloxberg.de' }, + relations: ['user'], + }) await expect(DbEvent.find()).resolves.toContainEqual( expect.objectContaining({ type: EventType.TRANSACTION_LINK_CREATE, @@ -664,10 +664,10 @@ describe('TransactionLinkResolver', () => { }) it('stores the TRANSACTION_LINK_DELETE event in the database', async () => { - const userConatct = await UserContact.findOneOrFail( - { email: 'bibi@bloxberg.de' }, - { relations: ['user'] }, - ) + const userConatct = await UserContact.findOneOrFail({ + where: { email: 'bibi@bloxberg.de' }, + relations: ['user'], + }) await expect(DbEvent.find()).resolves.toContainEqual( expect.objectContaining({ type: EventType.TRANSACTION_LINK_DELETE, @@ -719,14 +719,14 @@ describe('TransactionLinkResolver', () => { }) it('stores the TRANSACTION_LINK_REDEEM event in the database', async () => { - const creator = await UserContact.findOneOrFail( - { email: 'bibi@bloxberg.de' }, - { relations: ['user'] }, - ) - const redeemer = await UserContact.findOneOrFail( - { email: 'peter@lustig.de' }, - { relations: ['user'] }, - ) + const creator = await UserContact.findOneOrFail({ + where: { email: 'bibi@bloxberg.de' }, + relations: ['user'], + }) + const redeemer = await UserContact.findOneOrFail({ + where: { email: 'peter@lustig.de' }, + relations: ['user'], + }) await expect(DbEvent.find()).resolves.toContainEqual( expect.objectContaining({ type: EventType.TRANSACTION_LINK_REDEEM, diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index bebaa912c..0bd15d7dc 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -447,7 +447,7 @@ describe('UserResolver', () => { memo: `testing transaction link`, }) - transactionLink = await TransactionLink.findOneOrFail({}) + transactionLink = await TransactionLink.findOneOrFail({ where: { userId: bob.id } }) resetToken() @@ -1106,7 +1106,9 @@ describe('UserResolver', () => { errors: [ // keep Whitspace in error message! new GraphQLError(`Could not find any entity of type "UserContact" matching: { - "emailVerificationCode": "not-valid" + "where": { + "emailVerificationCode": "not-valid" + } }`), ], }), @@ -1181,13 +1183,13 @@ describe('UserResolver', () => { locale: 'en', }, }) - await expect(User.findOne({})).resolves.toEqual( + await expect(User.find()).resolves.toEqual([ expect.objectContaining({ firstName: 'Benjamin', lastName: 'Blümchen', language: 'en', }), - ) + ]) }) it('stores the USER_INFO_UPDATE event in the database', async () => { @@ -1218,11 +1220,11 @@ describe('UserResolver', () => { alias: 'bibi_Bloxberg', }, }) - await expect(User.findOne({})).resolves.toEqual( + await expect(User.find()).resolves.toEqual([ expect.objectContaining({ alias: 'bibi_Bloxberg', }), - ) + ]) }) }) }) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 214da858d..c3595071e 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -2,7 +2,7 @@ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/restrict-template-expressions */ -import { getConnection, getCustomRepository, IsNull, Not } from '@dbTools/typeorm' +import { getConnection, IsNull, Not } from '@dbTools/typeorm' import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' import { TransactionLink as DbTransactionLink } from '@entity/TransactionLink' import { User as DbUser } from '@entity/User' @@ -23,7 +23,6 @@ import { UserContactType } from '@enum/UserContactType' import { SearchAdminUsersResult } from '@model/AdminUser' import { User } from '@model/User' import { UserAdmin, SearchUsersResult } from '@model/UserAdmin' -import { UserRepository } from '@repository/User' import { subscribe } from '@/apis/KlicktippController' import { encode } from '@/auth/JWT' @@ -65,6 +64,7 @@ import { randombytes_random } from 'sodium-native' import { FULL_CREATION_AVAILABLE } from './const/const' import { getUserCreations } from './util/creations' import { findUserByIdentifier } from './util/findUserByIdentifier' +import { findUsers } from './util/findUsers' import { getKlicktippState } from './util/getKlicktippState' import { validateAlias } from './util/validateAlias' @@ -603,9 +603,7 @@ export class UserResolver { @Args() { currentPage = 1, pageSize = 25, order = Order.DESC }: Paginated, ): Promise { - const userRepository = getCustomRepository(UserRepository) - - const [users, count] = await userRepository.findAndCount({ + const [users, count] = await DbUser.findAndCount({ where: { isAdmin: Not(IsNull()), }, @@ -638,7 +636,6 @@ export class UserResolver { @Ctx() context: Context, ): Promise { const clientTimezoneOffset = getClientTimezoneOffset(context) - const userRepository = getCustomRepository(UserRepository) const userFields = [ 'id', 'firstName', @@ -648,7 +645,7 @@ export class UserResolver { 'deletedAt', 'isAdmin', ] - const [users, count] = await userRepository.findBySearchCriteriaPagedFiltered( + const [users, count] = await findUsers( userFields.map((fieldName) => { return 'user.' + fieldName }), diff --git a/backend/src/graphql/resolver/util/findUsers.ts b/backend/src/graphql/resolver/util/findUsers.ts new file mode 100644 index 000000000..d01afb904 --- /dev/null +++ b/backend/src/graphql/resolver/util/findUsers.ts @@ -0,0 +1,57 @@ +import { getConnection, Brackets, IsNull, Not } from '@dbTools/typeorm' +import { User as DbUser } from '@entity/User' + +import { SearchUsersFilters } from '@arg/SearchUsersFilters' +import { Order } from '@enum/Order' + +import { LogError } from '@/server/LogError' + +export const findUsers = async ( + select: string[], + searchCriteria: string, + filters: SearchUsersFilters | null, + currentPage: number, + pageSize: number, + order = Order.ASC, +): Promise<[DbUser[], number]> => { + const queryRunner = getConnection().createQueryRunner() + try { + await queryRunner.connect() + const query = queryRunner.manager + .createQueryBuilder(DbUser, 'user') + .select(select) + .withDeleted() + .leftJoinAndSelect('user.emailContact', 'emailContact') + .where( + new Brackets((qb) => { + qb.where( + 'user.firstName like :name or user.lastName like :lastName or emailContact.email like :email', + { + name: `%${searchCriteria}%`, + lastName: `%${searchCriteria}%`, + email: `%${searchCriteria}%`, + }, + ) + }), + ) + if (filters) { + if (filters.byActivated !== null) { + query.andWhere('emailContact.emailChecked = :value', { value: filters.byActivated }) + } + + if (filters.byDeleted !== null) { + query.andWhere({ deletedAt: filters.byDeleted ? Not(IsNull()) : IsNull() }) + } + } + + return await query + .orderBy({ 'user.id': order }) + .take(pageSize) + .skip((currentPage - 1) * pageSize) + .getManyAndCount() + } catch (err) { + throw new LogError('Unable to search users', err) + } finally { + await queryRunner.release() + } +} diff --git a/backend/src/graphql/resolver/util/validateAlias.test.ts b/backend/src/graphql/resolver/util/validateAlias.test.ts index 0cb790edb..5003f8975 100644 --- a/backend/src/graphql/resolver/util/validateAlias.test.ts +++ b/backend/src/graphql/resolver/util/validateAlias.test.ts @@ -95,7 +95,7 @@ describe('validate alias', () => { describe('test against existing alias in database', () => { beforeAll(async () => { const bibi = await userFactory(testEnv, bibiBloxberg) - const user = await User.findOne({ id: bibi.id }) + const user = await User.findOne({ where: { id: bibi.id } }) if (user) { user.alias = 'b-b' await user.save() From d81d0cbd536496ea92e57b8674ab3241619facc9 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Wed, 28 Jun 2023 13:08:41 +0200 Subject: [PATCH 6/7] undo query changes --- backend/src/seeds/graphql/queries.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/backend/src/seeds/graphql/queries.ts b/backend/src/seeds/graphql/queries.ts index 6353fe1cd..a964cdb3a 100644 --- a/backend/src/seeds/graphql/queries.ts +++ b/backend/src/seeds/graphql/queries.ts @@ -235,7 +235,6 @@ export const adminListContributions = gql` $order: Order = DESC $statusFilter: [ContributionStatus!] $userId: Int - $query: String ) { adminListContributions( currentPage: $currentPage @@ -243,7 +242,6 @@ export const adminListContributions = gql` order: $order statusFilter: $statusFilter userId: $userId - query: $query ) { contributionCount contributionList { From abe1d1b71f755ae50a8127eaffb210215f5dd1b6 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Wed, 28 Jun 2023 13:56:08 +0200 Subject: [PATCH 7/7] remove unused file --- backend/src/typeorm/repository/User.ts | 56 -------------------------- 1 file changed, 56 deletions(-) delete mode 100644 backend/src/typeorm/repository/User.ts diff --git a/backend/src/typeorm/repository/User.ts b/backend/src/typeorm/repository/User.ts deleted file mode 100644 index f54859f41..000000000 --- a/backend/src/typeorm/repository/User.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { Brackets, EntityRepository, IsNull, Not, Repository } from '@dbTools/typeorm' -import { User as DbUser } from '@entity/User' - -import { SearchUsersFilters } from '@arg/SearchUsersFilters' -import { Order } from '@enum/Order' - -@EntityRepository(DbUser) -export class UserRepository extends Repository { - async findBySearchCriteriaPagedFiltered( - select: string[], - searchCriteria: string, - filters: SearchUsersFilters | null, - currentPage: number, - pageSize: number, - order = Order.ASC, - ): Promise<[DbUser[], number]> { - const query = this.createQueryBuilder('user') - .select(select) - .withDeleted() - .leftJoinAndSelect('user.emailContact', 'emailContact') - .where( - new Brackets((qb) => { - qb.where( - 'user.firstName like :name or user.lastName like :lastName or emailContact.email like :email', - { - name: `%${searchCriteria}%`, - lastName: `%${searchCriteria}%`, - email: `%${searchCriteria}%`, - }, - ) - }), - ) - /* - filterCriteria.forEach((filter) => { - query.andWhere(filter) - }) - */ - if (filters) { - if (filters.byActivated !== null) { - query.andWhere('emailContact.emailChecked = :value', { value: filters.byActivated }) - // filterCriteria.push({ 'emailContact.emailChecked': filters.byActivated }) - } - - if (filters.byDeleted !== null) { - // filterCriteria.push({ deletedAt: filters.byDeleted ? Not(IsNull()) : IsNull() }) - query.andWhere({ deletedAt: filters.byDeleted ? Not(IsNull()) : IsNull() }) - } - } - - return query - .orderBy({ 'user.id': order }) - .take(pageSize) - .skip((currentPage - 1) * pageSize) - .getManyAndCount() - } -}