From 3e471eb81ee0037e40c6d127e90ef546250378aa Mon Sep 17 00:00:00 2001 From: ogerly Date: Tue, 12 Jul 2022 16:54:37 +0200 Subject: [PATCH 01/30] add creation on login query and store --- frontend/src/graphql/queries.js | 2 ++ frontend/src/store/store.js | 6 ++++++ frontend/src/store/store.test.js | 25 +++++++++++++++++++++++-- 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/frontend/src/graphql/queries.js b/frontend/src/graphql/queries.js index adcd653a4..27e63d568 100644 --- a/frontend/src/graphql/queries.js +++ b/frontend/src/graphql/queries.js @@ -13,6 +13,7 @@ export const login = gql` hasElopage publisherId isAdmin + creation } } ` @@ -30,6 +31,7 @@ export const verifyLogin = gql` hasElopage publisherId isAdmin + creation } } ` diff --git a/frontend/src/store/store.js b/frontend/src/store/store.js index e95eec7b9..8fdbc519e 100644 --- a/frontend/src/store/store.js +++ b/frontend/src/store/store.js @@ -47,6 +47,9 @@ export const mutations = { hasElopage: (state, hasElopage) => { state.hasElopage = hasElopage }, + creation: (state, creation) => { + state.creation = creation + }, } export const actions = { @@ -60,6 +63,7 @@ export const actions = { commit('hasElopage', data.hasElopage) commit('publisherId', data.publisherId) commit('isAdmin', data.isAdmin) + commit('creation', data.creation) }, logout: ({ commit, state }) => { commit('token', null) @@ -71,6 +75,7 @@ export const actions = { commit('hasElopage', false) commit('publisherId', null) commit('isAdmin', false) + commit('creation', null) localStorage.clear() }, } @@ -96,6 +101,7 @@ try { newsletterState: null, hasElopage: false, publisherId: null, + creation: null, }, getters: {}, // Syncronous mutation of the state diff --git a/frontend/src/store/store.test.js b/frontend/src/store/store.test.js index 3f942fa35..0493d7f53 100644 --- a/frontend/src/store/store.test.js +++ b/frontend/src/store/store.test.js @@ -30,6 +30,7 @@ const { publisherId, isAdmin, hasElopage, + creation, } = mutations const { login, logout } = actions @@ -139,6 +140,14 @@ describe('Vuex store', () => { expect(state.hasElopage).toBeTruthy() }) }) + + describe('creation', () => { + it('sets the state of creation', () => { + const state = { creation: null } + creation(state, true) + expect(state.creation).toEqual(true) + }) + }) }) describe('actions', () => { @@ -156,11 +165,12 @@ describe('Vuex store', () => { hasElopage: false, publisherId: 1234, isAdmin: true, + creation: ['1000', '1000', '1000'], } it('calls nine commits', () => { login({ commit, state }, commitedData) - expect(commit).toHaveBeenCalledTimes(8) + expect(commit).toHaveBeenCalledTimes(9) }) it('commits email', () => { @@ -202,6 +212,11 @@ describe('Vuex store', () => { login({ commit, state }, commitedData) expect(commit).toHaveBeenNthCalledWith(8, 'isAdmin', true) }) + + it('commits creation', () => { + login({ commit, state }, commitedData) + expect(commit).toHaveBeenNthCalledWith(9, 'creation', ['1000', '1000', '1000']) + }) }) describe('logout', () => { @@ -210,7 +225,7 @@ describe('Vuex store', () => { it('calls nine commits', () => { logout({ commit, state }) - expect(commit).toHaveBeenCalledTimes(8) + expect(commit).toHaveBeenCalledTimes(9) }) it('commits token', () => { @@ -253,6 +268,12 @@ describe('Vuex store', () => { expect(commit).toHaveBeenNthCalledWith(8, 'isAdmin', false) }) + it('commits creation', () => { + logout({ commit, state }) + expect(commit).toHaveBeenNthCalledWith(9, 'creation', null) + }) + + // how to get this working? it.skip('calls localStorage.clear()', () => { const clearStorageMock = jest.fn() From bc8078c427883aa5192a5d1b54556fb8f285e5d6 Mon Sep 17 00:00:00 2001 From: ogerly Date: Tue, 12 Jul 2022 16:55:50 +0200 Subject: [PATCH 02/30] fix lint --- frontend/src/store/store.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/store/store.test.js b/frontend/src/store/store.test.js index 0493d7f53..651a3ccc5 100644 --- a/frontend/src/store/store.test.js +++ b/frontend/src/store/store.test.js @@ -273,7 +273,6 @@ describe('Vuex store', () => { expect(commit).toHaveBeenNthCalledWith(9, 'creation', null) }) - // how to get this working? it.skip('calls localStorage.clear()', () => { const clearStorageMock = jest.fn() From 9d9d1a78f18abda66333139ac1b4ffd66e631607 Mon Sep 17 00:00:00 2001 From: elweyn Date: Wed, 13 Jul 2022 11:01:44 +0200 Subject: [PATCH 03/30] Add confirmedBy and confirmedAt for the contribution query. --- backend/src/graphql/model/Contribution.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/backend/src/graphql/model/Contribution.ts b/backend/src/graphql/model/Contribution.ts index dc1dd39e9..348a6eb98 100644 --- a/backend/src/graphql/model/Contribution.ts +++ b/backend/src/graphql/model/Contribution.ts @@ -12,6 +12,8 @@ export class Contribution { this.memo = contribution.memo this.createdAt = contribution.createdAt this.deletedAt = contribution.deletedAt + this.confirmedAt = contribution.confirmedAt + this.confirmedBy = contribution.confirmedBy } @Field(() => Number) @@ -31,6 +33,12 @@ export class Contribution { @Field(() => Date, { nullable: true }) deletedAt: Date | null + + @Field(() => Date, { nullable: true }) + confirmedAt: Date | null + + @Field(() => Number, { nullable: true }) + confirmedBy: number | null } @ObjectType() From 99c4e8367048fe1d100a307be5febd84b6036177 Mon Sep 17 00:00:00 2001 From: elweyn Date: Wed, 13 Jul 2022 11:26:18 +0200 Subject: [PATCH 04/30] Add deleted contribution to the list of contribution. --- backend/src/graphql/resolver/ContributionResolver.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 4424b40d0..562859116 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -58,6 +58,7 @@ export class ContributionResolver { order: { createdAt: order, }, + withDeleted: true, skip: (currentPage - 1) * pageSize, take: pageSize, }) From b7c24978392ae1f74baf3442ed32521d167c6637 Mon Sep 17 00:00:00 2001 From: elweyn Date: Wed, 13 Jul 2022 12:18:47 +0200 Subject: [PATCH 05/30] Add new right LIST_ALL_CONFIRMED_CONTRIBUTIONS. --- backend/src/auth/RIGHTS.ts | 1 + backend/src/auth/ROLES.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/backend/src/auth/RIGHTS.ts b/backend/src/auth/RIGHTS.ts index 6a6f8b7c0..975c2006a 100644 --- a/backend/src/auth/RIGHTS.ts +++ b/backend/src/auth/RIGHTS.ts @@ -27,6 +27,7 @@ export enum RIGHTS { GDT_BALANCE = 'GDT_BALANCE', CREATE_CONTRIBUTION = 'CREATE_CONTRIBUTION', LIST_CONTRIBUTIONS = 'LIST_CONTRIBUTIONS', + LIST_ALL_CONFIRMED_CONTRIBUTIONS = 'LIST_ALL_CONFIRMED_CONTRIBUTIONS', // Admin SEARCH_USERS = 'SEARCH_USERS', SET_USER_ROLE = 'SET_USER_ROLE', diff --git a/backend/src/auth/ROLES.ts b/backend/src/auth/ROLES.ts index f56106664..e5628bb62 100644 --- a/backend/src/auth/ROLES.ts +++ b/backend/src/auth/ROLES.ts @@ -25,6 +25,7 @@ export const ROLE_USER = new Role('user', [ RIGHTS.GDT_BALANCE, RIGHTS.CREATE_CONTRIBUTION, RIGHTS.LIST_CONTRIBUTIONS, + RIGHTS.LIST_ALL_CONFIRMED_CONTRIBUTIONS, ]) export const ROLE_ADMIN = new Role('admin', Object.values(RIGHTS)) // all rights From ed10d7d1a00b8cc8ae65d6efa1323921e800e649 Mon Sep 17 00:00:00 2001 From: mahula Date: Wed, 13 Jul 2022 14:54:17 +0200 Subject: [PATCH 06/30] set session timer to 0, if expiration is greater then 0 seconds --- frontend/src/components/SessionLogoutTimeout.vue | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/SessionLogoutTimeout.vue b/frontend/src/components/SessionLogoutTimeout.vue index 1e5a27998..113362abf 100644 --- a/frontend/src/components/SessionLogoutTimeout.vue +++ b/frontend/src/components/SessionLogoutTimeout.vue @@ -65,7 +65,7 @@ export default { this.$timer.restart('tokenExpires') this.$bvModal.show('modalSessionTimeOut') } - if (this.tokenExpiresInSeconds <= 0) { + if (this.tokenExpiresInSeconds === 0) { this.$timer.stop('tokenExpires') this.$emit('logout') } @@ -90,7 +90,11 @@ export default { }, computed: { tokenExpiresInSeconds() { - return Math.floor((new Date(this.$store.state.tokenTime * 1000).getTime() - this.now) / 1000) + const remainingSecs = Math.floor( + (new Date(this.$store.state.tokenTime * 1000).getTime() - this.now) / 1000, + ) + if (remainingSecs <= 0) return 0 + return remainingSecs }, }, beforeDestroy() { From b2164e6d1dc90fed257fcbb95601b5b5cc218e46 Mon Sep 17 00:00:00 2001 From: mahula Date: Wed, 13 Jul 2022 14:54:47 +0200 Subject: [PATCH 07/30] add unit test for this fix --- frontend/src/components/SessionLogoutTimeout.spec.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/SessionLogoutTimeout.spec.js b/frontend/src/components/SessionLogoutTimeout.spec.js index 0f5d21d36..94751f9cb 100644 --- a/frontend/src/components/SessionLogoutTimeout.spec.js +++ b/frontend/src/components/SessionLogoutTimeout.spec.js @@ -62,12 +62,16 @@ describe('SessionLogoutTimeout', () => { }) }) - describe('token is expired', () => { + describe('token is expired for several seconds', () => { beforeEach(() => { mocks.$store.state.tokenTime = setTokenTime(-60) wrapper = Wrapper() }) + it('value for remaining seconds is 0', () => { + expect(wrapper.tokenExpiresInSeconds === 0) + }) + it('emits logout', () => { expect(wrapper.emitted('logout')).toBeTruthy() }) From 1d1cc7e960aa845de7a659f6e5f4f25442c52e1b Mon Sep 17 00:00:00 2001 From: mahula Date: Wed, 13 Jul 2022 15:36:15 +0200 Subject: [PATCH 08/30] Update frontend/src/components/SessionLogoutTimeout.spec.js Co-authored-by: Moriz Wahl --- frontend/src/components/SessionLogoutTimeout.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/SessionLogoutTimeout.spec.js b/frontend/src/components/SessionLogoutTimeout.spec.js index 94751f9cb..bd6911d13 100644 --- a/frontend/src/components/SessionLogoutTimeout.spec.js +++ b/frontend/src/components/SessionLogoutTimeout.spec.js @@ -68,7 +68,7 @@ describe('SessionLogoutTimeout', () => { wrapper = Wrapper() }) - it('value for remaining seconds is 0', () => { + it('has value for remaining seconds equal 0', () => { expect(wrapper.tokenExpiresInSeconds === 0) }) From 2302da9054785b8b4a7ca330fd1ddbdd42826ce0 Mon Sep 17 00:00:00 2001 From: mahula Date: Wed, 13 Jul 2022 15:36:40 +0200 Subject: [PATCH 09/30] Update frontend/src/components/SessionLogoutTimeout.vue Co-authored-by: Moriz Wahl --- frontend/src/components/SessionLogoutTimeout.vue | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/src/components/SessionLogoutTimeout.vue b/frontend/src/components/SessionLogoutTimeout.vue index 113362abf..f10b8114a 100644 --- a/frontend/src/components/SessionLogoutTimeout.vue +++ b/frontend/src/components/SessionLogoutTimeout.vue @@ -93,8 +93,7 @@ export default { const remainingSecs = Math.floor( (new Date(this.$store.state.tokenTime * 1000).getTime() - this.now) / 1000, ) - if (remainingSecs <= 0) return 0 - return remainingSecs + return remainingSecs <= 0 ? 0 : remainingSecs }, }, beforeDestroy() { From 90d90ca9bd9960457aa6a3267e73628d21675519 Mon Sep 17 00:00:00 2001 From: mahula Date: Wed, 13 Jul 2022 19:04:38 +0200 Subject: [PATCH 10/30] fix linting --- frontend/src/components/SessionLogoutTimeout.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/SessionLogoutTimeout.vue b/frontend/src/components/SessionLogoutTimeout.vue index f10b8114a..1ebff752a 100644 --- a/frontend/src/components/SessionLogoutTimeout.vue +++ b/frontend/src/components/SessionLogoutTimeout.vue @@ -93,7 +93,7 @@ export default { const remainingSecs = Math.floor( (new Date(this.$store.state.tokenTime * 1000).getTime() - this.now) / 1000, ) - return remainingSecs <= 0 ? 0 : remainingSecs + return remainingSecs <= 0 ? 0 : remainingSecs }, }, beforeDestroy() { From 7c698de325294811d144f6ac7bac058d44200735 Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 14 Jul 2022 12:25:45 +0200 Subject: [PATCH 11/30] Add constructor to ContributionListResult. --- backend/src/graphql/model/Contribution.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/backend/src/graphql/model/Contribution.ts b/backend/src/graphql/model/Contribution.ts index dc1dd39e9..989296848 100644 --- a/backend/src/graphql/model/Contribution.ts +++ b/backend/src/graphql/model/Contribution.ts @@ -35,6 +35,11 @@ export class Contribution { @ObjectType() export class ContributionListResult { + constructor(count: number, list: Contribution[]) { + this.linkCount = count + this.linkList = list + } + @Field(() => Int) linkCount: number From 2f90bd981126ef77f744beacb5fa8d27bc3cc225 Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 14 Jul 2022 12:58:01 +0200 Subject: [PATCH 12/30] Withdrew User from Contribution object and replaced it with userId, firstName and lastName. --- backend/src/graphql/model/Contribution.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/backend/src/graphql/model/Contribution.ts b/backend/src/graphql/model/Contribution.ts index 989296848..324b0ff07 100644 --- a/backend/src/graphql/model/Contribution.ts +++ b/backend/src/graphql/model/Contribution.ts @@ -7,7 +7,9 @@ import { User } from './User' export class Contribution { constructor(contribution: dbContribution, user: User) { this.id = contribution.id - this.user = user + this.userId = user ? user.id : null + this.firstName = user ? user.firstName : null + this.lastName = user ? user.lastName : null this.amount = contribution.amount this.memo = contribution.memo this.createdAt = contribution.createdAt @@ -17,8 +19,14 @@ export class Contribution { @Field(() => Number) id: number - @Field(() => User) - user: User + @Field(() => Number, { nullable: true }) + userId: number | null + + @Field(() => String, { nullable: true }) + firstName: string | null + + @Field(() => String, { nullable: true }) + lastName: string | null @Field(() => Decimal) amount: Decimal From c02f575780166a8f2e6c29df4a83ffac59fcd36d Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 14 Jul 2022 12:59:21 +0200 Subject: [PATCH 13/30] Withdrew userid from contribution object. --- backend/src/graphql/model/Contribution.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/backend/src/graphql/model/Contribution.ts b/backend/src/graphql/model/Contribution.ts index 324b0ff07..a1537244d 100644 --- a/backend/src/graphql/model/Contribution.ts +++ b/backend/src/graphql/model/Contribution.ts @@ -7,7 +7,6 @@ import { User } from './User' export class Contribution { constructor(contribution: dbContribution, user: User) { this.id = contribution.id - this.userId = user ? user.id : null this.firstName = user ? user.firstName : null this.lastName = user ? user.lastName : null this.amount = contribution.amount @@ -19,9 +18,6 @@ export class Contribution { @Field(() => Number) id: number - @Field(() => Number, { nullable: true }) - userId: number | null - @Field(() => String, { nullable: true }) firstName: string | null From 8c6ec08e88aa4350134c2efd812a77ddfbeea2d6 Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 14 Jul 2022 16:42:55 +0200 Subject: [PATCH 14/30] Gives a list of allCreations and calls the User one time in the creation. --- .../graphql/resolver/ContributionResolver.ts | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 4424b40d0..8a23b3150 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -2,12 +2,13 @@ import { RIGHTS } from '@/auth/RIGHTS' import { Context, getUser } from '@/server/context' import { backendLogger as logger } from '@/server/logger' import { Contribution as dbContribution } from '@entity/Contribution' +import { User as dbUser } from '@entity/User' import { Arg, Args, Authorized, Ctx, Mutation, Query, Resolver } from 'type-graphql' -import { FindOperator, IsNull } from '@dbTools/typeorm' +import { FindOperator, IsNull, Not } from '@dbTools/typeorm' import ContributionArgs from '@arg/ContributionArgs' import Paginated from '@arg/Paginated' import { Order } from '@enum/Order' -import { Contribution } from '@model/Contribution' +import { Contribution, ContributionListResult } from '@model/Contribution' import { UnconfirmedContribution } from '@model/UnconfirmedContribution' import { User } from '@model/User' import { validateContribution, getUserCreation } from './util/creations' @@ -63,4 +64,37 @@ export class ContributionResolver { }) return contributions.map((contribution) => new Contribution(contribution, new User(user))) } + + @Authorized([RIGHTS.LIST_ALL_CONFIRMED_CONTRIBUTIONS]) + @Query(() => ContributionListResult) + async listAllConfirmedContributions( + @Args() + { currentPage = 1, pageSize = 5, order = Order.DESC }: Paginated, + ): Promise { + const dbContributions = await dbContribution.find({ + order: { + createdAt: order, + }, + skip: (currentPage - 1) * pageSize, + take: pageSize, + }) + const contributions: Contribution[] = [] + const userIds: number[] = [] + dbContributions.forEach(async (dbContribution) => { + userIds.push(dbContribution.userId) + }) + userIds.filter((elem, index, self) => { + return index === self.indexOf(elem) + }) + const users = new Map() + for (let i = 0; i < userIds.length; i++) { + const id = userIds[i] + const user = await dbUser.findOneOrFail({ id }) + users.set(id, user) + } + dbContributions.forEach((dbContribution) => { + contributions.push(new Contribution(dbContribution, users.get(dbContribution.userId))) + }) + return new ContributionListResult(contributions.length, contributions) + } } From fdea5f68ef8fd78176ce3ea5707c6cc270d2abbd Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 14 Jul 2022 16:43:20 +0200 Subject: [PATCH 15/30] Add confirmedBy and confirmedAt for the contribution query. --- backend/src/graphql/model/Contribution.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/backend/src/graphql/model/Contribution.ts b/backend/src/graphql/model/Contribution.ts index a1537244d..34bffd6d7 100644 --- a/backend/src/graphql/model/Contribution.ts +++ b/backend/src/graphql/model/Contribution.ts @@ -13,6 +13,8 @@ export class Contribution { this.memo = contribution.memo this.createdAt = contribution.createdAt this.deletedAt = contribution.deletedAt + this.confirmedAt = contribution.confirmedAt + this.confirmedBy = contribution.confirmedBy } @Field(() => Number) @@ -35,6 +37,12 @@ export class Contribution { @Field(() => Date, { nullable: true }) deletedAt: Date | null + + @Field(() => Date, { nullable: true }) + confirmedAt: Date | null + + @Field(() => Number, { nullable: true }) + confirmedBy: number | null } @ObjectType() From cbbe0ffad2cf8a528d5a3c5c5a336cfed7afe82b Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 14 Jul 2022 16:45:19 +0200 Subject: [PATCH 16/30] Change the method name from listAllConfirmedContributions to listAllContributions. --- backend/src/auth/RIGHTS.ts | 2 +- backend/src/auth/ROLES.ts | 2 +- backend/src/graphql/resolver/ContributionResolver.ts | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/src/auth/RIGHTS.ts b/backend/src/auth/RIGHTS.ts index 975c2006a..5258c9e3b 100644 --- a/backend/src/auth/RIGHTS.ts +++ b/backend/src/auth/RIGHTS.ts @@ -27,7 +27,7 @@ export enum RIGHTS { GDT_BALANCE = 'GDT_BALANCE', CREATE_CONTRIBUTION = 'CREATE_CONTRIBUTION', LIST_CONTRIBUTIONS = 'LIST_CONTRIBUTIONS', - LIST_ALL_CONFIRMED_CONTRIBUTIONS = 'LIST_ALL_CONFIRMED_CONTRIBUTIONS', + LIST_ALL_CONTRIBUTIONS = 'LIST_ALL_CONTRIBUTIONS', // Admin SEARCH_USERS = 'SEARCH_USERS', SET_USER_ROLE = 'SET_USER_ROLE', diff --git a/backend/src/auth/ROLES.ts b/backend/src/auth/ROLES.ts index e5628bb62..4a96d4813 100644 --- a/backend/src/auth/ROLES.ts +++ b/backend/src/auth/ROLES.ts @@ -25,7 +25,7 @@ export const ROLE_USER = new Role('user', [ RIGHTS.GDT_BALANCE, RIGHTS.CREATE_CONTRIBUTION, RIGHTS.LIST_CONTRIBUTIONS, - RIGHTS.LIST_ALL_CONFIRMED_CONTRIBUTIONS, + RIGHTS.LIST_ALL_CONTRIBUTIONS, ]) export const ROLE_ADMIN = new Role('admin', Object.values(RIGHTS)) // all rights diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 8a23b3150..c015496c1 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -65,9 +65,9 @@ export class ContributionResolver { return contributions.map((contribution) => new Contribution(contribution, new User(user))) } - @Authorized([RIGHTS.LIST_ALL_CONFIRMED_CONTRIBUTIONS]) + @Authorized([RIGHTS.LIST_ALL_CONTRIBUTIONS]) @Query(() => ContributionListResult) - async listAllConfirmedContributions( + async listAllContributions( @Args() { currentPage = 1, pageSize = 5, order = Order.DESC }: Paginated, ): Promise { From ab77a798f589c4907ae149f127e9e7c7c56219bb Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 14 Jul 2022 16:57:25 +0200 Subject: [PATCH 17/30] Add query seed for listAllContributions. --- backend/src/seeds/graphql/queries.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/backend/src/seeds/graphql/queries.ts b/backend/src/seeds/graphql/queries.ts index c27ecdd66..deae5f97b 100644 --- a/backend/src/seeds/graphql/queries.ts +++ b/backend/src/seeds/graphql/queries.ts @@ -191,6 +191,24 @@ export const listContributions = gql` } } ` + +export const listAllContributions = ` +query ($currentPage: Int = 1, $pageSize: Int = 5, $order: Order = DESC) { + listAllContributions(currentPage: $currentPage, pageSize: $pageSize, order: $order) { + linkCount + linkList { + id + firstName + lastName + amount + memo + createdAt + confirmedAt + confirmedBy + } + } +} +` // from admin interface export const listUnconfirmedContributions = gql` From ba90911aec704026ee6953e9db0f3731ef263116 Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 14 Jul 2022 16:57:57 +0200 Subject: [PATCH 18/30] Test that unauthenticated user can not query listAllContributions. --- .../resolver/ContributionResolver.test.ts | 56 ++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index 9b0f6a3bc..a4cb1d714 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -3,7 +3,7 @@ import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { createContribution } from '@/seeds/graphql/mutations' -import { listContributions, login } from '@/seeds/graphql/queries' +import { listAllContributions, listContributions, login } from '@/seeds/graphql/queries' import { cleanDB, resetToken, testEnvironment } from '@test/helpers' import { GraphQLError } from 'graphql' import { userFactory } from '@/seeds/factory/user' @@ -168,6 +168,11 @@ describe('ContributionResolver', () => { }) }) + afterAll(async () => { + await cleanDB() + await con.close() + }) + describe('filter confirmed is false', () => { it('returns creations', async () => { await expect( @@ -230,4 +235,53 @@ describe('ContributionResolver', () => { }) }) }) + + describe('listAllContribution', () => { + describe('unauthenticated', () => { + it('returns an error', async () => { + await expect( + query({ + query: listAllContributions, + variables: { + currentPage: 1, + pageSize: 25, + order: 'DESC', + filterConfirmed: false, + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('401 Unauthorized')], + }), + ) + }) + }) + + describe('authenticated', () => { + beforeAll(async () => { + await userFactory(testEnv, bibiBloxberg) + await userFactory(testEnv, peterLustig) + const bibisCreation = creations.find((creation) => creation.email === 'bibi@bloxberg.de') + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + await creationFactory(testEnv, bibisCreation!) + await query({ + query: login, + variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, + }) + await mutate({ + mutation: createContribution, + variables: { + amount: 100.0, + memo: 'Test env contribution', + creationDate: new Date().toString(), + }, + }) + }) + + afterAll(async () => { + await cleanDB() + await con.close() + }) + }) + }) }) From 246edadc1314e6092eb51daa7ffdf9eeff72e72f Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 14 Jul 2022 17:22:22 +0200 Subject: [PATCH 19/30] Test that authenticated user gets allContributions. --- .../resolver/ContributionResolver.test.ts | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index a4cb1d714..9aa247d4e 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -261,9 +261,9 @@ describe('ContributionResolver', () => { beforeAll(async () => { await userFactory(testEnv, bibiBloxberg) await userFactory(testEnv, peterLustig) - const bibisCreation = creations.find((creation) => creation.email === 'bibi@bloxberg.de') + creations.forEach(async (creation) => await creationFactory(testEnv, creation!)) // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - await creationFactory(testEnv, bibisCreation!) + // await creationFactory(testEnv, creations!) await query({ query: login, variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, @@ -282,6 +282,37 @@ describe('ContributionResolver', () => { await cleanDB() await con.close() }) + + it('returns allCreation', async () => { + await expect( + query({ + query: listAllContributions, + variables: { + currentPage: 1, + pageSize: 25, + order: 'DESC', + filterConfirmed: false, + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + data: { + listAllContributions: expect.arrayContaining([ + expect.objectContaining({ + id: expect.any(Number), + memo: 'Herzlich Willkommen bei Gradido!', + amount: '1000', + }), + expect.objectContaining({ + id: expect.any(Number), + memo: 'Test env contribution', + amount: '100', + }), + ]), + }, + }), + ) + }) }) }) }) From 3733bf511483f09fae6d37c2e5926c75ae247487 Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 14 Jul 2022 17:30:21 +0200 Subject: [PATCH 20/30] Change con.close to resetToken method. --- backend/src/graphql/resolver/ContributionResolver.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index 9aa247d4e..124adff18 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -170,7 +170,7 @@ describe('ContributionResolver', () => { afterAll(async () => { await cleanDB() - await con.close() + resetToken() }) describe('filter confirmed is false', () => { @@ -280,7 +280,7 @@ describe('ContributionResolver', () => { afterAll(async () => { await cleanDB() - await con.close() + resetToken() }) it('returns allCreation', async () => { From 34de4bb9014497a0db5a2d0d5cdcf662ff954ee2 Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 14 Jul 2022 17:42:49 +0200 Subject: [PATCH 21/30] Merge conflict on contribution resolver test file --- .../resolver/ContributionResolver.test.ts | 142 ++++++++++-------- 1 file changed, 78 insertions(+), 64 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index fd9636439..4f57cc0a1 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -2,17 +2,12 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' -<<<<<<< HEAD -import { createContribution } from '@/seeds/graphql/mutations' -import { listAllContributions, listContributions, login } from '@/seeds/graphql/queries' -======= import { adminUpdateContribution, createContribution, updateContribution, } from '@/seeds/graphql/mutations' -import { listContributions, login } from '@/seeds/graphql/queries' ->>>>>>> master +import { listAllContributions, listContributions, login } from '@/seeds/graphql/queries' import { cleanDB, resetToken, testEnvironment } from '@test/helpers' import { GraphQLError } from 'graphql' import { userFactory } from '@/seeds/factory/user' @@ -246,19 +241,6 @@ describe('ContributionResolver', () => { }) }) -<<<<<<< HEAD - describe('listAllContribution', () => { - describe('unauthenticated', () => { - it('returns an error', async () => { - await expect( - query({ - query: listAllContributions, - variables: { - currentPage: 1, - pageSize: 25, - order: 'DESC', - filterConfirmed: false, -======= describe('updateContribution', () => { describe('unauthenticated', () => { it('returns an error', async () => { @@ -270,7 +252,6 @@ describe('ContributionResolver', () => { amount: 100.0, memo: 'Test Contribution', creationDate: 'not-valid', ->>>>>>> master }, }), ).resolves.toEqual( @@ -283,25 +264,13 @@ describe('ContributionResolver', () => { describe('authenticated', () => { beforeAll(async () => { -<<<<<<< HEAD - await userFactory(testEnv, bibiBloxberg) - await userFactory(testEnv, peterLustig) - creations.forEach(async (creation) => await creationFactory(testEnv, creation!)) - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - // await creationFactory(testEnv, creations!) -======= await userFactory(testEnv, peterLustig) await userFactory(testEnv, bibiBloxberg) ->>>>>>> master await query({ query: login, variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, }) -<<<<<<< HEAD - await mutate({ -======= result = await mutate({ ->>>>>>> master mutation: createContribution, variables: { amount: 100.0, @@ -316,37 +285,6 @@ describe('ContributionResolver', () => { resetToken() }) -<<<<<<< HEAD - it('returns allCreation', async () => { - await expect( - query({ - query: listAllContributions, - variables: { - currentPage: 1, - pageSize: 25, - order: 'DESC', - filterConfirmed: false, - }, - }), - ).resolves.toEqual( - expect.objectContaining({ - data: { - listAllContributions: expect.arrayContaining([ - expect.objectContaining({ - id: expect.any(Number), - memo: 'Herzlich Willkommen bei Gradido!', - amount: '1000', - }), - expect.objectContaining({ - id: expect.any(Number), - memo: 'Test env contribution', - amount: '100', - }), - ]), - }, - }), - ) -======= describe('wrong contribution id', () => { it('throws an error', async () => { await expect( @@ -497,8 +435,84 @@ describe('ContributionResolver', () => { }), ) }) ->>>>>>> master + }) + + describe('listAllContribution', () => { + describe('unauthenticated', () => { + it('returns an error', async () => { + await expect( + query({ + query: listAllContributions, + variables: { + currentPage: 1, + pageSize: 25, + order: 'DESC', + filterConfirmed: false, + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('401 Unauthorized')], + }), + ) + }) + }) }) }) }) + + describe('authenticated', () => { + beforeAll(async () => { + await userFactory(testEnv, bibiBloxberg) + await userFactory(testEnv, peterLustig) + creations.forEach(async (creation) => await creationFactory(testEnv, creation!)) + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + // await creationFactory(testEnv, creations!) + await userFactory(testEnv, peterLustig) + await userFactory(testEnv, bibiBloxberg) + await query({ + query: login, + variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, + }) + result = await mutate({ + mutation: createContribution, + variables: { + amount: 100.0, + memo: 'Test env contribution', + creationDate: new Date().toString(), + }, + }) + }) + + it('returns allCreation', async () => { + await expect( + query({ + query: listAllContributions, + variables: { + currentPage: 1, + pageSize: 25, + order: 'DESC', + filterConfirmed: false, + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + data: { + listAllContributions: expect.arrayContaining([ + expect.objectContaining({ + id: expect.any(Number), + memo: 'Herzlich Willkommen bei Gradido!', + amount: '1000', + }), + expect.objectContaining({ + id: expect.any(Number), + memo: 'Test env contribution', + amount: '100', + }), + ]), + }, + }), + ) + }) + }) }) From c242f977337a5e048dcd1cfecf818f3d92d0456d Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 14 Jul 2022 17:52:31 +0200 Subject: [PATCH 22/30] Change the test for listAllContributions to have every seed user and create all creations, add Test suite that checks if every seeded data arrives as well. --- .../resolver/ContributionResolver.test.ts | 141 +++++++++--------- 1 file changed, 72 insertions(+), 69 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index 4f57cc0a1..b294fb40d 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -14,6 +14,8 @@ import { userFactory } from '@/seeds/factory/user' import { creationFactory } from '@/seeds/factory/creation' import { creations } from '@/seeds/creation/index' import { peterLustig } from '@/seeds/users/peter-lustig' +import { bobBaumeister } from '@/seeds/users/bob-baumeister' +import { raeuberHotzenplotz } from '@/seeds/users/raeuber-hotzenplotz' let mutate: any, query: any, con: any let testEnv: any @@ -436,83 +438,84 @@ describe('ContributionResolver', () => { ) }) }) - - describe('listAllContribution', () => { - describe('unauthenticated', () => { - it('returns an error', async () => { - await expect( - query({ - query: listAllContributions, - variables: { - currentPage: 1, - pageSize: 25, - order: 'DESC', - filterConfirmed: false, - }, - }), - ).resolves.toEqual( - expect.objectContaining({ - errors: [new GraphQLError('401 Unauthorized')], - }), - ) - }) - }) - }) }) }) - describe('authenticated', () => { - beforeAll(async () => { - await userFactory(testEnv, bibiBloxberg) - await userFactory(testEnv, peterLustig) - creations.forEach(async (creation) => await creationFactory(testEnv, creation!)) - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - // await creationFactory(testEnv, creations!) - await userFactory(testEnv, peterLustig) - await userFactory(testEnv, bibiBloxberg) - await query({ - query: login, - variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, - }) - result = await mutate({ - mutation: createContribution, - variables: { - amount: 100.0, - memo: 'Test env contribution', - creationDate: new Date().toString(), - }, + describe('listAllContribution', () => { + describe('unauthenticated', () => { + it('returns an error', async () => { + await expect( + query({ + query: listAllContributions, + variables: { + currentPage: 1, + pageSize: 25, + order: 'DESC', + filterConfirmed: false, + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('401 Unauthorized')], + }), + ) }) }) - it('returns allCreation', async () => { - await expect( - query({ - query: listAllContributions, + describe('authenticated', () => { + beforeAll(async () => { + await userFactory(testEnv, bibiBloxberg) + await userFactory(testEnv, peterLustig) + await userFactory(testEnv, raeuberHotzenplotz) + await userFactory(testEnv, bobBaumeister) + creations.forEach(async (creation) => await creationFactory(testEnv, creation!)) + await query({ + query: login, + variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, + }) + result = await mutate({ + mutation: createContribution, variables: { - currentPage: 1, - pageSize: 25, - order: 'DESC', - filterConfirmed: false, + amount: 100.0, + memo: 'Test env contribution', + creationDate: new Date().toString(), }, - }), - ).resolves.toEqual( - expect.objectContaining({ - data: { - listAllContributions: expect.arrayContaining([ - expect.objectContaining({ - id: expect.any(Number), - memo: 'Herzlich Willkommen bei Gradido!', - amount: '1000', - }), - expect.objectContaining({ - id: expect.any(Number), - memo: 'Test env contribution', - amount: '100', - }), - ]), - }, - }), - ) + }) + }) + + it('returns allCreation', async () => { + await expect( + query({ + query: listAllContributions, + variables: { + currentPage: 1, + pageSize: 25, + order: 'DESC', + filterConfirmed: false, + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + data: { + listAllContributions: { + linkCount: 25, + linkList: expect.arrayContaining([ + expect.objectContaining({ + id: expect.any(Number), + memo: 'Herzlich Willkommen bei Gradido!', + amount: '1000', + }), + expect.objectContaining({ + id: expect.any(Number), + memo: 'Test env contribution', + amount: '100', + }), + ]), + }, + }, + }), + ) + }) }) }) }) From b86ddbf8b0be90856de0a3a3e2b990745e9a5804 Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 14 Jul 2022 18:08:51 +0200 Subject: [PATCH 23/30] Fix linting. --- backend/src/graphql/resolver/ContributionResolver.test.ts | 1 + backend/src/graphql/resolver/ContributionResolver.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index b294fb40d..247d1be0e 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -468,6 +468,7 @@ describe('ContributionResolver', () => { await userFactory(testEnv, peterLustig) await userFactory(testEnv, raeuberHotzenplotz) await userFactory(testEnv, bobBaumeister) + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion creations.forEach(async (creation) => await creationFactory(testEnv, creation!)) await query({ query: login, diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 3faffb95d..cdaa5faa3 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -4,7 +4,7 @@ import { backendLogger as logger } from '@/server/logger' import { Contribution as dbContribution } from '@entity/Contribution' import { User as dbUser } from '@entity/User' import { Arg, Args, Authorized, Ctx, Int, Mutation, Query, Resolver } from 'type-graphql' -import { FindOperator, IsNull, Not } from '@dbTools/typeorm' +import { FindOperator, IsNull } from '@dbTools/typeorm' import ContributionArgs from '@arg/ContributionArgs' import Paginated from '@arg/Paginated' import { Order } from '@enum/Order' From 175bc514be7fea2f1737e4e6861c1fa7c5680e5b Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Fri, 15 Jul 2022 13:36:31 +0200 Subject: [PATCH 24/30] feat: Do not log IntrospectionQuery from Query Browser --- backend/src/server/plugins.ts | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/backend/src/server/plugins.ts b/backend/src/server/plugins.ts index 1972bc1c8..24df45baa 100644 --- a/backend/src/server/plugins.ts +++ b/backend/src/server/plugins.ts @@ -31,20 +31,24 @@ const filterVariables = (variables: any) => { const logPlugin = { requestDidStart(requestContext: any) { const { logger } = requestContext - const { query, mutation, variables } = requestContext.request - logger.info(`Request: + const { query, mutation, variables, operationName } = requestContext.request + if (operationName !== 'IntrospectionQuery') { + logger.info(`Request: ${mutation || query}variables: ${JSON.stringify(filterVariables(variables), null, 2)}`) + } return { willSendResponse(requestContext: any) { - if (requestContext.context.user) logger.info(`User ID: ${requestContext.context.user.id}`) - if (requestContext.response.data) { - logger.info('Response Success!') - logger.trace(`Response-Data: + if (operationName !== 'IntrospectionQuery') { + if (requestContext.context.user) logger.info(`User ID: ${requestContext.context.user.id}`) + if (requestContext.response.data) { + logger.info('Response Success!') + logger.trace(`Response-Data: ${JSON.stringify(requestContext.response.data, null, 2)}`) - } - if (requestContext.response.errors) - logger.error(`Response-Errors: + } + if (requestContext.response.errors) + logger.error(`Response-Errors: ${JSON.stringify(requestContext.response.errors, null, 2)}`) + } return requestContext }, } From d0662270431f112710c23748c72c6577c99eef3e Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 15 Jul 2022 14:13:33 +0200 Subject: [PATCH 25/30] Change the Contribution entity to join on user. --- .../0039-contributions_table/Contribution.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/database/entity/0039-contributions_table/Contribution.ts b/database/entity/0039-contributions_table/Contribution.ts index 6c7358f90..ee6e0f73f 100644 --- a/database/entity/0039-contributions_table/Contribution.ts +++ b/database/entity/0039-contributions_table/Contribution.ts @@ -1,6 +1,15 @@ import Decimal from 'decimal.js-light' -import { BaseEntity, Column, Entity, PrimaryGeneratedColumn, DeleteDateColumn } from 'typeorm' +import { + BaseEntity, + Column, + Entity, + PrimaryGeneratedColumn, + DeleteDateColumn, + OneToOne, + JoinColumn, +} from 'typeorm' import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer' +import { User } from '../User' @Entity('contributions') export class Contribution extends BaseEntity { @@ -10,6 +19,10 @@ export class Contribution extends BaseEntity { @Column({ unsigned: true, nullable: false, name: 'user_id' }) userId: number + @OneToOne(() => User) + @JoinColumn({ name: 'user_id' }) + user: User + @Column({ type: 'datetime', default: () => 'CURRENT_TIMESTAMP', name: 'created_at' }) createdAt: Date From 5f5c19e6ba364ee036284fb47a197a6da3683832 Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 15 Jul 2022 14:14:15 +0200 Subject: [PATCH 26/30] Change find to much more efficient code. --- .../graphql/resolver/ContributionResolver.ts | 28 ++++++------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 812e81527..d71ecac59 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -2,7 +2,6 @@ import { RIGHTS } from '@/auth/RIGHTS' import { Context, getUser } from '@/server/context' import { backendLogger as logger } from '@/server/logger' import { Contribution as dbContribution } from '@entity/Contribution' -import { User as dbUser } from '@entity/User' import { Arg, Args, Authorized, Ctx, Int, Mutation, Query, Resolver } from 'type-graphql' import { FindOperator, IsNull } from '@dbTools/typeorm' import ContributionArgs from '@arg/ContributionArgs' @@ -72,31 +71,20 @@ export class ContributionResolver { @Args() { currentPage = 1, pageSize = 5, order = Order.DESC }: Paginated, ): Promise { - const dbContributions = await dbContribution.find({ + const [dbContributions, count] = await dbContribution.findAndCount({ + relations: ['user'], order: { createdAt: order, }, skip: (currentPage - 1) * pageSize, take: pageSize, }) - const contributions: Contribution[] = [] - const userIds: number[] = [] - dbContributions.forEach(async (dbContribution) => { - userIds.push(dbContribution.userId) - }) - userIds.filter((elem, index, self) => { - return index === self.indexOf(elem) - }) - const users = new Map() - for (let i = 0; i < userIds.length; i++) { - const id = userIds[i] - const user = await dbUser.findOneOrFail({ id }) - users.set(id, user) - } - dbContributions.forEach((dbContribution) => { - contributions.push(new Contribution(dbContribution, users.get(dbContribution.userId))) - }) - return new ContributionListResult(contributions.length, contributions) + return new ContributionListResult( + count, + dbContributions.map( + (contribution) => new Contribution(contribution, new User(contribution.user)), + ), + ) } @Authorized([RIGHTS.UPDATE_CONTRIBUTION]) From 382211f3ca12fa9585ef853751d886672997876e Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 15 Jul 2022 14:14:55 +0200 Subject: [PATCH 27/30] Adapt test so that we check findAllContributions. --- .../src/graphql/resolver/ContributionResolver.test.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index 247d1be0e..fd5ff68a2 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -466,15 +466,14 @@ describe('ContributionResolver', () => { beforeAll(async () => { await userFactory(testEnv, bibiBloxberg) await userFactory(testEnv, peterLustig) - await userFactory(testEnv, raeuberHotzenplotz) - await userFactory(testEnv, bobBaumeister) + const bibisCreation = creations.find((creation) => creation.email === 'bibi@bloxberg.de') // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - creations.forEach(async (creation) => await creationFactory(testEnv, creation!)) + await creationFactory(testEnv, bibisCreation!) await query({ query: login, variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, }) - result = await mutate({ + await mutate({ mutation: createContribution, variables: { amount: 100.0, @@ -499,7 +498,7 @@ describe('ContributionResolver', () => { expect.objectContaining({ data: { listAllContributions: { - linkCount: 25, + linkCount: 2, linkList: expect.arrayContaining([ expect.objectContaining({ id: expect.any(Number), From cada4eca19cfa95b3ba7603838f2f163effb05ad Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 15 Jul 2022 14:32:20 +0200 Subject: [PATCH 28/30] Change OneToOne relation to OneToMany / ManyToOne. --- .../0039-contributions_table/Contribution.ts | 3 ++- .../0040-add_contribution_link_id_to_user/User.ts | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/database/entity/0039-contributions_table/Contribution.ts b/database/entity/0039-contributions_table/Contribution.ts index ee6e0f73f..5df527530 100644 --- a/database/entity/0039-contributions_table/Contribution.ts +++ b/database/entity/0039-contributions_table/Contribution.ts @@ -7,6 +7,7 @@ import { DeleteDateColumn, OneToOne, JoinColumn, + ManyToOne, } from 'typeorm' import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer' import { User } from '../User' @@ -19,7 +20,7 @@ export class Contribution extends BaseEntity { @Column({ unsigned: true, nullable: false, name: 'user_id' }) userId: number - @OneToOne(() => User) + @ManyToOne(() => User, (user) => user.contributions) @JoinColumn({ name: 'user_id' }) user: User diff --git a/database/entity/0040-add_contribution_link_id_to_user/User.ts b/database/entity/0040-add_contribution_link_id_to_user/User.ts index 9bf76e5f5..56047345a 100644 --- a/database/entity/0040-add_contribution_link_id_to_user/User.ts +++ b/database/entity/0040-add_contribution_link_id_to_user/User.ts @@ -1,4 +1,13 @@ -import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, DeleteDateColumn } from 'typeorm' +import { + BaseEntity, + Entity, + PrimaryGeneratedColumn, + Column, + DeleteDateColumn, + OneToMany, + JoinColumn, +} from 'typeorm' +import { Contribution } from '../Contribution' @Entity('users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) export class User extends BaseEntity { @@ -76,4 +85,8 @@ export class User extends BaseEntity { default: null, }) passphrase: string + + @OneToMany(() => Contribution, (contribution) => contribution.user) + @JoinColumn({ name: 'user_id' }) + contributions?: Contribution[] } From 843993e34085397eb86b8e67477bf58e94debd6a Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 15 Jul 2022 14:34:47 +0200 Subject: [PATCH 29/30] Fix linting. --- backend/src/graphql/resolver/ContributionResolver.test.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index fd5ff68a2..e6478ffc2 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -14,8 +14,6 @@ import { userFactory } from '@/seeds/factory/user' import { creationFactory } from '@/seeds/factory/creation' import { creations } from '@/seeds/creation/index' import { peterLustig } from '@/seeds/users/peter-lustig' -import { bobBaumeister } from '@/seeds/users/bob-baumeister' -import { raeuberHotzenplotz } from '@/seeds/users/raeuber-hotzenplotz' let mutate: any, query: any, con: any let testEnv: any From 5892f7b42947db8270fe4d26a4faed587abe68c3 Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 15 Jul 2022 14:48:51 +0200 Subject: [PATCH 30/30] Remove OneToOne import from contribution entity. --- database/entity/0039-contributions_table/Contribution.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/database/entity/0039-contributions_table/Contribution.ts b/database/entity/0039-contributions_table/Contribution.ts index 5df527530..b5e6ac0e0 100644 --- a/database/entity/0039-contributions_table/Contribution.ts +++ b/database/entity/0039-contributions_table/Contribution.ts @@ -5,7 +5,6 @@ import { Entity, PrimaryGeneratedColumn, DeleteDateColumn, - OneToOne, JoinColumn, ManyToOne, } from 'typeorm'