From de2bd1113e0cc6ba833ef97d9570116c27a9cdc9 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 1 Sep 2022 15:38:05 +0200 Subject: [PATCH 1/7] refactor: Improve Statistics Query --- .../graphql/resolver/StatisticsResolver.ts | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/backend/src/graphql/resolver/StatisticsResolver.ts b/backend/src/graphql/resolver/StatisticsResolver.ts index 4c1500839..c2cebbed5 100644 --- a/backend/src/graphql/resolver/StatisticsResolver.ts +++ b/backend/src/graphql/resolver/StatisticsResolver.ts @@ -7,49 +7,49 @@ import { getConnection } from '@dbTools/typeorm' import Decimal from 'decimal.js-light' import { calculateDecay } from '@/util/decay' +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ + @Resolver() export class StatisticsResolver { @Authorized([RIGHTS.COMMUNITY_STATISTICS]) @Query(() => CommunityStatistics) - async communityStatistics(): Promise { - const allUsers = await DbUser.find({ withDeleted: true }) + async communityStatistics(@Info() info: any): Promise { - let totalUsers = 0 - let activeUsers = 0 - let deletedUsers = 0 + const allUsers = await DbUser.count({ withDeleted: true }) + const totalUsers = await DbUser.count() + const deletedUsers = allUsers - totalUsers let totalGradidoAvailable: Decimal = new Decimal(0) let totalGradidoUnbookedDecayed: Decimal = new Decimal(0) const receivedCallDate = new Date() - for (let i = 0; i < allUsers.length; i++) { - if (allUsers[i].deletedAt) { - deletedUsers++ - } else { - totalUsers++ - const lastTransaction = await DbTransaction.findOne({ - where: { userId: allUsers[i].id }, - order: { balanceDate: 'DESC' }, - }) - if (lastTransaction) { - activeUsers++ - const decay = calculateDecay( - lastTransaction.balance, - lastTransaction.balanceDate, - receivedCallDate, - ) - if (decay) { - totalGradidoAvailable = totalGradidoAvailable.plus(decay.balance.toString()) - totalGradidoUnbookedDecayed = totalGradidoUnbookedDecayed.plus(decay.decay.toString()) - } - } - } - } - const queryRunner = getConnection().createQueryRunner() await queryRunner.connect() + const lastUserTransactions = await queryRunner.manager + .createQueryBuilder(DbUser, 'user') + .select('transaction.balance', 'balance') + .addSelect('transaction.balance_date', 'balanceDate') + .innerJoin(DbTransaction, 'transaction', 'user.id = transaction.user_id') + .where( + `transaction.balance_date = (SELECT MAX(t.balance_date) FROM transactions AS t WHERE t.user_id = user.id)`, + ) + .orderBy('transaction.balance_date', 'DESC') + .addOrderBy('transaction.id', 'DESC') + .getRawMany() + + const activeUsers = lastUserTransactions.length + + lastUserTransactions.forEach(({ balance, balanceDate }) => { + const decay = calculateDecay(new Decimal(balance), new Date(balanceDate), receivedCallDate) + if (decay) { + totalGradidoAvailable = totalGradidoAvailable.plus(decay.balance.toString()) + totalGradidoUnbookedDecayed = totalGradidoUnbookedDecayed.plus(decay.decay.toString()) + } + }) + const { totalGradidoCreated } = await queryRunner.manager .createQueryBuilder() .select('SUM(transaction.amount) AS totalGradidoCreated') From eb8a245c2d526758c2d9f751a0ebe4fee8a63369 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 1 Sep 2022 16:26:57 +0200 Subject: [PATCH 2/7] fix resolver args --- backend/src/graphql/resolver/StatisticsResolver.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/src/graphql/resolver/StatisticsResolver.ts b/backend/src/graphql/resolver/StatisticsResolver.ts index c2cebbed5..b0c061d91 100644 --- a/backend/src/graphql/resolver/StatisticsResolver.ts +++ b/backend/src/graphql/resolver/StatisticsResolver.ts @@ -14,8 +14,7 @@ import { calculateDecay } from '@/util/decay' export class StatisticsResolver { @Authorized([RIGHTS.COMMUNITY_STATISTICS]) @Query(() => CommunityStatistics) - async communityStatistics(@Info() info: any): Promise { - + async communityStatistics(): Promise { const allUsers = await DbUser.count({ withDeleted: true }) const totalUsers = await DbUser.count() const deletedUsers = allUsers - totalUsers From 04b96bac2fcb90c25611abd856673fcc5b998081 Mon Sep 17 00:00:00 2001 From: elweyn Date: Tue, 6 Sep 2022 10:39:20 +0200 Subject: [PATCH 3/7] Throw error if moderator tries to answer his own contribution in adminCreateContributionMessage. --- backend/src/graphql/resolver/AdminResolver.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index f4656aec8..6ed56e082 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -717,6 +717,9 @@ export class AdminResolver { if (!contribution) { throw new Error('Contribution not found') } + if (contribution.userId === user.id) { + throw new Error('Can not answer on own contribution') + } contributionMessage.contributionId = contributionId contributionMessage.createdAt = new Date() contributionMessage.message = message From ced14bd752e00adb6635a34893f89cbd383662bf Mon Sep 17 00:00:00 2001 From: elweyn Date: Tue, 6 Sep 2022 10:59:32 +0200 Subject: [PATCH 4/7] Change error message Admin can not answer on own contribution. --- backend/src/graphql/resolver/AdminResolver.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index 6ed56e082..65662e8eb 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -718,7 +718,7 @@ export class AdminResolver { throw new Error('Contribution not found') } if (contribution.userId === user.id) { - throw new Error('Can not answer on own contribution') + throw new Error('Admin can not answer on own contribution') } contributionMessage.contributionId = contributionId contributionMessage.createdAt = new Date() From aa9d60c78c77d56c23461e45d107a1f7736ef672 Mon Sep 17 00:00:00 2001 From: elweyn Date: Tue, 6 Sep 2022 11:07:23 +0200 Subject: [PATCH 5/7] Add test that admin can not call adminCreateContributionMessage on own contribution --- .../ContributionMessageResolver.test.ts | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/backend/src/graphql/resolver/ContributionMessageResolver.test.ts b/backend/src/graphql/resolver/ContributionMessageResolver.test.ts index 6c617acb4..c0e330750 100644 --- a/backend/src/graphql/resolver/ContributionMessageResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionMessageResolver.test.ts @@ -93,6 +93,38 @@ describe('ContributionMessageResolver', () => { }), ) }) + + it('throws error when contribution.userId equals user.id', async () => { + await query({ + query: login, + variables: { email: 'peter@lustig.de', password: 'Aa12345_' }, + }) + const result2 = await mutate({ + mutation: createContribution, + variables: { + amount: 100.0, + memo: 'Test env contribution', + creationDate: new Date().toString(), + }, + }) + await expect( + mutate({ + mutation: adminCreateContributionMessage, + variables: { + contributionId: result2.data.createContribution.id, + message: 'Test', + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [ + new GraphQLError( + 'ContributionMessage was not successful: Error: Admin can not answer on own contribution', + ), + ], + }), + ) + }) }) describe('valid input', () => { From dfa97fd855157a14159f72e8be634dce51b4e7ae Mon Sep 17 00:00:00 2001 From: ogerly Date: Tue, 6 Sep 2022 11:00:29 +0200 Subject: [PATCH 6/7] moderator cannot answer himself --- .../components/Tables/OpenCreationsTable.vue | 59 +++++++++++-------- .../graphql/listUnconfirmedContributions.js | 1 + 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/admin/src/components/Tables/OpenCreationsTable.vue b/admin/src/components/Tables/OpenCreationsTable.vue index 86c5ecce6..af9947f85 100644 --- a/admin/src/components/Tables/OpenCreationsTable.vue +++ b/admin/src/components/Tables/OpenCreationsTable.vue @@ -12,33 +12,42 @@