From 8c00fcd6ccb8069a7df73053164226b91ad868df Mon Sep 17 00:00:00 2001 From: elweyn Date: Mon, 6 Feb 2023 14:34:40 +0100 Subject: [PATCH 01/19] Merge new unit tests for ContributionResolver. --- admin/package.json | 5 +- backend/package.json | 3 + .../resolver/ContributionResolver.test.ts | 175 +++++++++--------- .../graphql/resolver/ContributionResolver.ts | 59 +++--- backend/src/seeds/graphql/queries.ts | 53 ++++-- database/package.json | 3 + frontend/package.json | 5 +- 7 files changed, 167 insertions(+), 136 deletions(-) diff --git a/admin/package.json b/admin/package.json index 8270c4da6..30e93239b 100644 --- a/admin/package.json +++ b/admin/package.json @@ -86,5 +86,8 @@ "> 1%", "last 2 versions", "not ie <= 10" - ] + ], + "nodemonConfig": { + "ignore": ["**/*.spec.js"] + } } diff --git a/backend/package.json b/backend/package.json index bfcd61d5b..9a36c2ff8 100644 --- a/backend/package.json +++ b/backend/package.json @@ -72,5 +72,8 @@ "ts-node": "^10.0.0", "tsconfig-paths": "^3.14.0", "typescript": "^4.3.4" + }, + "nodemonConfig": { + "ignore": ["**/*.test.ts"] } } diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index 7c239e699..c64837285 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -23,7 +23,7 @@ import { import { listAllContributions, listContributions, - listUnconfirmedContributions, + adminListAllContributions, } from '@/seeds/graphql/queries' import { // sendAccountActivationEmail, @@ -1963,11 +1963,11 @@ describe('ContributionResolver', () => { }) }) - describe('listUnconfirmedContributions', () => { + describe('adminListAllContributions', () => { it('returns an error', async () => { await expect( query({ - query: listUnconfirmedContributions, + query: adminListAllContributions, }), ).resolves.toEqual( expect.objectContaining({ @@ -2071,11 +2071,11 @@ describe('ContributionResolver', () => { }) }) - describe('listUnconfirmedContributions', () => { + describe('adminListAllContributions', () => { it('returns an error', async () => { await expect( query({ - query: listUnconfirmedContributions, + query: adminListAllContributions, }), ).resolves.toEqual( expect.objectContaining({ @@ -2665,94 +2665,97 @@ describe('ContributionResolver', () => { }) }) - describe('listUnconfirmedContributions', () => { + describe('adminListAllContributions', () => { it('returns four pending creations', async () => { await expect( query({ - query: listUnconfirmedContributions, + query: adminListAllContributions, }), ).resolves.toEqual( expect.objectContaining({ data: { - listUnconfirmedContributions: expect.arrayContaining([ - expect.objectContaining({ - id: expect.any(Number), - firstName: 'Peter', - lastName: 'Lustig', - email: 'peter@lustig.de', - date: expect.any(String), - memo: 'Das war leider zu Viel!', - amount: '200', - moderator: admin.id, - creation: ['1000', '800', '500'], - }), - expect.objectContaining({ - id: expect.any(Number), - firstName: 'Peter', - lastName: 'Lustig', - email: 'peter@lustig.de', - date: expect.any(String), - memo: 'Grundeinkommen', - amount: '500', - moderator: admin.id, - creation: ['1000', '800', '500'], - }), - expect.not.objectContaining({ - id: expect.any(Number), - firstName: 'Bibi', - lastName: 'Bloxberg', - email: 'bibi@bloxberg.de', - date: expect.any(String), - memo: 'Test contribution to delete', - amount: '100', - moderator: null, - creation: ['1000', '1000', '90'], - }), - expect.objectContaining({ - id: expect.any(Number), - firstName: 'Bibi', - lastName: 'Bloxberg', - email: 'bibi@bloxberg.de', - date: expect.any(String), - memo: 'Test PENDING contribution update', - amount: '10', - moderator: null, - creation: ['1000', '1000', '90'], - }), - expect.objectContaining({ - id: expect.any(Number), - firstName: 'Bibi', - lastName: 'Bloxberg', - email: 'bibi@bloxberg.de', - date: expect.any(String), - memo: 'Test IN_PROGRESS contribution', - amount: '100', - moderator: null, - creation: ['1000', '1000', '90'], - }), - expect.objectContaining({ - id: expect.any(Number), - firstName: 'Bibi', - lastName: 'Bloxberg', - email: 'bibi@bloxberg.de', - date: expect.any(String), - memo: 'Grundeinkommen', - amount: '500', - moderator: admin.id, - creation: ['1000', '1000', '90'], - }), - expect.objectContaining({ - id: expect.any(Number), - firstName: 'Bibi', - lastName: 'Bloxberg', - email: 'bibi@bloxberg.de', - date: expect.any(String), - memo: 'Aktives Grundeinkommen', - amount: '200', - moderator: admin.id, - creation: ['1000', '1000', '90'], - }), - ]), + adminListAllContributions: { + contributionCount: 4, + contributionList: expect.arrayContaining([ + expect.objectContaining({ + id: expect.any(Number), + firstName: 'Peter', + lastName: 'Lustig', + email: 'peter@lustig.de', + date: expect.any(String), + memo: 'Das war leider zu Viel!', + amount: '200', + moderator: admin.id, + creation: ['1000', '800', '500'], + }), + expect.objectContaining({ + id: expect.any(Number), + firstName: 'Peter', + lastName: 'Lustig', + email: 'peter@lustig.de', + date: expect.any(String), + memo: 'Grundeinkommen', + amount: '500', + moderator: admin.id, + creation: ['1000', '800', '500'], + }), + expect.not.objectContaining({ + id: expect.any(Number), + firstName: 'Bibi', + lastName: 'Bloxberg', + email: 'bibi@bloxberg.de', + date: expect.any(String), + memo: 'Test contribution to delete', + amount: '100', + moderator: null, + creation: ['1000', '1000', '90'], + }), + expect.objectContaining({ + id: expect.any(Number), + firstName: 'Bibi', + lastName: 'Bloxberg', + email: 'bibi@bloxberg.de', + date: expect.any(String), + memo: 'Test PENDING contribution update', + amount: '10', + moderator: null, + creation: ['1000', '1000', '90'], + }), + expect.objectContaining({ + id: expect.any(Number), + firstName: 'Bibi', + lastName: 'Bloxberg', + email: 'bibi@bloxberg.de', + date: expect.any(String), + memo: 'Test IN_PROGRESS contribution', + amount: '100', + moderator: null, + creation: ['1000', '1000', '90'], + }), + expect.objectContaining({ + id: expect.any(Number), + firstName: 'Bibi', + lastName: 'Bloxberg', + email: 'bibi@bloxberg.de', + date: expect.any(String), + memo: 'Grundeinkommen', + amount: '500', + moderator: admin.id, + creation: ['1000', '1000', '90'], + }), + expect.objectContaining({ + id: expect.any(Number), + firstName: 'Bibi', + lastName: 'Bloxberg', + email: 'bibi@bloxberg.de', + date: expect.any(String), + memo: 'Aktives Grundeinkommen', + amount: '200', + moderator: admin.id, + creation: ['1000', '1000', '90'], + }), + ]), + }, }, }), ) diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index c7946d2c8..6016a2c23 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -477,40 +477,39 @@ export class ContributionResolver { } @Authorized([RIGHTS.LIST_UNCONFIRMED_CONTRIBUTIONS]) - @Query(() => [UnconfirmedContribution]) - async listUnconfirmedContributions(@Ctx() context: Context): Promise { - const clientTimezoneOffset = getClientTimezoneOffset(context) - const contributions = await getConnection() + @Query(() => ContributionListResult) // [UnconfirmedContribution] + async adminListAllContributions( + @Args() + { currentPage = 1, pageSize = 3, order = Order.DESC }: Paginated, + @Arg('statusFilter', () => [ContributionStatus], { nullable: true }) + statusFilter?: ContributionStatus[], + ): Promise { + const where: { + contributionStatus?: FindOperator | null + } = {} + + if (statusFilter && statusFilter.length) { + where.contributionStatus = In(statusFilter) + } + + const [dbContributions, count] = await getConnection() .createQueryBuilder() .select('c') .from(DbContribution, 'c') - .leftJoinAndSelect('c.messages', 'm') - .where({ confirmedAt: IsNull() }) - .andWhere({ deniedAt: IsNull() }) - .getMany() + .innerJoinAndSelect('c.user', 'u') + .where(where) + .withDeleted() + .orderBy('c.createdAt', order) + .limit(pageSize) + .offset((currentPage - 1) * pageSize) + .getManyAndCount() - if (contributions.length === 0) { - return [] - } - - const userIds = contributions.map((p) => p.userId) - const userCreations = await getUserCreations(userIds, clientTimezoneOffset) - const users = await DbUser.find({ - where: { id: In(userIds) }, - withDeleted: true, - relations: ['emailContact'], - }) - - return contributions.map((contribution) => { - const user = users.find((u) => u.id === contribution.userId) - const creation = userCreations.find((c) => c.id === contribution.userId) - - return new UnconfirmedContribution( - contribution, - user, - creation ? creation.creations : FULL_CREATION_AVAILABLE, - ) - }) + console.log('dbContributions', dbContributions) + console.log('count', count) + return new ContributionListResult( + count, + dbContributions.map((contribution) => new Contribution(contribution, contribution.user)), + ) } @Authorized([RIGHTS.ADMIN_DELETE_CONTRIBUTION]) diff --git a/backend/src/seeds/graphql/queries.ts b/backend/src/seeds/graphql/queries.ts index 385a69479..423575a16 100644 --- a/backend/src/seeds/graphql/queries.ts +++ b/backend/src/seeds/graphql/queries.ts @@ -177,6 +177,40 @@ query ($currentPage: Int = 1, $pageSize: Int = 5, $order: Order = DESC, $statusF contributionCount contributionList { id + firstName + lastName + amount + memo + createdAt + confirmedAt + confirmedBy + contributionDate + state + messagesCount + deniedAt + deniedBy + } + } +} +` +// from admin interface + +export const adminListAllContributions = gql` + query ( + $currentPage: Int = 1 + $pageSize: Int = 3 + $order: Order = DESC + $statusFilter: [ContributionStatus!] + ) { + adminListAllContributions( + currentPage: $currentPage + pageSize: $pageSize + order: $order + statusFilter: $statusFilter + ) { + contributionCount + contributionList { + id firstName lastName amount @@ -189,24 +223,7 @@ query ($currentPage: Int = 1, $pageSize: Int = 5, $order: Order = DESC, $statusF messagesCount deniedAt deniedBy - } - } -} -` -// from admin interface - -export const listUnconfirmedContributions = gql` - query { - listUnconfirmedContributions { - id - firstName - lastName - email - amount - memo - date - moderator - creation + } } } ` diff --git a/database/package.json b/database/package.json index f4e1c7e84..dc805da93 100644 --- a/database/package.json +++ b/database/package.json @@ -47,5 +47,8 @@ "ts-mysql-migrate": "^1.0.2", "typeorm": "^0.2.38", "uuid": "^8.3.2" + }, + "nodemonConfig": { + "ignore": ["**/*.test.ts"] } } diff --git a/frontend/package.json b/frontend/package.json index 29c440988..73651327f 100755 --- a/frontend/package.json +++ b/frontend/package.json @@ -104,5 +104,8 @@ ], "author": "Gradido-Akademie - https://www.gradido.net/", "license": "Apache-2.0", - "description": "Gradido, the Natural Economy of Life, is a way to worldwide prosperity and peace in harmony with nature. - Gradido, die Natürliche Ökonomie des lebens, ist ein Weg zu weltweitem Wohlstand und Frieden in Harmonie mit der Natur." + "description": "Gradido, the Natural Economy of Life, is a way to worldwide prosperity and peace in harmony with nature. - Gradido, die Natürliche Ökonomie des lebens, ist ein Weg zu weltweitem Wohlstand und Frieden in Harmonie mit der Natur.", + "nodemonConfig": { + "ignore": ["**/*.spec.js"] + } } From ad16aff1eaedc6ea53fef3864fee5a1afa9667a9 Mon Sep 17 00:00:00 2001 From: elweyn Date: Mon, 6 Feb 2023 15:06:58 +0100 Subject: [PATCH 02/19] Change listUnconfirmedContributions to adminListAllContributions. --- .../resolver/ContributionResolver.test.ts | 271 +++++++++++++----- .../graphql/resolver/ContributionResolver.ts | 5 +- backend/src/seeds/graphql/queries.ts | 2 +- 3 files changed, 204 insertions(+), 74 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index c64837285..5ab4e531d 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -2675,84 +2675,217 @@ describe('ContributionResolver', () => { expect.objectContaining({ data: { adminListAllContributions: { - contributionCount: 4, + contributionCount: 14, contributionList: expect.arrayContaining([ expect.objectContaining({ + amount: '500', + confirmedAt: null, + confirmedBy: null, + contributionDate: expect.any(String), + createdAt: expect.any(String), + deniedAt: null, + deniedBy: null, + firstName: 'Bibi', id: expect.any(Number), - firstName: 'Peter', - lastName: 'Lustig', - email: 'peter@lustig.de', - date: expect.any(String), - memo: 'Das war leider zu Viel!', + lastName: 'Bloxberg', + memo: 'Grundeinkommen', + messagesCount: 0, + state: 'PENDING', + }), + expect.objectContaining({ amount: '200', - moderator: admin.id, - creation: ['1000', '800', '500'], - }), - expect.objectContaining({ - id: expect.any(Number), - firstName: 'Peter', - lastName: 'Lustig', - email: 'peter@lustig.de', - date: expect.any(String), - memo: 'Grundeinkommen', - amount: '500', - moderator: admin.id, - creation: ['1000', '800', '500'], - }), - expect.not.objectContaining({ - id: expect.any(Number), + confirmedAt: null, + confirmedBy: null, + contributionDate: expect.any(String), + createdAt: expect.any(String), + deniedAt: null, + deniedBy: null, firstName: 'Bibi', - lastName: 'Bloxberg', - email: 'bibi@bloxberg.de', - date: expect.any(String), - memo: 'Test contribution to delete', - amount: '100', - moderator: null, - creation: ['1000', '1000', '90'], - }), - expect.objectContaining({ id: expect.any(Number), - firstName: 'Bibi', lastName: 'Bloxberg', - email: 'bibi@bloxberg.de', - date: expect.any(String), - memo: 'Test PENDING contribution update', - amount: '10', - moderator: null, - creation: ['1000', '1000', '90'], - }), - expect.objectContaining({ - id: expect.any(Number), - firstName: 'Bibi', - lastName: 'Bloxberg', - email: 'bibi@bloxberg.de', - date: expect.any(String), - memo: 'Test IN_PROGRESS contribution', - amount: '100', - moderator: null, - creation: ['1000', '1000', '90'], - }), - expect.objectContaining({ - id: expect.any(Number), - firstName: 'Bibi', - lastName: 'Bloxberg', - email: 'bibi@bloxberg.de', - date: expect.any(String), - memo: 'Grundeinkommen', - amount: '500', - moderator: admin.id, - creation: ['1000', '1000', '90'], - }), - expect.objectContaining({ - id: expect.any(Number), - firstName: 'Bibi', - lastName: 'Bloxberg', - email: 'bibi@bloxberg.de', - date: expect.any(String), memo: 'Aktives Grundeinkommen', + messagesCount: 0, + state: 'PENDING', + }), + expect.objectContaining({ + amount: '500', + confirmedAt: null, + confirmedBy: null, + contributionDate: expect.any(String), + createdAt: expect.any(String), + deniedAt: null, + deniedBy: null, + firstName: 'Peter', + id: expect.any(Number), + lastName: 'Lustig', + memo: 'Grundeinkommen', + messagesCount: 0, + state: 'PENDING', + }), + expect.objectContaining({ amount: '200', - moderator: admin.id, - creation: ['1000', '1000', '90'], + confirmedAt: null, + confirmedBy: null, + contributionDate: expect.any(String), + createdAt: expect.any(String), + deniedAt: null, + deniedBy: null, + firstName: 'Peter', + id: expect.any(Number), + lastName: 'Lustig', + memo: 'Das war leider zu Viel!', + messagesCount: 0, + state: 'PENDING', + }), + expect.objectContaining({ + amount: '166', + confirmedAt: null, + confirmedBy: null, + contributionDate: expect.any(String), + createdAt: expect.any(String), + deniedAt: null, + deniedBy: null, + firstName: 'Peter', + id: expect.any(Number), + lastName: 'Lustig', + memo: 'Whatever contribution', + messagesCount: 0, + state: 'DELETED', + }), + expect.objectContaining({ + amount: '166', + confirmedAt: null, + confirmedBy: null, + contributionDate: expect.any(String), + createdAt: expect.any(String), + deniedAt: expect.any(String), + deniedBy: expect.any(Number), + firstName: 'Räuber', + id: expect.any(Number), + lastName: 'Hotzenplotz', + memo: 'Whatever contribution', + messagesCount: 0, + state: 'DENIED', + }), + expect.objectContaining({ + amount: '166', + confirmedAt: null, + confirmedBy: null, + contributionDate: expect.any(String), + createdAt: expect.any(String), + deniedAt: null, + deniedBy: null, + firstName: 'Räuber', + id: expect.any(Number), + lastName: 'Hotzenplotz', + memo: 'Whatever contribution', + messagesCount: 0, + state: 'DELETED', + }), + expect.objectContaining({ + amount: '166', + confirmedAt: expect.any(String), + confirmedBy: expect.any(Number), + contributionDate: expect.any(String), + createdAt: expect.any(String), + deniedAt: null, + deniedBy: null, + firstName: 'Räuber', + id: expect.any(Number), + lastName: 'Hotzenplotz', + memo: 'Whatever contribution', + messagesCount: 0, + state: 'CONFIRMED', + }), + expect.objectContaining({ + amount: '100', + confirmedAt: null, + confirmedBy: null, + contributionDate: expect.any(String), + createdAt: expect.any(String), + deniedAt: expect.any(String), + deniedBy: expect.any(Number), + firstName: 'Bibi', + id: expect.any(Number), + lastName: 'Bloxberg', + memo: 'Test contribution to deny', + messagesCount: 0, + state: 'DENIED', + }), + expect.objectContaining({ + amount: '100', + confirmedAt: expect.any(String), + confirmedBy: expect.any(Number), + contributionDate: expect.any(String), + createdAt: expect.any(String), + deniedAt: null, + deniedBy: null, + firstName: 'Bibi', + id: expect.any(Number), + lastName: 'Bloxberg', + memo: 'Test contribution to confirm', + messagesCount: 0, + state: 'CONFIRMED', + }), + expect.objectContaining({ + amount: '100', + confirmedAt: null, + confirmedBy: null, + contributionDate: expect.any(String), + createdAt: expect.any(String), + deniedAt: null, + deniedBy: null, + firstName: 'Bibi', + id: expect.any(Number), + lastName: 'Bloxberg', + memo: 'Test IN_PROGRESS contribution', + messagesCount: 0, + state: 'IN_PROGRESS', + }), + expect.objectContaining({ + amount: '10', + confirmedAt: null, + confirmedBy: null, + contributionDate: expect.any(String), + createdAt: expect.any(String), + deniedAt: null, + deniedBy: null, + firstName: 'Bibi', + id: expect.any(Number), + lastName: 'Bloxberg', + memo: 'Test PENDING contribution update', + messagesCount: 0, + state: 'PENDING', + }), + expect.objectContaining({ + amount: '100', + confirmedAt: null, + confirmedBy: null, + contributionDate: expect.any(String), + createdAt: expect.any(String), + deniedAt: null, + deniedBy: null, + firstName: 'Bibi', + id: expect.any(Number), + lastName: 'Bloxberg', + memo: 'Test contribution to delete', + messagesCount: 0, + state: 'DELETED', + }), + expect.objectContaining({ + amount: '1000', + confirmedAt: expect.any(String), + confirmedBy: expect.any(Number), + contributionDate: expect.any(String), + createdAt: expect.any(String), + deniedAt: null, + deniedBy: null, + firstName: 'Bibi', + id: expect.any(Number), + lastName: 'Bloxberg', + memo: 'Herzlich Willkommen bei Gradido!', + messagesCount: 0, + state: 'CONFIRMED', }), ]), }, diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 6016a2c23..89973906a 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -30,12 +30,11 @@ import { backendLogger as logger } from '@/server/logger' import { getCreationDates, getUserCreation, - getUserCreations, validateContribution, updateCreations, isValidDateString, } from './util/creations' -import { MEMO_MAX_CHARS, MEMO_MIN_CHARS, FULL_CREATION_AVAILABLE } from './const/const' +import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const' import { Event, EventContributionCreate, @@ -504,8 +503,6 @@ export class ContributionResolver { .offset((currentPage - 1) * pageSize) .getManyAndCount() - console.log('dbContributions', dbContributions) - console.log('count', count) return new ContributionListResult( count, dbContributions.map((contribution) => new Contribution(contribution, contribution.user)), diff --git a/backend/src/seeds/graphql/queries.ts b/backend/src/seeds/graphql/queries.ts index 423575a16..400d41490 100644 --- a/backend/src/seeds/graphql/queries.ts +++ b/backend/src/seeds/graphql/queries.ts @@ -198,7 +198,7 @@ query ($currentPage: Int = 1, $pageSize: Int = 5, $order: Order = DESC, $statusF export const adminListAllContributions = gql` query ( $currentPage: Int = 1 - $pageSize: Int = 3 + $pageSize: Int = 25 $order: Order = DESC $statusFilter: [ContributionStatus!] ) { From 6a0ccb75b85888df2ff1a044024a9863c998f561 Mon Sep 17 00:00:00 2001 From: elweyn Date: Mon, 6 Feb 2023 15:32:12 +0100 Subject: [PATCH 03/19] Remove the ignore on nodemon watch of test files. --- admin/package.json | 5 +---- backend/package.json | 3 --- database/package.json | 3 --- frontend/package.json | 5 +---- 4 files changed, 2 insertions(+), 14 deletions(-) diff --git a/admin/package.json b/admin/package.json index 30e93239b..8270c4da6 100644 --- a/admin/package.json +++ b/admin/package.json @@ -86,8 +86,5 @@ "> 1%", "last 2 versions", "not ie <= 10" - ], - "nodemonConfig": { - "ignore": ["**/*.spec.js"] - } + ] } diff --git a/backend/package.json b/backend/package.json index 9a36c2ff8..bfcd61d5b 100644 --- a/backend/package.json +++ b/backend/package.json @@ -72,8 +72,5 @@ "ts-node": "^10.0.0", "tsconfig-paths": "^3.14.0", "typescript": "^4.3.4" - }, - "nodemonConfig": { - "ignore": ["**/*.test.ts"] } } diff --git a/database/package.json b/database/package.json index dc805da93..f4e1c7e84 100644 --- a/database/package.json +++ b/database/package.json @@ -47,8 +47,5 @@ "ts-mysql-migrate": "^1.0.2", "typeorm": "^0.2.38", "uuid": "^8.3.2" - }, - "nodemonConfig": { - "ignore": ["**/*.test.ts"] } } diff --git a/frontend/package.json b/frontend/package.json index 73651327f..29c440988 100755 --- a/frontend/package.json +++ b/frontend/package.json @@ -104,8 +104,5 @@ ], "author": "Gradido-Akademie - https://www.gradido.net/", "license": "Apache-2.0", - "description": "Gradido, the Natural Economy of Life, is a way to worldwide prosperity and peace in harmony with nature. - Gradido, die Natürliche Ökonomie des lebens, ist ein Weg zu weltweitem Wohlstand und Frieden in Harmonie mit der Natur.", - "nodemonConfig": { - "ignore": ["**/*.spec.js"] - } + "description": "Gradido, the Natural Economy of Life, is a way to worldwide prosperity and peace in harmony with nature. - Gradido, die Natürliche Ökonomie des lebens, ist ein Weg zu weltweitem Wohlstand und Frieden in Harmonie mit der Natur." } From 7f182a5927ffd5cab3ebfbb4af39ac2d4f1e1e21 Mon Sep 17 00:00:00 2001 From: ogerly Date: Thu, 16 Feb 2023 15:21:55 +0100 Subject: [PATCH 04/19] change fetchPolicy, add scripts.update --- frontend/src/pages/Community.vue | 2 +- package.json | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/frontend/src/pages/Community.vue b/frontend/src/pages/Community.vue index 113bcd4e4..7427aa2fa 100644 --- a/frontend/src/pages/Community.vue +++ b/frontend/src/pages/Community.vue @@ -122,13 +122,13 @@ export default { query() { return listAllContributions }, - fetchPolicy: 'network-only', variables() { return { currentPage: this.currentPageAll, pageSize: this.pageSizeAll, } }, + fetchPolicy: 'no-cache', update({ listAllContributions }) { this.contributionCountAll = listAllContributions.contributionCount this.itemsAll = listAllContributions.contributionList diff --git a/package.json b/package.json index 2220c1a85..85b8dfe53 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,8 @@ "author": "Ulf Gebhardt ", "license": "Apache-2.0", "scripts": { - "release": "scripts/release.sh" + "release": "scripts/release.sh", + "update": "cd admin && yarn && cd ../backend && yarn && cd ../database && yarn && cd ../dht-node && yarn && cd ../e2e-tests && yarn && cd ../federation && yarn && cd ../frontend && yarn" }, "dependencies": { "auto-changelog": "^2.4.0", From 6567babd3b516b459e9a5bbf4a522120de37f807 Mon Sep 17 00:00:00 2001 From: ogerly Date: Thu, 16 Feb 2023 15:28:40 +0100 Subject: [PATCH 05/19] remove package json script update --- package.json | 1 - 1 file changed, 1 deletion(-) diff --git a/package.json b/package.json index 85b8dfe53..959e4d6d5 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,6 @@ "license": "Apache-2.0", "scripts": { "release": "scripts/release.sh", - "update": "cd admin && yarn && cd ../backend && yarn && cd ../database && yarn && cd ../dht-node && yarn && cd ../e2e-tests && yarn && cd ../federation && yarn && cd ../frontend && yarn" }, "dependencies": { "auto-changelog": "^2.4.0", From 10327e9fd507342b240b4c91e5d0f00201d0342c Mon Sep 17 00:00:00 2001 From: ogerly Date: Thu, 16 Feb 2023 15:39:33 +0100 Subject: [PATCH 06/19] remove comma --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 959e4d6d5..2220c1a85 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "author": "Ulf Gebhardt ", "license": "Apache-2.0", "scripts": { - "release": "scripts/release.sh", + "release": "scripts/release.sh" }, "dependencies": { "auto-changelog": "^2.4.0", From 3476f680ed61f784b249aba750a8fbefe21917d1 Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 17 Feb 2023 13:53:58 +0100 Subject: [PATCH 07/19] Remove QueryBuilder and rewrite it with ContributionEntity.findAndCount method. --- .../graphql/resolver/ContributionResolver.ts | 31 +++++++------------ 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index d2e6001c9..0d1e6db9a 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -431,25 +431,18 @@ export class ContributionResolver { @Arg('statusFilter', () => [ContributionStatus], { nullable: true }) statusFilter?: ContributionStatus[], ): Promise { - const where: { - contributionStatus?: FindOperator | null - } = {} - - if (statusFilter && statusFilter.length) { - where.contributionStatus = In(statusFilter) - } - - const [dbContributions, count] = await getConnection() - .createQueryBuilder() - .select('c') - .from(DbContribution, 'c') - .innerJoinAndSelect('c.user', 'u') - .where(where) - .withDeleted() - .orderBy('c.createdAt', order) - .limit(pageSize) - .offset((currentPage - 1) * pageSize) - .getManyAndCount() + const [dbContributions, count] = await DbContribution.findAndCount({ + where: { + ...(statusFilter && statusFilter.length && { contributionStatus: In(statusFilter) }), + }, + withDeleted: true, + order: { + createdAt: order, + }, + relations: ['user'], + skip: (currentPage - 1) * pageSize, + take: pageSize, + }) return new ContributionListResult( count, From 62284bd0163f5a8536b976a6e83281cd05d7c5e0 Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 17 Feb 2023 13:54:39 +0100 Subject: [PATCH 08/19] Set test for adminListAllContributions at the end of the admin szenario. --- .../resolver/ContributionResolver.test.ts | 557 ++++++++++-------- 1 file changed, 318 insertions(+), 239 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index 638622738..a77f09b9f 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -49,6 +49,7 @@ import { raeuberHotzenplotz } from '@/seeds/users/raeuber-hotzenplotz' import { UnconfirmedContribution } from '@model/UnconfirmedContribution' import { ContributionListResult } from '@model/Contribution' import { ContributionStatus } from '@enum/ContributionStatus' +import { Order } from '@enum/Order' // mock account activation email to avoid console spam jest.mock('@/emails/sendEmailVariants', () => { @@ -1690,20 +1691,6 @@ describe('ContributionResolver', () => { }) }) - describe('adminListAllContributions', () => { - it('returns an error', async () => { - await expect( - query({ - query: adminListAllContributions, - }), - ).resolves.toEqual( - expect.objectContaining({ - errors: [new GraphQLError('401 Unauthorized')], - }), - ) - }) - }) - describe('adminDeleteContribution', () => { it('returns an error', async () => { await expect( @@ -1798,20 +1785,6 @@ describe('ContributionResolver', () => { }) }) - describe('adminListAllContributions', () => { - it('returns an error', async () => { - await expect( - query({ - query: adminListAllContributions, - }), - ).resolves.toEqual( - expect.objectContaining({ - errors: [new GraphQLError('401 Unauthorized')], - }), - ) - }) - }) - describe('adminDeleteContribution', () => { it('returns an error', async () => { await expect( @@ -2406,217 +2379,6 @@ describe('ContributionResolver', () => { }) }) - describe('adminListAllContributions', () => { - it('returns four pending creations', async () => { - const { - data: { adminListAllContributions: contributionListObject }, - }: { data: { adminListAllContributions: ContributionListResult } } = await query({ - query: adminListAllContributions, - }) - expect(contributionListObject.contributionList).toHaveLength(13) - expect(contributionListObject).toMatchObject({ - contributionCount: 13, - contributionList: expect.arrayContaining([ - expect.objectContaining({ - amount: '500', - confirmedAt: null, - confirmedBy: null, - contributionDate: expect.any(String), - createdAt: expect.any(String), - deniedAt: null, - deniedBy: null, - firstName: 'Bibi', - id: expect.any(Number), - lastName: 'Bloxberg', - memo: 'Grundeinkommen', - messagesCount: 0, - state: 'PENDING', - }), - expect.objectContaining({ - amount: '200', - confirmedAt: null, - confirmedBy: null, - contributionDate: expect.any(String), - createdAt: expect.any(String), - deniedAt: null, - deniedBy: null, - firstName: 'Bibi', - id: expect.any(Number), - lastName: 'Bloxberg', - memo: 'Aktives Grundeinkommen', - messagesCount: 0, - state: 'PENDING', - }), - expect.objectContaining({ - amount: '500', - confirmedAt: null, - confirmedBy: null, - contributionDate: expect.any(String), - createdAt: expect.any(String), - deniedAt: null, - deniedBy: null, - firstName: 'Peter', - id: expect.any(Number), - lastName: 'Lustig', - memo: 'Grundeinkommen', - messagesCount: 0, - state: 'PENDING', - }), - expect.objectContaining({ - amount: '200', - confirmedAt: null, - confirmedBy: null, - contributionDate: expect.any(String), - createdAt: expect.any(String), - deniedAt: null, - deniedBy: null, - firstName: 'Peter', - id: expect.any(Number), - lastName: 'Lustig', - memo: 'Das war leider zu Viel!', - messagesCount: 0, - state: 'PENDING', - }), - expect.objectContaining({ - amount: '166', - confirmedAt: null, - confirmedBy: null, - contributionDate: expect.any(String), - createdAt: expect.any(String), - deniedAt: expect.any(String), - deniedBy: expect.any(Number), - firstName: 'Räuber', - id: expect.any(Number), - lastName: 'Hotzenplotz', - memo: 'Whatever contribution', - messagesCount: 0, - state: 'DENIED', - }), - expect.objectContaining({ - amount: '166', - confirmedAt: null, - confirmedBy: null, - contributionDate: expect.any(String), - createdAt: expect.any(String), - deniedAt: null, - deniedBy: null, - firstName: 'Räuber', - id: expect.any(Number), - lastName: 'Hotzenplotz', - memo: 'Whatever contribution', - messagesCount: 0, - state: 'DELETED', - }), - expect.objectContaining({ - amount: '166', - confirmedAt: expect.any(String), - confirmedBy: expect.any(Number), - contributionDate: expect.any(String), - createdAt: expect.any(String), - deniedAt: null, - deniedBy: null, - firstName: 'Räuber', - id: expect.any(Number), - lastName: 'Hotzenplotz', - memo: 'Whatever contribution', - messagesCount: 0, - state: 'CONFIRMED', - }), - expect.objectContaining({ - amount: '100', - confirmedAt: null, - confirmedBy: null, - contributionDate: expect.any(String), - createdAt: expect.any(String), - deniedAt: expect.any(String), - deniedBy: expect.any(Number), - firstName: 'Bibi', - id: expect.any(Number), - lastName: 'Bloxberg', - memo: 'Test contribution to deny', - messagesCount: 0, - state: 'DENIED', - }), - expect.objectContaining({ - amount: '100', - confirmedAt: expect.any(String), - confirmedBy: expect.any(Number), - contributionDate: expect.any(String), - createdAt: expect.any(String), - deniedAt: null, - deniedBy: null, - firstName: 'Bibi', - id: expect.any(Number), - lastName: 'Bloxberg', - memo: 'Test contribution to confirm', - messagesCount: 0, - state: 'CONFIRMED', - }), - expect.objectContaining({ - amount: '100', - confirmedAt: null, - confirmedBy: null, - contributionDate: expect.any(String), - createdAt: expect.any(String), - deniedAt: null, - deniedBy: null, - firstName: 'Bibi', - id: expect.any(Number), - lastName: 'Bloxberg', - memo: 'Test IN_PROGRESS contribution', - messagesCount: 0, - state: 'IN_PROGRESS', - }), - expect.objectContaining({ - amount: '10', - confirmedAt: null, - confirmedBy: null, - contributionDate: expect.any(String), - createdAt: expect.any(String), - deniedAt: null, - deniedBy: null, - firstName: 'Bibi', - id: expect.any(Number), - lastName: 'Bloxberg', - memo: 'Test PENDING contribution update', - messagesCount: 0, - state: 'PENDING', - }), - expect.objectContaining({ - amount: '100', - confirmedAt: null, - confirmedBy: null, - contributionDate: expect.any(String), - createdAt: expect.any(String), - deniedAt: null, - deniedBy: null, - firstName: 'Bibi', - id: expect.any(Number), - lastName: 'Bloxberg', - memo: 'Test contribution to delete', - messagesCount: 0, - state: 'DELETED', - }), - expect.objectContaining({ - amount: '1000', - confirmedAt: expect.any(String), - confirmedBy: expect.any(Number), - contributionDate: expect.any(String), - createdAt: expect.any(String), - deniedAt: null, - deniedBy: null, - firstName: 'Bibi', - id: expect.any(Number), - lastName: 'Bloxberg', - memo: 'Herzlich Willkommen bei Gradido!', - messagesCount: 0, - state: 'CONFIRMED', - }), - ]), - }) - }) - }) - describe('adminDeleteContribution', () => { describe('creation id does not exist', () => { it('throws an error', async () => { @@ -2957,4 +2719,321 @@ describe('ContributionResolver', () => { }) }) }) + + describe('adminListAllContribution', () => { + describe('unauthenticated', () => { + it('returns an error', async () => { + await expect( + query({ + query: adminListAllContributions, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('401 Unauthorized')], + }), + ) + }) + }) + + describe('authenticated as user', () => { + beforeAll(async () => { + await mutate({ + mutation: login, + variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, + }) + }) + + afterAll(() => { + resetToken() + }) + + it('returns an error', async () => { + await expect( + query({ + query: adminListAllContributions, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('401 Unauthorized')], + }), + ) + }) + }) + + describe('authenticated as admin', () => { + beforeAll(async () => { + await mutate({ + mutation: login, + variables: { email: 'peter@lustig.de', password: 'Aa12345_' }, + }) + }) + + afterAll(() => { + resetToken() + }) + + it('returns thirteen pending creations', async () => { + const { + data: { adminListAllContributions: contributionListObject }, + }: { data: { adminListAllContributions: ContributionListResult } } = await query({ + query: adminListAllContributions, + }) + expect(contributionListObject.contributionList).toHaveLength(19) + expect(contributionListObject).toMatchObject({ + contributionCount: 19, + contributionList: expect.arrayContaining([ + expect.objectContaining({ + amount: expect.decimalEqual(50), + firstName: 'Bibi', + id: expect.any(Number), + lastName: 'Bloxberg', + memo: 'Herzlich Willkommen bei Gradido liebe Bibi!', + messagesCount: 0, + state: 'CONFIRMED', + }), + expect.objectContaining({ + amount: expect.decimalEqual(50), + firstName: 'Bibi', + id: expect.any(Number), + lastName: 'Bloxberg', + memo: 'Herzlich Willkommen bei Gradido liebe Bibi!', + messagesCount: 0, + state: 'CONFIRMED', + }), + expect.objectContaining({ + amount: expect.decimalEqual(450), + firstName: 'Bibi', + id: expect.any(Number), + lastName: 'Bloxberg', + memo: 'Herzlich Willkommen bei Gradido liebe Bibi!', + messagesCount: 0, + state: 'CONFIRMED', + }), + expect.objectContaining({ + amount: expect.decimalEqual(100), + firstName: 'Bob', + id: expect.any(Number), + lastName: 'der Baumeister', + memo: 'Confirmed Contribution', + messagesCount: 0, + state: 'CONFIRMED', + }), + 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: 'Bibi', + id: expect.any(Number), + lastName: 'Bloxberg', + memo: 'Aktives Grundeinkommen', + messagesCount: 0, + state: 'PENDING', + }), + expect.objectContaining({ + amount: expect.decimalEqual(500), + firstName: 'Bibi', + id: expect.any(Number), + lastName: 'Bloxberg', + memo: 'Grundeinkommen', + messagesCount: 0, + state: 'PENDING', + }), + expect.objectContaining({ + amount: expect.decimalEqual(500), + firstName: 'Peter', + id: expect.any(Number), + lastName: 'Lustig', + memo: 'Grundeinkommen', + messagesCount: 0, + state: 'PENDING', + }), + expect.objectContaining({ + amount: expect.decimalEqual(10), + firstName: 'Bibi', + id: expect.any(Number), + lastName: 'Bloxberg', + memo: 'Test PENDING contribution update', + 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', + }), + 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: 'DENIED', + }), + expect.objectContaining({ + amount: expect.decimalEqual(166), + firstName: 'Räuber', + id: expect.any(Number), + lastName: 'Hotzenplotz', + memo: 'Whatever contribution', + messagesCount: 0, + state: 'CONFIRMED', + }), + expect.objectContaining({ + amount: expect.decimalEqual(100), + firstName: 'Bibi', + id: expect.any(Number), + lastName: 'Bloxberg', + memo: 'Test IN_PROGRESS contribution', + messagesCount: 0, + state: 'IN_PROGRESS', + }), + expect.objectContaining({ + amount: expect.decimalEqual(100), + firstName: 'Bibi', + id: expect.any(Number), + lastName: 'Bloxberg', + memo: 'Test contribution to confirm', + messagesCount: 0, + state: 'CONFIRMED', + }), + expect.objectContaining({ + amount: expect.decimalEqual(100), + firstName: 'Bibi', + id: expect.any(Number), + lastName: 'Bloxberg', + memo: 'Test contribution to deny', + messagesCount: 0, + state: 'DENIED', + }), + expect.objectContaining({ + amount: expect.decimalEqual(100), + firstName: 'Bibi', + id: expect.any(Number), + lastName: 'Bloxberg', + memo: 'Test contribution to delete', + messagesCount: 0, + state: 'DELETED', + }), + expect.objectContaining({ + amount: expect.decimalEqual(1000), + firstName: 'Bibi', + id: expect.any(Number), + lastName: 'Bloxberg', + memo: 'Herzlich Willkommen bei Gradido!', + messagesCount: 0, + state: 'CONFIRMED', + }), + ]), + }) + }) + + it('returns five pending creations', async () => { + const { + data: { adminListAllContributions: contributionListObject }, + }: { data: { adminListAllContributions: ContributionListResult } } = await query({ + query: adminListAllContributions, + variables: { + currentPage: 1, + pageSize: 5, + order: Order.DESC, + statusFilter: ['PENDING'], + }, + }) + console.log(contributionListObject.contributionList) + expect(contributionListObject.contributionList).toHaveLength(5) + expect(contributionListObject).toMatchObject({ + contributionCount: 6, + contributionList: expect.arrayContaining([ + expect.objectContaining({ + amount: '400', + firstName: 'Peter', + id: expect.any(Number), + lastName: 'Lustig', + memo: 'Herzlich Willkommen bei Gradido!', + messagesCount: 0, + state: 'PENDING', + }), + expect.objectContaining({ + amount: '200', + firstName: 'Bibi', + id: expect.any(Number), + lastName: 'Bloxberg', + memo: 'Aktives Grundeinkommen', + messagesCount: 0, + state: 'PENDING', + }), + expect.objectContaining({ + amount: '500', + firstName: 'Bibi', + id: expect.any(Number), + lastName: 'Bloxberg', + memo: 'Grundeinkommen', + messagesCount: 0, + state: 'PENDING', + }), + expect.objectContaining({ + amount: '500', + firstName: 'Peter', + id: expect.any(Number), + lastName: 'Lustig', + memo: 'Grundeinkommen', + messagesCount: 0, + state: 'PENDING', + }), + expect.objectContaining({ + amount: '100', + firstName: 'Peter', + id: expect.any(Number), + lastName: 'Lustig', + memo: 'Test env contribution', + messagesCount: 0, + state: 'PENDING', + }), + expect.not.objectContaining({ + state: 'DENIED', + }), + expect.not.objectContaining({ + state: 'DELETED', + }), + expect.not.objectContaining({ + state: 'CONFIRMED', + }), + expect.not.objectContaining({ + state: 'IN_PROGRESS', + }), + ]), + }) + }) + }) + }) }) From a54f1711547fcf2fef5a58954f1d99acb29329ca Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 17 Feb 2023 13:57:02 +0100 Subject: [PATCH 09/19] Remove console.log statement to test. --- backend/src/graphql/resolver/ContributionResolver.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index a77f09b9f..536e41db0 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -2969,7 +2969,6 @@ describe('ContributionResolver', () => { statusFilter: ['PENDING'], }, }) - console.log(contributionListObject.contributionList) expect(contributionListObject.contributionList).toHaveLength(5) expect(contributionListObject).toMatchObject({ contributionCount: 6, From 9ddef04f569fe0cc81d906971c7a332401e9e113 Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 17 Feb 2023 15:46:53 +0100 Subject: [PATCH 10/19] Change test name. --- backend/src/graphql/resolver/ContributionResolver.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index 536e41db0..528148997 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -2772,7 +2772,7 @@ describe('ContributionResolver', () => { resetToken() }) - it('returns thirteen pending creations', async () => { + it('returns 19 pending creations', async () => { const { data: { adminListAllContributions: contributionListObject }, }: { data: { adminListAllContributions: ContributionListResult } } = await query({ From 84c724daeaeb329e33d11c53a369158346c35c62 Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 17 Feb 2023 15:51:45 +0100 Subject: [PATCH 11/19] Change to suggestion --- backend/src/graphql/resolver/ContributionResolver.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index 528148997..c01cdda4c 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -2772,7 +2772,7 @@ describe('ContributionResolver', () => { resetToken() }) - it('returns 19 pending creations', async () => { + it('returns 19 creations in total', async () => { const { data: { adminListAllContributions: contributionListObject }, }: { data: { adminListAllContributions: ContributionListResult } } = await query({ From a61e66ffc4a78ee6d0e71a4b3980fe51a84013ba Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 17 Feb 2023 16:12:26 +0100 Subject: [PATCH 12/19] Refactor the near functions to a single one. --- .../graphql/resolver/ContributionResolver.ts | 45 +++++++------------ .../resolver/util/findContributions.ts | 24 ++++++++++ 2 files changed, 39 insertions(+), 30 deletions(-) create mode 100644 backend/src/graphql/resolver/util/findContributions.ts diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 0d1e6db9a..0fb3c198f 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -55,6 +55,7 @@ import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK' import LogError from '@/server/LogError' import { getLastTransaction } from './util/getLastTransaction' +import { findContributions } from './util/findContributions' @Resolver() export class ContributionResolver { @@ -167,25 +168,14 @@ export class ContributionResolver { @Arg('statusFilter', () => [ContributionStatus], { nullable: true }) statusFilter?: ContributionStatus[], ): Promise { - const where: { - contributionStatus?: FindOperator | null - } = {} + const [dbContributions, count] = await findContributions( + order, + currentPage, + pageSize, + false, + statusFilter, + ) - if (statusFilter && statusFilter.length) { - where.contributionStatus = In(statusFilter) - } - - const [dbContributions, count] = await getConnection() - .createQueryBuilder() - .select('c') - .from(DbContribution, 'c') - .innerJoinAndSelect('c.user', 'u') - .leftJoinAndSelect('c.messages', 'm') - .where(where) - .orderBy('c.createdAt', order) - .limit(pageSize) - .offset((currentPage - 1) * pageSize) - .getManyAndCount() return new ContributionListResult( count, dbContributions.map((contribution) => new Contribution(contribution, contribution.user)), @@ -431,18 +421,13 @@ export class ContributionResolver { @Arg('statusFilter', () => [ContributionStatus], { nullable: true }) statusFilter?: ContributionStatus[], ): Promise { - const [dbContributions, count] = await DbContribution.findAndCount({ - where: { - ...(statusFilter && statusFilter.length && { contributionStatus: In(statusFilter) }), - }, - withDeleted: true, - order: { - createdAt: order, - }, - relations: ['user'], - skip: (currentPage - 1) * pageSize, - take: pageSize, - }) + const [dbContributions, count] = await findContributions( + order, + currentPage, + pageSize, + true, + statusFilter, + ) return new ContributionListResult( count, diff --git a/backend/src/graphql/resolver/util/findContributions.ts b/backend/src/graphql/resolver/util/findContributions.ts new file mode 100644 index 000000000..0dc70cf30 --- /dev/null +++ b/backend/src/graphql/resolver/util/findContributions.ts @@ -0,0 +1,24 @@ +import { ContributionStatus } from '@enum/ContributionStatus' +import { Order } from '@enum/Order' +import { Contribution as DbContribution } from '@entity/Contribution' +import { In } from '@dbTools/typeorm' + +export const findContributions = async ( + order: Order, + currentPage: number, + pageSize: number, + withDeleted: boolean, + statusFilter?: ContributionStatus[], +): Promise<[DbContribution[], number]> => + DbContribution.findAndCount({ + where: { + ...(statusFilter && statusFilter.length && { contributionStatus: In(statusFilter) }), + }, + withDeleted: withDeleted, + order: { + createdAt: order, + }, + relations: ['user'], + skip: (currentPage - 1) * pageSize, + take: pageSize, + }) From bf5cb142cce4986174a4f158bba2a584488626a3 Mon Sep 17 00:00:00 2001 From: elweyn Date: Sat, 18 Feb 2023 07:13:35 +0100 Subject: [PATCH 13/19] Remove unused In import. --- backend/src/graphql/resolver/ContributionResolver.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 0fb3c198f..36ed2c089 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -1,6 +1,6 @@ import Decimal from 'decimal.js-light' import { Arg, Args, Authorized, Ctx, Int, Mutation, Query, Resolver } from 'type-graphql' -import { FindOperator, IsNull, In, getConnection } from '@dbTools/typeorm' +import { FindOperator, IsNull, getConnection } from '@dbTools/typeorm' import { Contribution as DbContribution } from '@entity/Contribution' import { ContributionMessage } from '@entity/ContributionMessage' From 1e7d4a779adffb8ee82c64db0518996f35f4d75f Mon Sep 17 00:00:00 2001 From: Hannes Heine Date: Tue, 21 Feb 2023 04:02:55 +0100 Subject: [PATCH 14/19] Update backend/src/graphql/resolver/ContributionResolver.test.ts Co-authored-by: Moriz Wahl --- backend/src/graphql/resolver/ContributionResolver.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index c01cdda4c..40da5339b 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -2957,7 +2957,7 @@ describe('ContributionResolver', () => { }) }) - it('returns five pending creations', async () => { + it('returns five pending creations with page size set to 5', async () => { const { data: { adminListAllContributions: contributionListObject }, }: { data: { adminListAllContributions: ContributionListResult } } = await query({ From 93d07ca4d131147283494fa77fea6208a25a3a83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Tue, 21 Feb 2023 22:29:44 +0100 Subject: [PATCH 15/19] add dht-node to deployment scripts --- deployment/bare_metal/.env.dist | 9 +++++++-- deployment/bare_metal/install.sh | 3 +++ deployment/bare_metal/start.sh | 15 +++++++++++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/deployment/bare_metal/.env.dist b/deployment/bare_metal/.env.dist index 9c9c7ac82..b19bd8855 100644 --- a/deployment/bare_metal/.env.dist +++ b/deployment/bare_metal/.env.dist @@ -57,10 +57,15 @@ EMAIL_CODE_REQUEST_TIME=10 WEBHOOK_ELOPAGE_SECRET=secret # Federation -# if you set the value of FEDERATION_DHT_TOPIC, the DHT hyperswarm will start to announce and listen -# on an hash created from this topic +FEDERATION_DHT_CONFIG_VERSION=v2.2023-02-07 +# if you set the value of FEDERATION_DHT_TOPIC, the DHT hyperswarm will start to announce and listen on an hash created from this topic # FEDERATION_DHT_TOPIC=GRADIDO_HUB # FEDERATION_DHT_SEED=64ebcb0e3ad547848fef4197c6e2332f +FEDERATION_COMMUNITY_URL=http://stage1.gradido.net +# the api port is the baseport, which will be added with the api-version, e.g. 1_0 = 5010 +FEDERATION_COMMUNITY_API_PORT=5000 + + # database DATABASE_CONFIG_VERSION=v1.2022-03-18 diff --git a/deployment/bare_metal/install.sh b/deployment/bare_metal/install.sh index 9e60bec08..284e40576 100755 --- a/deployment/bare_metal/install.sh +++ b/deployment/bare_metal/install.sh @@ -137,6 +137,9 @@ envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/frontend/.env # Configure admin envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/admin/.env.template > $PROJECT_ROOT/admin/.env +# Configure dht-node +envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/dht-node/.env.template > $PROJECT_ROOT/dht-node/.env + # create cronjob to delete yarn output in /tmp # crontab -e # hourly job: 0 * * * * find /tmp -name "yarn--*" -cmin +60 -exec rm -r {} \; > /dev/null diff --git a/deployment/bare_metal/start.sh b/deployment/bare_metal/start.sh index 95b89241f..14a616040 100755 --- a/deployment/bare_metal/start.sh +++ b/deployment/bare_metal/start.sh @@ -93,10 +93,12 @@ cp -f $PROJECT_ROOT/database/.env $PROJECT_ROOT/database/.env.bak cp -f $PROJECT_ROOT/backend/.env $PROJECT_ROOT/backend/.env.bak cp -f $PROJECT_ROOT/frontend/.env $PROJECT_ROOT/frontend/.env.bak cp -f $PROJECT_ROOT/admin/.env $PROJECT_ROOT/admin/.env.bak +cp -f $PROJECT_ROOT/dht-node/.env $PROJECT_ROOT/dht-node/.env.bak envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/database/.env.template > $PROJECT_ROOT/database/.env envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/backend/.env.template > $PROJECT_ROOT/backend/.env envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/frontend/.env.template > $PROJECT_ROOT/frontend/.env envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/admin/.env.template > $PROJECT_ROOT/admin/.env +envsubst "$(env | sed -e 's/=.*//' -e 's/^/\$/g')" < $PROJECT_ROOT/dht-node/.env.template > $PROJECT_ROOT/dht-node/.env # Install & build database echo 'Updating database' >> $UPDATE_HTML @@ -152,6 +154,19 @@ pm2 delete gradido-admin pm2 start --name gradido-admin "yarn --cwd $PROJECT_ROOT/admin start" -l $GRADIDO_LOG_PATH/pm2.admin.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS' pm2 save +# Install & build dht-node +echo 'Updating dht-node' >> $UPDATE_HTML +cd $PROJECT_ROOT/dht-node +# TODO maybe handle this differently? +unset NODE_ENV +yarn install +yarn build +# TODO maybe handle this differently? +export NODE_ENV=production +pm2 delete gradido-dht-node +pm2 start --name gradido-dht-node "yarn --cwd $PROJECT_ROOT/dht-node start" -l $GRADIDO_LOG_PATH/pm2.dht-node.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS' +pm2 save + # let nginx showing gradido echo 'Configuring nginx to serve gradido again' >> $UPDATE_HTML ln -s /etc/nginx/sites-available/gradido.conf /etc/nginx/sites-enabled/ From d37714b4688097f26e88dce4154d541deaff6456 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Tue, 21 Feb 2023 23:02:46 +0100 Subject: [PATCH 16/19] config changes --- dht-node/.env.dist | 10 +++++----- dht-node/.env.template | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dht-node/.env.dist b/dht-node/.env.dist index 5d287ee1a..51728d3e1 100644 --- a/dht-node/.env.dist +++ b/dht-node/.env.dist @@ -11,9 +11,9 @@ TYPEORM_LOGGING_RELATIVE_PATH=typeorm.dht-node.log # LOG_LEVEL=info # Federation -# if you set the value of FEDERATION_DHT_TOPIC, the DHT hyperswarm will start to announce and listen -# on an hash created from this topic +# if you set the value of FEDERATION_DHT_TOPIC, the DHT hyperswarm will start to announce and listen on an hash created from this topic FEDERATION_DHT_TOPIC=GRADIDO_HUB -# FEDERATION_DHT_SEED=64ebcb0e3ad547848fef4197c6e2332f -# FEDERATION_COMMUNITY_URL=http://localhost -# FEDERATION_COMMUNITY_API_PORT=5000 +# FEDERATION_DHT_SEED=64ebcb0e3ad547848fef4197c6e2332f +FEDERATION_COMMUNITY_URL=http://localhost +# the api port is the dht baseport, which will be added with the supported api-versions, e.g. 1_0 = 5010 +FEDERATION_COMMUNITY_API_PORT=5000 diff --git a/dht-node/.env.template b/dht-node/.env.template index b3e5d6478..243bfc60f 100644 --- a/dht-node/.env.template +++ b/dht-node/.env.template @@ -1,4 +1,4 @@ -CONFIG_VERSION=$BACKEND_CONFIG_VERSION +CONFIG_VERSION=$FEDERATION_DHT_CONFIG_VERSION # Database DB_HOST=localhost From e6291c7dd488a6691e178b911c8e9739d16be7ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Tue, 21 Feb 2023 23:56:26 +0100 Subject: [PATCH 17/19] solve error returning ownApiList --- dht-node/log4js-config.json | 4 ++-- dht-node/src/dht_node/index.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dht-node/log4js-config.json b/dht-node/log4js-config.json index 877bc4255..3e5cc59ec 100644 --- a/dht-node/log4js-config.json +++ b/dht-node/log4js-config.json @@ -8,7 +8,7 @@ "pattern": "yyyy-MM-dd", "layout": { - "type": "pattern", "pattern": "%d{ISO8601} %c [%X{user}] [%f : %l] - %m" + "type": "pattern", "pattern": "%d{ISO8601} %p %c [%X{user}] [%f : %l] - %m" }, "keepFileExt" : true, "fileNameSep" : "_", @@ -21,7 +21,7 @@ "pattern": "yyyy-MM-dd", "layout": { - "type": "pattern", "pattern": "%d{ISO8601} %c [%X{user}] [%f : %l] - %m" + "type": "pattern", "pattern": "%d{ISO8601} %p %c [%X{user}] [%f : %l] - %m" }, "keepFileExt" : true, "fileNameSep" : "_", diff --git a/dht-node/src/dht_node/index.ts b/dht-node/src/dht_node/index.ts index 50ed46600..722a62af7 100644 --- a/dht-node/src/dht_node/index.ts +++ b/dht-node/src/dht_node/index.ts @@ -31,8 +31,8 @@ export const startDHT = async (topic: string): Promise => { logger.info(`keyPairDHT: publicKey=${keyPair.publicKey.toString('hex')}`) logger.debug(`keyPairDHT: secretKey=${keyPair.secretKey.toString('hex')}`) - const ownApiVersions = writeHomeCommunityEnries(keyPair.publicKey) - logger.debug(`ApiList: ${JSON.stringify(ownApiVersions)}`) + const ownApiVersions = await writeHomeCommunityEnries(keyPair.publicKey) + logger.info(`ApiList: ${JSON.stringify(ownApiVersions)}`) const node = new DHT({ keyPair }) From 9966a0663066662a98ab46e3e4e196037669ab97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Wed, 22 Feb 2023 21:14:34 +0100 Subject: [PATCH 18/19] conditional start of dht-node --- deployment/bare_metal/start.sh | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/deployment/bare_metal/start.sh b/deployment/bare_metal/start.sh index 14a616040..be353c0cd 100755 --- a/deployment/bare_metal/start.sh +++ b/deployment/bare_metal/start.sh @@ -164,7 +164,11 @@ yarn build # TODO maybe handle this differently? export NODE_ENV=production pm2 delete gradido-dht-node -pm2 start --name gradido-dht-node "yarn --cwd $PROJECT_ROOT/dht-node start" -l $GRADIDO_LOG_PATH/pm2.dht-node.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS' +if [ ! -z $FEDERATION_DHT_TOPIC ]; then + pm2 start --name gradido-dht-node "yarn --cwd $PROJECT_ROOT/dht-node start" -l $GRADIDO_LOG_PATH/pm2.dht-node.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS' +else + echo "No Federation DHT-Topic configured. DHT-Node not started..." +fi pm2 save # let nginx showing gradido From b070ef55041ebd5d0600eab7190594d99c0e12e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Wed, 22 Feb 2023 21:30:32 +0100 Subject: [PATCH 19/19] conditional dht-node start with message --- deployment/bare_metal/start.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/deployment/bare_metal/start.sh b/deployment/bare_metal/start.sh index be353c0cd..89dc9d2f0 100755 --- a/deployment/bare_metal/start.sh +++ b/deployment/bare_metal/start.sh @@ -167,7 +167,9 @@ pm2 delete gradido-dht-node if [ ! -z $FEDERATION_DHT_TOPIC ]; then pm2 start --name gradido-dht-node "yarn --cwd $PROJECT_ROOT/dht-node start" -l $GRADIDO_LOG_PATH/pm2.dht-node.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS' else - echo "No Federation DHT-Topic configured. DHT-Node not started..." + echo "=====================================================================" + echo "WARNING: FEDERATION_DHT_TOPIC not configured. DHT-Node not started..." + echo "=====================================================================" fi pm2 save