From e35104faa86c771bc5bdb0cd5426ccba108c7550 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 26 Jun 2023 13:59:42 +0200 Subject: [PATCH] get backend running with new typeorm version --- backend/.eslintrc.js | 2 +- .../src/graphql/resolver/BalanceResolver.ts | 4 +- .../resolver/ContributionLinkResolver.ts | 4 +- .../resolver/ContributionMessageResolver.ts | 4 +- .../resolver/ContributionResolver.test.ts | 58 +++++++++++++++++++ .../graphql/resolver/ContributionResolver.ts | 42 ++++++++------ .../resolver/TransactionLinkResolver.ts | 37 +++++++----- backend/src/graphql/resolver/UserResolver.ts | 20 ++++--- .../resolver/util/findContributions.ts | 33 +++++++++-- .../resolver/util/findUserByIdentifier.ts | 10 ++-- .../resolver/util/getLastTransaction.ts | 14 ++--- .../resolver/util/transactionLinkList.ts | 4 +- backend/src/seeds/graphql/queries.ts | 2 + backend/src/server/context.ts | 2 +- backend/src/typeorm/DBVersion.ts | 2 +- backend/src/util/hasElopageBuys.ts | 2 +- 16 files changed, 167 insertions(+), 73 deletions(-) diff --git a/backend/.eslintrc.js b/backend/.eslintrc.js index e853c8bf6..0df8aca46 100644 --- a/backend/.eslintrc.js +++ b/backend/.eslintrc.js @@ -40,7 +40,7 @@ module.exports = { ], // import 'import/export': 'error', - 'import/no-deprecated': 'error', + // 'import/no-deprecated': 'error', 'import/no-empty-named-blocks': 'error', 'import/no-extraneous-dependencies': 'error', 'import/no-mutable-exports': 'error', diff --git a/backend/src/graphql/resolver/BalanceResolver.ts b/backend/src/graphql/resolver/BalanceResolver.ts index c8fdacdcf..9cd133181 100644 --- a/backend/src/graphql/resolver/BalanceResolver.ts +++ b/backend/src/graphql/resolver/BalanceResolver.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/restrict-template-expressions */ -import { getCustomRepository } from '@dbTools/typeorm' +import { getCustomRepository, IsNull } from '@dbTools/typeorm' import { Transaction as dbTransaction } from '@entity/Transaction' import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink' import { Decimal } from 'decimal.js-light' @@ -57,7 +57,7 @@ export class BalanceResolver { const linkCount = await dbTransactionLink.count({ where: { userId: user.id, - redeemedAt: null, + redeemedAt: IsNull(), // validUntil: MoreThan(new Date()), }, }) diff --git a/backend/src/graphql/resolver/ContributionLinkResolver.ts b/backend/src/graphql/resolver/ContributionLinkResolver.ts index 1dcf6a3cb..808bd584e 100644 --- a/backend/src/graphql/resolver/ContributionLinkResolver.ts +++ b/backend/src/graphql/resolver/ContributionLinkResolver.ts @@ -103,7 +103,7 @@ export class ContributionLinkResolver { @Arg('id', () => Int) id: number, @Ctx() context: Context, ): Promise { - const dbContributionLink = await DbContributionLink.findOne(id) + const dbContributionLink = await DbContributionLink.findOne({ where: { id } }) if (!dbContributionLink) { throw new LogError('Contribution Link not found', id) } @@ -130,7 +130,7 @@ export class ContributionLinkResolver { @Arg('id', () => Int) id: number, @Ctx() context: Context, ): Promise { - const dbContributionLink = await DbContributionLink.findOne(id) + const dbContributionLink = await DbContributionLink.findOne({ where: { id } }) if (!dbContributionLink) { throw new LogError('Contribution Link not found', id) } diff --git a/backend/src/graphql/resolver/ContributionMessageResolver.ts b/backend/src/graphql/resolver/ContributionMessageResolver.ts index b7fd37787..cc21f6e91 100644 --- a/backend/src/graphql/resolver/ContributionMessageResolver.ts +++ b/backend/src/graphql/resolver/ContributionMessageResolver.ts @@ -36,7 +36,7 @@ export class ContributionMessageResolver { await queryRunner.startTransaction('REPEATABLE READ') const contributionMessage = DbContributionMessage.create() try { - const contribution = await DbContribution.findOne({ id: contributionId }) + const contribution = await DbContribution.findOne({ where: { id: contributionId } }) if (!contribution) { throw new LogError('Contribution not found', contributionId) } @@ -124,7 +124,7 @@ export class ContributionMessageResolver { if (contribution.userId === moderator.id) { throw new LogError('Admin can not answer on his own contribution', contributionId) } - if (!contribution.user.emailContact) { + if (!contribution.user.emailContact && contribution.user.emailId) { contribution.user.emailContact = await DbUserContact.findOneOrFail({ where: { id: contribution.user.emailId }, }) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index d4c84b4f3..81e913dde 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -2890,6 +2890,64 @@ 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 fa1590523..9727d6015 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -101,7 +101,7 @@ export class ContributionResolver { @Ctx() context: Context, ): Promise { const user = getUser(context) - const contribution = await DbContribution.findOne(id) + const contribution = await DbContribution.findOne({ where: { id } }) if (!contribution) { throw new LogError('Contribution not found', id) } @@ -372,6 +372,8 @@ 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, @@ -381,6 +383,7 @@ export class ContributionResolver { userId, relations: ['user', 'messages'], statusFilter, + query, }) return new ContributionListResult( @@ -395,7 +398,7 @@ export class ContributionResolver { @Arg('id', () => Int) id: number, @Ctx() context: Context, ): Promise { - const contribution = await DbContribution.findOne(id) + const contribution = await DbContribution.findOne({ where: { id } }) if (!contribution) { throw new LogError('Contribution not found', id) } @@ -409,10 +412,10 @@ export class ContributionResolver { ) { throw new LogError('Own contribution can not be deleted as admin') } - const user = await DbUser.findOneOrFail( - { id: contribution.userId }, - { relations: ['emailContact'] }, - ) + const user = await DbUser.findOneOrFail({ + where: { id: contribution.userId }, + relations: ['emailContact'], + }) contribution.contributionStatus = ContributionStatus.DELETED contribution.deletedBy = moderator.id await contribution.save() @@ -447,7 +450,7 @@ export class ContributionResolver { const releaseLock = await TRANSACTIONS_LOCK.acquire() try { const clientTimezoneOffset = getClientTimezoneOffset(context) - const contribution = await DbContribution.findOne(id) + const contribution = await DbContribution.findOne({ where: { id } }) if (!contribution) { throw new LogError('Contribution not found', id) } @@ -461,10 +464,11 @@ export class ContributionResolver { if (moderatorUser.id === contribution.userId) { throw new LogError('Moderator can not confirm own contribution') } - const user = await DbUser.findOneOrFail( - { id: contribution.userId }, - { withDeleted: true, relations: ['emailContact'] }, - ) + const user = await DbUser.findOneOrFail({ + where: { id: contribution.userId }, + withDeleted: true, + relations: ['emailContact'], + }) if (user.deletedAt) { throw new LogError('Can not confirm contribution since the user was deleted') } @@ -565,9 +569,11 @@ export class ContributionResolver { @Ctx() context: Context, ): Promise { const contributionToUpdate = await DbContribution.findOne({ - id, - confirmedAt: IsNull(), - deniedBy: IsNull(), + where: { + id, + confirmedAt: IsNull(), + deniedBy: IsNull(), + }, }) if (!contributionToUpdate) { throw new LogError('Contribution not found', id) @@ -582,10 +588,10 @@ export class ContributionResolver { ) } const moderator = getUser(context) - const user = await DbUser.findOne( - { id: contributionToUpdate.userId }, - { relations: ['emailContact'] }, - ) + const user = await DbUser.findOne({ + where: { id: contributionToUpdate.userId }, + relations: ['emailContact'], + }) if (!user) { throw new LogError('Could not find User of the Contribution', contributionToUpdate.userId) } diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.ts b/backend/src/graphql/resolver/TransactionLinkResolver.ts index d6649814a..0ff606fa5 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.ts @@ -108,7 +108,7 @@ export class TransactionLinkResolver { ): Promise { const user = getUser(context) - const transactionLink = await DbTransactionLink.findOne({ id }) + const transactionLink = await DbTransactionLink.findOne({ where: { id } }) if (!transactionLink) { throw new LogError('Transaction link not found', id) } @@ -138,17 +138,22 @@ export class TransactionLinkResolver { @Query(() => QueryLinkResult) async queryTransactionLink(@Arg('code') code: string): Promise { if (code.match(/^CL-/)) { - const contributionLink = await DbContributionLink.findOneOrFail( - { code: code.replace('CL-', '') }, - { withDeleted: true }, - ) + const contributionLink = await DbContributionLink.findOneOrFail({ + where: { code: code.replace('CL-', '') }, + withDeleted: true, + }) return new ContributionLink(contributionLink) } else { - const transactionLink = await DbTransactionLink.findOneOrFail({ code }, { withDeleted: true }) - const user = await DbUser.findOneOrFail({ id: transactionLink.userId }) + const transactionLink = await DbTransactionLink.findOneOrFail({ + where: { code }, + withDeleted: true, + }) + const user = await DbUser.findOneOrFail({ where: { id: transactionLink.userId } }) let redeemedBy: User | null = null if (transactionLink?.redeemedBy) { - redeemedBy = new User(await DbUser.findOneOrFail({ id: transactionLink.redeemedBy })) + redeemedBy = new User( + await DbUser.findOneOrFail({ where: { id: transactionLink.redeemedBy } }), + ) } return new TransactionLink(transactionLink, new User(user), redeemedBy) } @@ -191,7 +196,7 @@ export class TransactionLinkResolver { throw new LogError('Contribution link is no longer valid', contributionLink.validTo) } } - let alreadyRedeemed: DbContribution | undefined + let alreadyRedeemed: DbContribution | null switch (contributionLink.cycle) { case ContributionCycleType.ONCE: { alreadyRedeemed = await queryRunner.manager @@ -302,15 +307,17 @@ export class TransactionLinkResolver { return true } else { const now = new Date() - const transactionLink = await DbTransactionLink.findOne({ code }) + const transactionLink = await DbTransactionLink.findOne({ where: { code } }) if (!transactionLink) { throw new LogError('Transaction link not found', code) } - const linkedUser = await DbUser.findOne( - { id: transactionLink.userId }, - { relations: ['emailContact'] }, - ) + const linkedUser = await DbUser.findOne({ + where: { + id: transactionLink.userId, + }, + relations: ['emailContact'], + }) if (!linkedUser) { throw new LogError('Linked user not found for given link', transactionLink.userId) @@ -378,7 +385,7 @@ export class TransactionLinkResolver { @Arg('userId', () => Int) userId: number, ): Promise { - const user = await DbUser.findOne({ id: userId }) + const user = await DbUser.findOne({ where: { id: userId } }) if (!user) { throw new LogError('Could not find requested User', userId) } diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 19f59e1a3..840bb43c9 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, getCustomRepository, IsNull, Not, Equal } from '@dbTools/typeorm' import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' import { TransactionLink as DbTransactionLink } from '@entity/TransactionLink' import { User as DbUser } from '@entity/User' @@ -278,7 +278,7 @@ export class UserResolver { eventRegisterRedeem.involvedContributionLink = contributionLink } } else { - const transactionLink = await DbTransactionLink.findOne({ where: { code: redeemCode } }) + const transactionLink = await DbTransactionLink.findOne({ where: { code: redeemCode } }) logger.info('redeemCode found transactionLink', transactionLink) if (transactionLink) { dbUser.referrerId = transactionLink.userId @@ -403,8 +403,8 @@ export class UserResolver { } // load code - const userContact = await DbUserContact.findOne({ - where: { emailVerificationCode: code }, + const userContact = await DbUserContact.findOneOrFail({ + where: { emailVerificationCode: Equal(BigInt(code)) }, relations: ['user'], }).catch(() => { throw new LogError('Could not login with emailVerificationCode') @@ -474,7 +474,9 @@ export class UserResolver { @Query(() => Boolean) async queryOptIn(@Arg('optIn') optIn: string): Promise { logger.info(`queryOptIn(${optIn})...`) - const userContact = await DbUserContact.findOneOrFail({ where: { emailVerificationCode: optIn } }) + const userContact = await DbUserContact.findOneOrFail({ + where: { emailVerificationCode: Equal(BigInt(optIn)) }, + }) logger.debug('found optInCode', userContact) // Code is only valid for `CONFIG.EMAIL_CODE_VALID_TIME` minutes if (!isEmailVerificationCodeValid(userContact.updatedAt || userContact.createdAt)) { @@ -734,7 +736,7 @@ export class UserResolver { } await user.save() await EVENT_ADMIN_USER_ROLE_SET(user, moderator) - const newUser = await DbUser.findOne({ where: { id: userId } }) + const newUser = await DbUser.findOne({ where: { id: userId } }) return newUser ? newUser.isAdmin : null } @@ -744,7 +746,7 @@ export class UserResolver { @Arg('userId', () => Int) userId: number, @Ctx() context: Context, ): Promise { - const user = await DbUser.findOne({ id: userId }) + const user = await DbUser.findOne({ where: { id: userId } }) // user exists ? if (!user) { throw new LogError('Could not find user with given ID', userId) @@ -757,7 +759,7 @@ export class UserResolver { // soft-delete user await user.softRemove() await EVENT_ADMIN_USER_DELETE(user, moderator) - const newUser = await DbUser.findOne({ where: { id: userId }, withDeleted: true }) + const newUser = await DbUser.findOne({ where: { id: userId }, withDeleted: true }) return newUser ? newUser.deletedAt : null } @@ -822,7 +824,7 @@ export async function findUserByEmail(email: string): Promise { const dbUserContact = await DbUserContact.findOneOrFail({ where: { email }, withDeleted: true, - relations: ['user'] + relations: ['user'], }).catch(() => { throw new LogError('No user with this credentials', email) }) diff --git a/backend/src/graphql/resolver/util/findContributions.ts b/backend/src/graphql/resolver/util/findContributions.ts index 28984d5b1..66038538a 100644 --- a/backend/src/graphql/resolver/util/findContributions.ts +++ b/backend/src/graphql/resolver/util/findContributions.ts @@ -1,4 +1,4 @@ -import { In } from '@dbTools/typeorm' +import { In, Like, FindOperator } from '@dbTools/typeorm' import { Contribution as DbContribution } from '@entity/Contribution' import { ContributionStatus } from '@enum/ContributionStatus' @@ -12,27 +12,48 @@ 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 } = { + const { order, currentPage, pageSize, withDeleted, relations, userId, statusFilter, query } = { 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({ - where: { - ...(statusFilter?.length && { contributionStatus: In(statusFilter) }), - ...(userId && { userId }), + relations: { + user: { + emailContact: true, + }, + messages: true, }, withDeleted, + where, order: { createdAt: order, id: order, }, - relations, skip: (currentPage - 1) * pageSize, take: pageSize, }) diff --git a/backend/src/graphql/resolver/util/findUserByIdentifier.ts b/backend/src/graphql/resolver/util/findUserByIdentifier.ts index bd9a25071..96c9eb458 100644 --- a/backend/src/graphql/resolver/util/findUserByIdentifier.ts +++ b/backend/src/graphql/resolver/util/findUserByIdentifier.ts @@ -7,20 +7,20 @@ import { LogError } from '@/server/LogError' import { VALID_ALIAS_REGEX } from './validateAlias' export const findUserByIdentifier = async (identifier: string): Promise => { - let user: DbUser | undefined + let user: DbUser | null if (validate(identifier) && version(identifier) === 4) { user = await DbUser.findOne({ where: { gradidoID: identifier }, relations: ['emailContact'] }) if (!user) { throw new LogError('No user found to given identifier', identifier) } } else if (/^.{2,}@.{2,}\..{2,}$/.exec(identifier)) { - const userContact = await DbUserContact.findOne( - { + const userContact = await DbUserContact.findOne({ + where: { email: identifier, emailChecked: true, }, - { relations: ['user'] }, - ) + relations: ['user'], + }) if (!userContact) { throw new LogError('No user with this credentials', identifier) } diff --git a/backend/src/graphql/resolver/util/getLastTransaction.ts b/backend/src/graphql/resolver/util/getLastTransaction.ts index 5b3e862c2..0d7747088 100644 --- a/backend/src/graphql/resolver/util/getLastTransaction.ts +++ b/backend/src/graphql/resolver/util/getLastTransaction.ts @@ -3,12 +3,10 @@ import { Transaction as DbTransaction } from '@entity/Transaction' export const getLastTransaction = async ( userId: number, relations?: string[], -): Promise => { - return DbTransaction.findOne( - { userId }, - { - order: { balanceDate: 'DESC', id: 'DESC' }, - relations, - }, - ) +): Promise => { + return DbTransaction.findOne({ + where: { userId }, + order: { balanceDate: 'DESC', id: 'DESC' }, + relations, + }) } diff --git a/backend/src/graphql/resolver/util/transactionLinkList.ts b/backend/src/graphql/resolver/util/transactionLinkList.ts index ee79216c8..653f86804 100644 --- a/backend/src/graphql/resolver/util/transactionLinkList.ts +++ b/backend/src/graphql/resolver/util/transactionLinkList.ts @@ -1,4 +1,4 @@ -import { MoreThan } from '@dbTools/typeorm' +import { MoreThan, IsNull } from '@dbTools/typeorm' import { TransactionLink as DbTransactionLink } from '@entity/TransactionLink' import { User as DbUser } from '@entity/User' @@ -22,7 +22,7 @@ export async function transactionLinkList( const [transactionLinks, count] = await DbTransactionLink.findAndCount({ where: { userId: user.id, - ...(!withRedeemed && { redeemedBy: null }), + ...(!withRedeemed && { redeemedBy: IsNull() }), ...(!withExpired && { validUntil: MoreThan(new Date()) }), }, withDeleted, diff --git a/backend/src/seeds/graphql/queries.ts b/backend/src/seeds/graphql/queries.ts index a964cdb3a..6353fe1cd 100644 --- a/backend/src/seeds/graphql/queries.ts +++ b/backend/src/seeds/graphql/queries.ts @@ -235,6 +235,7 @@ export const adminListContributions = gql` $order: Order = DESC $statusFilter: [ContributionStatus!] $userId: Int + $query: String ) { adminListContributions( currentPage: $currentPage @@ -242,6 +243,7 @@ export const adminListContributions = gql` order: $order statusFilter: $statusFilter userId: $userId + query: $query ) { contributionCount contributionList { diff --git a/backend/src/server/context.ts b/backend/src/server/context.ts index c7e59365b..45f0a6c1f 100644 --- a/backend/src/server/context.ts +++ b/backend/src/server/context.ts @@ -15,7 +15,7 @@ export interface Context { clientTimezoneOffset?: number gradidoID?: string // hack to use less DB calls for Balance Resolver - lastTransaction?: dbTransaction + lastTransaction?: dbTransaction | null transactionCount?: number linkCount?: number sumHoldAvailableAmount?: Decimal diff --git a/backend/src/typeorm/DBVersion.ts b/backend/src/typeorm/DBVersion.ts index f465069d3..acde7c1f0 100644 --- a/backend/src/typeorm/DBVersion.ts +++ b/backend/src/typeorm/DBVersion.ts @@ -4,7 +4,7 @@ import { backendLogger as logger } from '@/server/logger' const getDBVersion = async (): Promise => { try { - const dbVersion = await Migration.findOne({ order: { version: 'DESC' } }) + const [dbVersion] = await Migration.find({ order: { version: 'DESC' }, take: 1 }) return dbVersion ? dbVersion.fileName : null } catch (error) { logger.error(error) diff --git a/backend/src/util/hasElopageBuys.ts b/backend/src/util/hasElopageBuys.ts index 4e23e717c..1465e76e2 100644 --- a/backend/src/util/hasElopageBuys.ts +++ b/backend/src/util/hasElopageBuys.ts @@ -1,6 +1,6 @@ import { LoginElopageBuys } from '@entity/LoginElopageBuys' export async function hasElopageBuys(email: string): Promise { - const elopageBuyCount = await LoginElopageBuys.count({ payerEmail: email }) + const elopageBuyCount = await LoginElopageBuys.count({ where: { payerEmail: email } }) return elopageBuyCount > 0 }