From d9f8f8cb0775956d21612d63778fdc38f0bc6a2c Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 16 Jan 2023 10:19:10 +0100 Subject: [PATCH 01/10] normalized-amount-transaction-if-processed again --- frontend/src/components/Inputs/InputAmount.vue | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/Inputs/InputAmount.vue b/frontend/src/components/Inputs/InputAmount.vue index 7a72a3a77..3268a0ec1 100644 --- a/frontend/src/components/Inputs/InputAmount.vue +++ b/frontend/src/components/Inputs/InputAmount.vue @@ -20,7 +20,7 @@ trim v-focus="amountFocused" @focus="amountFocused = true" - @blur="normalizeAmount(true)" + @blur="normalizeAmount(valid)" :disabled="disabled" autocomplete="off" > @@ -90,5 +90,8 @@ export default { this.currentValue = this.$n(this.amountValue, 'ungroupedDecimal') }, }, + mounted() { + if (this.value !== '') this.normalizeAmount(true) + }, } From 7781011b1a5352d7b7cb77ef135443d644dbec30 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 16 Jan 2023 15:22:45 +0100 Subject: [PATCH 02/10] refactor(backend): field resolvers in statistics --- .../src/graphql/model/CommunityStatistics.ts | 27 ++-- .../graphql/resolver/StatisticsResolver.ts | 138 +++++++++++------- 2 files changed, 103 insertions(+), 62 deletions(-) diff --git a/backend/src/graphql/model/CommunityStatistics.ts b/backend/src/graphql/model/CommunityStatistics.ts index 61354115c..8b8a34f80 100644 --- a/backend/src/graphql/model/CommunityStatistics.ts +++ b/backend/src/graphql/model/CommunityStatistics.ts @@ -2,13 +2,25 @@ import { ObjectType, Field } from 'type-graphql' import Decimal from 'decimal.js-light' @ObjectType() -export class CommunityStatistics { - @Field(() => Number) - totalUsers: number - +export class TotalAvailable { @Field(() => Number) activeUsers: number + @Field(() => Decimal) + totalGradidoAvailable: Decimal + + @Field(() => Decimal) + totalGradidoUnbookedDecayed: Decimal +} + +@ObjectType() +export class CommunityStatistics { + @Field(() => Number) + allUsers: number + + @Field(() => Number) + totalUsers: number + @Field(() => Number) deletedUsers: number @@ -18,9 +30,6 @@ export class CommunityStatistics { @Field(() => Decimal) totalGradidoDecayed: Decimal - @Field(() => Decimal) - totalGradidoAvailable: Decimal - - @Field(() => Decimal) - totalGradidoUnbookedDecayed: Decimal + @Field(() => TotalAvailable) + totalAvailable: TotalAvailable } diff --git a/backend/src/graphql/resolver/StatisticsResolver.ts b/backend/src/graphql/resolver/StatisticsResolver.ts index f6c2b9e22..577ca2c81 100644 --- a/backend/src/graphql/resolver/StatisticsResolver.ts +++ b/backend/src/graphql/resolver/StatisticsResolver.ts @@ -1,81 +1,113 @@ import Decimal from 'decimal.js-light' -import { Resolver, Query, Authorized } from 'type-graphql' +import { Resolver, Query, Authorized, FieldResolver } from 'type-graphql' import { getConnection } from '@dbTools/typeorm' import { Transaction as DbTransaction } from '@entity/Transaction' import { User as DbUser } from '@entity/User' -import { CommunityStatistics } from '@model/CommunityStatistics' +import { CommunityStatistics, TotalAvailable } from '@model/CommunityStatistics' import { RIGHTS } from '@/auth/RIGHTS' import { calculateDecay } from '@/util/decay' -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ - -@Resolver() +/* eslint-disable-next-line @typescript-eslint/no-unused-vars */ +@Resolver((of) => CommunityStatistics) export class StatisticsResolver { @Authorized([RIGHTS.COMMUNITY_STATISTICS]) @Query(() => CommunityStatistics) async communityStatistics(): Promise { - const allUsers = await DbUser.count({ withDeleted: true }) - const totalUsers = await DbUser.count() - const deletedUsers = allUsers - totalUsers + return new CommunityStatistics() + } + @FieldResolver(() => Decimal) + async allUsers(): Promise { + return await DbUser.count({ withDeleted: true }) + } + + @FieldResolver() + async totalUsers(): Promise { + return await DbUser.count() + } + + @FieldResolver() + async deletedUsers(): Promise { + return (await this.allUsers()) - (await this.totalUsers()) + } + + @FieldResolver() + async totalGradidoCreated(): Promise { + const queryRunner = getConnection().createQueryRunner() + try { + await queryRunner.connect() + const { totalGradidoCreated } = await queryRunner.manager + .createQueryBuilder() + .select('SUM(transaction.amount) AS totalGradidoCreated') + .from(DbTransaction, 'transaction') + .where('transaction.typeId = 1') + .getRawOne() + return totalGradidoCreated + } finally { + await queryRunner.release() + } + } + + @FieldResolver() + async totalGradidoDecayed(): Promise { + const queryRunner = getConnection().createQueryRunner() + try { + await queryRunner.connect() + const { totalGradidoDecayed } = await queryRunner.manager + .createQueryBuilder() + .select('SUM(transaction.decay) AS totalGradidoDecayed') + .from(DbTransaction, 'transaction') + .where('transaction.decay IS NOT NULL') + .getRawOne() + return totalGradidoDecayed + } finally { + await queryRunner.release() + } + } + + @FieldResolver() + async totalAvailable(): Promise { let totalGradidoAvailable: Decimal = new Decimal(0) let totalGradidoUnbookedDecayed: Decimal = new Decimal(0) const receivedCallDate = new Date() const queryRunner = getConnection().createQueryRunner() - await queryRunner.connect() + try { + 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 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 + 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()) + 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()) + } + }) + + return { + activeUsers, + totalGradidoAvailable, + totalGradidoUnbookedDecayed, } - }) - - const { totalGradidoCreated } = await queryRunner.manager - .createQueryBuilder() - .select('SUM(transaction.amount) AS totalGradidoCreated') - .from(DbTransaction, 'transaction') - .where('transaction.typeId = 1') - .getRawOne() - - const { totalGradidoDecayed } = await queryRunner.manager - .createQueryBuilder() - .select('SUM(transaction.decay) AS totalGradidoDecayed') - .from(DbTransaction, 'transaction') - .where('transaction.decay IS NOT NULL') - .getRawOne() - - await queryRunner.release() - - return { - totalUsers, - activeUsers, - deletedUsers, - totalGradidoCreated, - totalGradidoDecayed, - totalGradidoAvailable, - totalGradidoUnbookedDecayed, + } finally { + await queryRunner.release() } } } From 6b1497a988e42c8d24f16135715695563e0fdc97 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 16 Jan 2023 15:23:17 +0100 Subject: [PATCH 03/10] statistics for field resolvers --- admin/src/graphql/communityStatistics.js | 8 +++++--- admin/src/pages/CommunityStatistic.spec.js | 8 +++++--- admin/src/pages/CommunityStatistic.vue | 8 +++++++- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/admin/src/graphql/communityStatistics.js b/admin/src/graphql/communityStatistics.js index 868bfd02a..1b427dbbe 100644 --- a/admin/src/graphql/communityStatistics.js +++ b/admin/src/graphql/communityStatistics.js @@ -4,12 +4,14 @@ export const communityStatistics = gql` query { communityStatistics { totalUsers - activeUsers deletedUsers totalGradidoCreated totalGradidoDecayed - totalGradidoAvailable - totalGradidoUnbookedDecayed + totalAvailable { + activeUsers + totalGradidoAvailable + totalGradidoUnbookedDecayed + } } } ` diff --git a/admin/src/pages/CommunityStatistic.spec.js b/admin/src/pages/CommunityStatistic.spec.js index 50e04d11f..f8bfa95e2 100644 --- a/admin/src/pages/CommunityStatistic.spec.js +++ b/admin/src/pages/CommunityStatistic.spec.js @@ -17,12 +17,14 @@ const defaultData = () => { return { communityStatistics: { totalUsers: 3113, - activeUsers: 1057, deletedUsers: 35, totalGradidoCreated: '4083774.05000000000000000000', totalGradidoDecayed: '-1062639.13634129622923372197', - totalGradidoAvailable: '2513565.869444365732411569', - totalGradidoUnbookedDecayed: '-500474.6738366222166261272', + totalAvailable: { + activeUsers: 1057, + totalGradidoAvailable: '2513565.869444365732411569', + totalGradidoUnbookedDecayed: '-500474.6738366222166261272', + }, }, } } diff --git a/admin/src/pages/CommunityStatistic.vue b/admin/src/pages/CommunityStatistic.vue index 3b4865ee3..6858e77f6 100644 --- a/admin/src/pages/CommunityStatistic.vue +++ b/admin/src/pages/CommunityStatistic.vue @@ -31,7 +31,13 @@ export default { return communityStatistics }, update({ communityStatistics }) { - this.statistics = communityStatistics + const totals = { ...communityStatistics.totalAvailable } + this.statistics = { ...communityStatistics, ...totals } + this.activeUsers = this.statistics.totalAvailable.activeUsers + this.totalGradidoAvailable = this.statistics.totalAvailable.totalGradidoAvailable + this.totalGradidoUnbookedDecayed = + this.statistics.totalAvailable.totalGradidoUnbookedDecayed + delete this.totalAvailable }, error({ message }) { this.toastError(message) From 9f3c43426dc925dcfcd809f3651306c454138f6c Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 16 Jan 2023 15:28:20 +0100 Subject: [PATCH 04/10] clean up --- admin/src/pages/CommunityStatistic.vue | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/admin/src/pages/CommunityStatistic.vue b/admin/src/pages/CommunityStatistic.vue index 6858e77f6..6a2261d13 100644 --- a/admin/src/pages/CommunityStatistic.vue +++ b/admin/src/pages/CommunityStatistic.vue @@ -33,11 +33,7 @@ export default { update({ communityStatistics }) { const totals = { ...communityStatistics.totalAvailable } this.statistics = { ...communityStatistics, ...totals } - this.activeUsers = this.statistics.totalAvailable.activeUsers - this.totalGradidoAvailable = this.statistics.totalAvailable.totalGradidoAvailable - this.totalGradidoUnbookedDecayed = - this.statistics.totalAvailable.totalGradidoUnbookedDecayed - delete this.totalAvailable + delete this.statistics.totalAvailable }, error({ message }) { this.toastError(message) From 1e66cda707472f85a3a06c915f70706d000e09db Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 16 Jan 2023 19:41:34 +0100 Subject: [PATCH 05/10] change name of dynamic statitics fields --- admin/src/graphql/communityStatistics.js | 2 +- admin/src/pages/CommunityStatistic.spec.js | 2 +- admin/src/pages/CommunityStatistic.vue | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/admin/src/graphql/communityStatistics.js b/admin/src/graphql/communityStatistics.js index 1b427dbbe..3159ee258 100644 --- a/admin/src/graphql/communityStatistics.js +++ b/admin/src/graphql/communityStatistics.js @@ -7,7 +7,7 @@ export const communityStatistics = gql` deletedUsers totalGradidoCreated totalGradidoDecayed - totalAvailable { + dynamicStatisticsFields { activeUsers totalGradidoAvailable totalGradidoUnbookedDecayed diff --git a/admin/src/pages/CommunityStatistic.spec.js b/admin/src/pages/CommunityStatistic.spec.js index f8bfa95e2..528548f02 100644 --- a/admin/src/pages/CommunityStatistic.spec.js +++ b/admin/src/pages/CommunityStatistic.spec.js @@ -20,7 +20,7 @@ const defaultData = () => { deletedUsers: 35, totalGradidoCreated: '4083774.05000000000000000000', totalGradidoDecayed: '-1062639.13634129622923372197', - totalAvailable: { + dynamicStatisticsFields: { activeUsers: 1057, totalGradidoAvailable: '2513565.869444365732411569', totalGradidoUnbookedDecayed: '-500474.6738366222166261272', diff --git a/admin/src/pages/CommunityStatistic.vue b/admin/src/pages/CommunityStatistic.vue index 6a2261d13..e656fd2c8 100644 --- a/admin/src/pages/CommunityStatistic.vue +++ b/admin/src/pages/CommunityStatistic.vue @@ -31,9 +31,9 @@ export default { return communityStatistics }, update({ communityStatistics }) { - const totals = { ...communityStatistics.totalAvailable } + const totals = { ...communityStatistics.dynamicStatisticsFields } this.statistics = { ...communityStatistics, ...totals } - delete this.statistics.totalAvailable + delete this.statistics.dynamicStatisticsFields }, error({ message }) { this.toastError(message) From b66372bd90e501ffaeb2dc9ed843a8d197e24ea6 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 16 Jan 2023 19:42:01 +0100 Subject: [PATCH 06/10] change name of dynamic statitics fields --- backend/src/graphql/model/CommunityStatistics.ts | 7 ++++--- backend/src/graphql/resolver/StatisticsResolver.ts | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/backend/src/graphql/model/CommunityStatistics.ts b/backend/src/graphql/model/CommunityStatistics.ts index 8b8a34f80..87ef595af 100644 --- a/backend/src/graphql/model/CommunityStatistics.ts +++ b/backend/src/graphql/model/CommunityStatistics.ts @@ -2,7 +2,7 @@ import { ObjectType, Field } from 'type-graphql' import Decimal from 'decimal.js-light' @ObjectType() -export class TotalAvailable { +export class DynamicStatisticsFields { @Field(() => Number) activeUsers: number @@ -30,6 +30,7 @@ export class CommunityStatistics { @Field(() => Decimal) totalGradidoDecayed: Decimal - @Field(() => TotalAvailable) - totalAvailable: TotalAvailable + // be carefull querying this, takes longer than 2 secs. + @Field(() => DynamicStatisticsFields) + dynamicStatisticsFields: DynamicStatisticsFields } diff --git a/backend/src/graphql/resolver/StatisticsResolver.ts b/backend/src/graphql/resolver/StatisticsResolver.ts index 577ca2c81..e91840f10 100644 --- a/backend/src/graphql/resolver/StatisticsResolver.ts +++ b/backend/src/graphql/resolver/StatisticsResolver.ts @@ -5,7 +5,7 @@ import { getConnection } from '@dbTools/typeorm' import { Transaction as DbTransaction } from '@entity/Transaction' import { User as DbUser } from '@entity/User' -import { CommunityStatistics, TotalAvailable } from '@model/CommunityStatistics' +import { CommunityStatistics, DynamicStatisticsFields } from '@model/CommunityStatistics' import { RIGHTS } from '@/auth/RIGHTS' import { calculateDecay } from '@/util/decay' @@ -69,7 +69,7 @@ export class StatisticsResolver { } @FieldResolver() - async totalAvailable(): Promise { + async dynamicStatisticsFields(): Promise { let totalGradidoAvailable: Decimal = new Decimal(0) let totalGradidoUnbookedDecayed: Decimal = new Decimal(0) From b52162320d2e6939064cd5025ac0446946e39bba Mon Sep 17 00:00:00 2001 From: mahula Date: Tue, 17 Jan 2023 11:32:22 +0100 Subject: [PATCH 07/10] fix unit tests for amout input component --- frontend/src/components/Inputs/InputAmount.spec.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/frontend/src/components/Inputs/InputAmount.spec.js b/frontend/src/components/Inputs/InputAmount.spec.js index b2d524e08..b20ab0f23 100644 --- a/frontend/src/components/Inputs/InputAmount.spec.js +++ b/frontend/src/components/Inputs/InputAmount.spec.js @@ -46,13 +46,14 @@ describe('InputAmount', () => { describe('amount normalization', () => { describe('if invalid', () => { - beforeEach(() => { + beforeEach(async () => { + await wrapper.setProps({ value: '12m34' }) valid = false }) it('is not normalized', () => { - wrapper.vm.normalizeAmount(valid) - expect(wrapper.vm.amountValue).toBe(0.0) + wrapper.vm.normalizeAmount(false) + expect(wrapper.vm.currentValue).toBe('12m34') }) }) @@ -97,13 +98,14 @@ describe('InputAmount', () => { describe('amount normalization', () => { describe('if invalid', () => { - beforeEach(() => { + beforeEach(async () => { + await wrapper.setProps({ value: '12m34' }) valid = false }) it('is not normalized', () => { wrapper.vm.normalizeAmount(valid) - expect(wrapper.vm.amountValue).toBe(0.0) + expect(wrapper.vm.currentValue).toBe('12m34') }) }) From 782978579932fa6e45195310877fbbff64dd9788 Mon Sep 17 00:00:00 2001 From: ogerly Date: Tue, 17 Jan 2023 13:07:49 +0100 Subject: [PATCH 08/10] resolve conflicts --- frontend/src/components/Contributions/ContributionForm.spec.js | 1 + frontend/src/components/Inputs/InputAmount.spec.js | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/Contributions/ContributionForm.spec.js b/frontend/src/components/Contributions/ContributionForm.spec.js index bc7ed9785..020e3f552 100644 --- a/frontend/src/components/Contributions/ContributionForm.spec.js +++ b/frontend/src/components/Contributions/ContributionForm.spec.js @@ -23,6 +23,7 @@ describe('ContributionForm', () => { const mocks = { $t: jest.fn((t) => t), $d: jest.fn((d) => d), + $n: jest.fn((n) => n), $store: { state: { creation: ['1000', '1000', '1000'], diff --git a/frontend/src/components/Inputs/InputAmount.spec.js b/frontend/src/components/Inputs/InputAmount.spec.js index b20ab0f23..ede54b8c3 100644 --- a/frontend/src/components/Inputs/InputAmount.spec.js +++ b/frontend/src/components/Inputs/InputAmount.spec.js @@ -9,10 +9,11 @@ describe('InputAmount', () => { const mocks = { $t: jest.fn((t) => t), + $n: jest.fn((n) => n), $i18n: { locale: jest.fn(() => 'en'), }, - $n: jest.fn((n) => String(n)), + // $n: jest.fn((n) => String(n)), $route: { params: {}, }, From 808eee7ae26290bd6ab3190b1fdbcde59095c956 Mon Sep 17 00:00:00 2001 From: ogerly Date: Tue, 17 Jan 2023 15:39:01 +0100 Subject: [PATCH 09/10] session extend , remove creation from query verifyLogin --- frontend/src/graphql/queries.js | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/graphql/queries.js b/frontend/src/graphql/queries.js index 65fde8d1d..3b1186a0c 100644 --- a/frontend/src/graphql/queries.js +++ b/frontend/src/graphql/queries.js @@ -13,7 +13,6 @@ export const verifyLogin = gql` hasElopage publisherId isAdmin - creation hideAmountGDD hideAmountGDT } From 35997f5499bbda70a62b36e4292bfbff64793181 Mon Sep 17 00:00:00 2001 From: ogerly Date: Tue, 17 Jan 2023 15:59:46 +0100 Subject: [PATCH 10/10] remove unused code --- frontend/src/components/Inputs/InputAmount.spec.js | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/components/Inputs/InputAmount.spec.js b/frontend/src/components/Inputs/InputAmount.spec.js index ede54b8c3..0b03ce769 100644 --- a/frontend/src/components/Inputs/InputAmount.spec.js +++ b/frontend/src/components/Inputs/InputAmount.spec.js @@ -13,7 +13,6 @@ describe('InputAmount', () => { $i18n: { locale: jest.fn(() => 'en'), }, - // $n: jest.fn((n) => String(n)), $route: { params: {}, },