From 49c85990975027a9aa1f581bfe092a786a592082 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 22 Jun 2023 15:23:33 +0200 Subject: [PATCH 1/9] add user query on find contributions --- .../resolver/util/findContributions.ts | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/backend/src/graphql/resolver/util/findContributions.ts b/backend/src/graphql/resolver/util/findContributions.ts index 28984d5b1..9204a005e 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 } from '@dbTools/typeorm' import { Contribution as DbContribution } from '@entity/Contribution' import { ContributionStatus } from '@enum/ContributionStatus' @@ -12,21 +12,31 @@ 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: [], ...options, } + const requiredWhere = { + ...(statusFilter?.length && { contributionStatus: In(statusFilter) }), + ...(userId && { userId }), + } + + const where = query + ? [ + { ...requiredWhere, name: Like(`%${query}%`) }, + { ...requiredWhere, lastName: Like(`%${query}%`) }, + { ...requiredWhere, email: Like(`%${query}%`) }, + ] + : requiredWhere return DbContribution.findAndCount({ - where: { - ...(statusFilter?.length && { contributionStatus: In(statusFilter) }), - ...(userId && { userId }), - }, + where, withDeleted, order: { createdAt: order, From 32b6b0bee956982eff977e2e04e3073cd3bfe81a Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Wed, 28 Jun 2023 14:26:46 +0200 Subject: [PATCH 2/9] add query to find contributions, change relations to object notation --- .../graphql/resolver/ContributionResolver.ts | 14 +++-- .../resolver/util/findContributions.ts | 53 +++++++++++++++---- backend/src/seeds/graphql/queries.ts | 2 + 3 files changed, 57 insertions(+), 12 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 2e36eba3f..def01ceb0 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -138,7 +138,7 @@ export class ContributionResolver { currentPage, pageSize, withDeleted: true, - relations: ['messages'], + relations: { messages: true }, userId: user.id, statusFilter, }) @@ -160,7 +160,7 @@ export class ContributionResolver { order, currentPage, pageSize, - relations: ['user'], + relations: { user: true }, statusFilter, }) @@ -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, @@ -379,8 +381,14 @@ export class ContributionResolver { pageSize, withDeleted: true, userId, - relations: ['user', 'messages'], + relations: { + user: { + emailContact: true, + }, + messages: true, + }, statusFilter, + query, }) return new ContributionListResult( diff --git a/backend/src/graphql/resolver/util/findContributions.ts b/backend/src/graphql/resolver/util/findContributions.ts index 28984d5b1..b717abf55 100644 --- a/backend/src/graphql/resolver/util/findContributions.ts +++ b/backend/src/graphql/resolver/util/findContributions.ts @@ -1,38 +1,73 @@ -import { In } from '@dbTools/typeorm' +import { In, Like } from '@dbTools/typeorm' import { Contribution as DbContribution } from '@entity/Contribution' import { ContributionStatus } from '@enum/ContributionStatus' import { Order } from '@enum/Order' +interface Relations { + [key: string]: boolean | Relations +} + interface FindContributionsOptions { order: Order currentPage: number pageSize: number withDeleted?: boolean - relations?: string[] + relations?: Relations | undefined 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: [], + relations: undefined, + query: '', ...options, } + + const requiredWhere = { + ...(statusFilter?.length && { contributionStatus: In(statusFilter) }), + ...(userId && { userId }), + } + + const where = + query && relations && relations.user + ? [ + { + ...requiredWhere, + user: { + firstName: Like(`%${query}%`), + }, + }, + { + ...requiredWhere, + user: { + lastName: Like(`%${query}%`), + }, + }, + { + ...requiredWhere, + user: { + emailContact: { + email: Like(`%${query}%`), + }, + }, + }, + ] + : requiredWhere + return DbContribution.findAndCount({ - where: { - ...(statusFilter?.length && { contributionStatus: In(statusFilter) }), - ...(userId && { userId }), - }, + relations, + where, withDeleted, order: { createdAt: order, id: order, }, - relations, skip: (currentPage - 1) * pageSize, take: pageSize, }) 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 { From 7192b666eec87ca0074ffa1e539f4ceaa09f1c74 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Wed, 28 Jun 2023 14:36:33 +0200 Subject: [PATCH 3/9] test user query on find contribbutions --- .../resolver/ContributionResolver.test.ts | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index 42fe79ff0..590fae064 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -2890,6 +2890,97 @@ describe('ContributionResolver', () => { ]), }) }) + + describe('with user query', () => { + it('returns only contributions of the queried user', async () => { + const { + data: { adminListContributions: contributionListObject }, + } = await query({ + query: adminListContributions, + variables: { + 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', + }), + ]), + }) + }) + + // test for case sensitivity and email + it('returns only contributions of the queried user email', async () => { + const { + data: { adminListContributions: contributionListObject }, + } = await query({ + query: adminListContributions, + variables: { + query: 'RAEUBER', // only found in lowercase in the email + }, + }) + expect(contributionListObject.contributionList).toHaveLength(3) + expect(contributionListObject).toMatchObject({ + contributionCount: 3, + contributionList: expect.arrayContaining([ + expect.objectContaining({ + amount: expect.decimalEqual(166), + firstName: 'Räuber', + id: expect.any(Number), + lastName: 'Hotzenplotz', + memo: 'Whatever contribution', + messagesCount: 0, + state: 'DENIED', + }), + expect.objectContaining({ + amount: expect.decimalEqual(166), + firstName: 'Räuber', + id: expect.any(Number), + lastName: 'Hotzenplotz', + memo: 'Whatever contribution', + messagesCount: 0, + state: 'DELETED', + }), + expect.objectContaining({ + amount: expect.decimalEqual(166), + firstName: 'Räuber', + id: expect.any(Number), + lastName: 'Hotzenplotz', + memo: 'Whatever contribution', + messagesCount: 0, + state: 'CONFIRMED', + }), + ]), + }) + }) + }) }) }) }) From 6030ca08985a0ec21d133871d54d34959736887c Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 29 Jun 2023 14:41:07 +0200 Subject: [PATCH 4/9] change state to status --- .../graphql/resolver/ContributionResolver.test.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index f5c8c51b0..735b6ee69 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -2912,7 +2912,7 @@ describe('ContributionResolver', () => { lastName: 'Lustig', memo: 'Herzlich Willkommen bei Gradido!', messagesCount: 0, - state: 'PENDING', + status: 'PENDING', }), expect.objectContaining({ amount: expect.decimalEqual(100), @@ -2921,7 +2921,7 @@ describe('ContributionResolver', () => { lastName: 'Lustig', memo: 'Test env contribution', messagesCount: 0, - state: 'PENDING', + status: 'PENDING', }), expect.objectContaining({ amount: expect.decimalEqual(200), @@ -2930,7 +2930,7 @@ describe('ContributionResolver', () => { lastName: 'Lustig', memo: 'Das war leider zu Viel!', messagesCount: 0, - state: 'DELETED', + status: 'DELETED', }), ]), }) @@ -2957,7 +2957,7 @@ describe('ContributionResolver', () => { lastName: 'Hotzenplotz', memo: 'Whatever contribution', messagesCount: 0, - state: 'DENIED', + status: 'DENIED', }), expect.objectContaining({ amount: expect.decimalEqual(166), @@ -2966,7 +2966,7 @@ describe('ContributionResolver', () => { lastName: 'Hotzenplotz', memo: 'Whatever contribution', messagesCount: 0, - state: 'DELETED', + status: 'DELETED', }), expect.objectContaining({ amount: expect.decimalEqual(166), @@ -2975,7 +2975,7 @@ describe('ContributionResolver', () => { lastName: 'Hotzenplotz', memo: 'Whatever contribution', messagesCount: 0, - state: 'CONFIRMED', + status: 'CONFIRMED', }), ]), }) From ad3c233ce129219e7b5400212d3dd0f829f85898 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 29 Jun 2023 16:14:37 +0200 Subject: [PATCH 5/9] feat(admin): query users on contributions --- admin/src/components/UserQuery.vue | 37 +++++++++++++++++++++ admin/src/graphql/adminListContributions.js | 2 ++ admin/src/pages/CreationConfirm.vue | 5 +++ 3 files changed, 44 insertions(+) create mode 100644 admin/src/components/UserQuery.vue diff --git a/admin/src/components/UserQuery.vue b/admin/src/components/UserQuery.vue new file mode 100644 index 000000000..2a31a8dea --- /dev/null +++ b/admin/src/components/UserQuery.vue @@ -0,0 +1,37 @@ + + diff --git a/admin/src/graphql/adminListContributions.js b/admin/src/graphql/adminListContributions.js index 3c1dcd69c..6a9a69b17 100644 --- a/admin/src/graphql/adminListContributions.js +++ b/admin/src/graphql/adminListContributions.js @@ -7,6 +7,7 @@ export const adminListContributions = gql` $order: Order = DESC $statusFilter: [ContributionStatus!] $userId: Int + $query: String ) { adminListContributions( currentPage: $currentPage @@ -14,6 +15,7 @@ export const adminListContributions = gql` order: $order statusFilter: $statusFilter userId: $userId + query: $query ) { contributionCount contributionList { diff --git a/admin/src/pages/CreationConfirm.vue b/admin/src/pages/CreationConfirm.vue index fbbe03406..9218ecab7 100644 --- a/admin/src/pages/CreationConfirm.vue +++ b/admin/src/pages/CreationConfirm.vue @@ -1,6 +1,7 @@