From 906d700f19383380e5e50ce15c3699261aaf635d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Wed, 8 Jun 2022 03:21:25 +0200 Subject: [PATCH 01/25] Merge remote-tracking branch 'origin/1920-feature-create-contribution-link-table' into 1921-feature-contribution-link-crud-in-admin-resolver --- .../0037-add_contribution_links_table/ContributionLinks.ts | 2 +- database/migrations/0037-add_contribution_links_table.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/database/entity/0037-add_contribution_links_table/ContributionLinks.ts b/database/entity/0037-add_contribution_links_table/ContributionLinks.ts index 6539716c6..26ecc6cea 100644 --- a/database/entity/0037-add_contribution_links_table/ContributionLinks.ts +++ b/database/entity/0037-add_contribution_links_table/ContributionLinks.ts @@ -11,7 +11,7 @@ export class ContributionLinks extends BaseEntity { name: string @Column({ length: 255, nullable: false, collation: 'utf8mb4_unicode_ci' }) - description: string + memo: string @Column({ name: 'valid_from', type: 'datetime', nullable: true, default: null }) validFrom: Date | null diff --git a/database/migrations/0037-add_contribution_links_table.ts b/database/migrations/0037-add_contribution_links_table.ts index 42f03184b..bd56c7fee 100644 --- a/database/migrations/0037-add_contribution_links_table.ts +++ b/database/migrations/0037-add_contribution_links_table.ts @@ -11,7 +11,7 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis CREATE TABLE IF NOT EXISTS \`contribution_links\` ( \`id\` int(10) unsigned NOT NULL AUTO_INCREMENT, \`name\` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL, - \`decsription\` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, + \`memo\` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, \`valid_from\` datetime NULL, \`valid_to\` datetime NULL, \`amount\` bigint(20) NOT NULL, From f7935973ef6a364f680ec4ef04198d5e15baab0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Wed, 8 Jun 2022 03:21:59 +0200 Subject: [PATCH 02/25] CRUD Rights for ContributionLink --- backend/src/auth/RIGHTS.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/backend/src/auth/RIGHTS.ts b/backend/src/auth/RIGHTS.ts index 8188b3daa..c030a0451 100644 --- a/backend/src/auth/RIGHTS.ts +++ b/backend/src/auth/RIGHTS.ts @@ -37,4 +37,8 @@ export enum RIGHTS { UNDELETE_USER = 'UNDELETE_USER', CREATION_TRANSACTION_LIST = 'CREATION_TRANSACTION_LIST', LIST_TRANSACTION_LINKS_ADMIN = 'LIST_TRANSACTION_LINKS_ADMIN', + CONTRIBUTION_LINK_CREATE = 'CONTRIBUTION_LINK_CREATE', + CONTRIBUTION_LINK_READ = 'CONTRIBUTION_LINK_READ', + CONTRIBUTION_LINK_UPDATE = 'CONTRIBUTION_LINK_UPDATE', + CONTRIBUTION_LINK_DELETE = 'CONTRIBUTION_LINK_DELETE', } From 0817b54384669a6eb5ac30ca55b7168affc7cd17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Wed, 8 Jun 2022 03:22:35 +0200 Subject: [PATCH 03/25] Args object for create ContributionLink --- .../graphql/arg/CreateContributionLinkArgs.ts | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 backend/src/graphql/arg/CreateContributionLinkArgs.ts diff --git a/backend/src/graphql/arg/CreateContributionLinkArgs.ts b/backend/src/graphql/arg/CreateContributionLinkArgs.ts new file mode 100644 index 000000000..2e3da86b3 --- /dev/null +++ b/backend/src/graphql/arg/CreateContributionLinkArgs.ts @@ -0,0 +1,30 @@ +import { ArgsType, Field, InputType } from 'type-graphql' +import Decimal from 'decimal.js-light' + +@InputType() +@ArgsType() +export default class CreateContributionLinkArgs { + @Field(() => String) + startDate: string + + @Field(() => String) + endDate: string + + @Field(() => String) + name: string + + @Field(() => Decimal) + amount: Decimal + + @Field(() => String) + memo: string + + @Field(() => String) + cycle: string + + @Field(() => Int) + repetition: number + + @Field(() => Decimal) + maxAmount: Decimal +} From a32910a7666397d0805e227edd4c2e08d959a5d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Wed, 8 Jun 2022 03:24:55 +0200 Subject: [PATCH 04/25] Resolver with new method createContributionLink --- backend/src/graphql/resolver/AdminResolver.ts | 114 ++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index 4c94e48c8..9e7a3a031 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -39,12 +39,22 @@ import { Order } from '@enum/Order' import { communityUser } from '@/util/communityUser' import { checkOptInCode, activationLink, printTimeDuration } from './UserResolver' import { sendAccountActivationEmail } from '@/mailer/sendAccountActivationEmail' +import { ContributionLinks as dbContributionLinks } from '@entity/ContributionLinks' +import CreateContributionLinkArgs from '@arg/CreateContributionLinkArgs' +import { ContributionCycleType } from '@enum/ContributionCycleType' import CONFIG from '@/config' +import { backendLogger as logger } from '@/server/logger' +import _ from 'lodash' +import { randomBytes } from 'crypto' // const EMAIL_OPT_IN_REGISTER = 1 // const EMAIL_OPT_UNKNOWN = 3 // elopage? const MAX_CREATION_AMOUNT = new Decimal(1000) const FULL_CREATION_AVAILABLE = [MAX_CREATION_AMOUNT, MAX_CREATION_AMOUNT, MAX_CREATION_AMOUNT] +const CONTRIBUTIONLINK_NAME_MAX_CHARS = 100 +const CONTRIBUTIONLINK_NAME_MIN_CHARS = 5 +const CONTRIBUTIONLINK_MEMO_MAX_CHARS = 255 +const CONTRIBUTIONLINK_MEMO_MIN_CHARS = 5 @Resolver() export class AdminResolver { @@ -460,6 +470,77 @@ export class AdminResolver { linkList: transactionLinks.map((tl) => new TransactionLink(tl, new User(user))), } } + + @Authorized([RIGHTS.CONTRIBUTION_LINK_CREATE]) + @Mutation(() => dbContributionLinks) + async createContributionLink( + @Args() + { + startDate, + endDate, + name, + amount, + memo, + cycle, + repetition, + maxAmount, + }: CreateContributionLinkArgs, + @Ctx() context: Context, + ): Promise { + if (!isStartEndDateValid(startDate, endDate)) { + logger.error(`The startDate=${startDate} must be before or equals the endDate=${endDate}!`) + throw new Error(`The startDate=${startDate} must be before or equals the endDate=${endDate}!`) + } + if (name == null) { + logger.error(`The name must be initialized!`) + throw new Error(`The name must be initialized!`) + } + if ( + name.length < CONTRIBUTIONLINK_NAME_MIN_CHARS || + name.length > CONTRIBUTIONLINK_NAME_MAX_CHARS + ) { + const msg = `The name=${name} with a length of ${name.length} did not fulfill the requested bounderies min=${CONTRIBUTIONLINK_NAME_MIN_CHARS} and max=${CONTRIBUTIONLINK_NAME_MAX_CHARS}` + logger.error(`${msg}`) + throw new Error(`${msg}`) + } + if (amount == null) { + logger.error(`The amount must be initialized!`) + throw new Error('The amount must be initialized!') + } + const amountObj = new Decimal(amount) + const moderator = getUser(context) + const startDateObj = new Date(startDate) + const endDateObj = new Date(endDate) + if (amountObj.isZero || amountObj.isNegative()) { + logger.error(`The amount=${amount} must be initialized with a positiv value!`) + throw new Error(`The amount=${amount} must be initialized with a positiv value!`) + } + const contributionLink = dbContributionLinks.create() + contributionLink.amount = amount + contributionLink.code = contributionLinkCode(startDateObj) + contributionLink.createdAt = new Date() + contributionLink.cycle = cycle // ? cycle : ContributionCycleType.NONE + contributionLink.deletedAt = null + contributionLink.linkEnabled = true + /* not supported in the 1st expansion stage + contributionLink.maxAccountBalance = null + */ + contributionLink.maxAmountPerMonth = maxAmount + contributionLink.maxPerCycle = repetition + contributionLink.memo = memo + /* not supported in the 1st expansion stage + contributionLink.minGapHours = null + */ + contributionLink.name = name + /* not supported in the 1st expansion stage + contributionLink.totalMaxCountOfContribution = null + */ + contributionLink.validFrom = startDateObj + contributionLink.validTo = endDateObj + + await dbContributionLinks.save(contributionLink) + return dbContributionLinks.findOneOrFail(contributionLink.code) + } } interface CreationMap { @@ -541,6 +622,29 @@ function isCreationValid(creations: Decimal[], amount: Decimal, creationDate: Da return true } +function isStartEndDateValid(startDate: string, endDate: string) { + if (startDate == null && endDate == null) { + logger.error('Start- and End-Date are not initialized. At least a startDate must be set!') + throw new Error('Start- and End-Date are not initialized. At least a startDate must be set!') + } + + if (startDate == null) { + logger.error('StartDate is not initialized. At least a startDate must be set!') + throw new Error('Start-Date is not initialized. At least a startDate must be set!') + } + + if (startDate != null && endDate != null) { + const startDateObj = new Date(startDate) + const endDateObj = new Date(endDate) + + // check if endDate is before startDate + if (endDateObj.getTime() - startDateObj.getTime() < 0) { + return false + } + } + return true +} + const getCreationMonths = (): number[] => { const now = new Date(Date.now()) return [ @@ -553,3 +657,13 @@ const getCreationMonths = (): number[] => { const getCreationIndex = (month: number): number => { return getCreationMonths().findIndex((el) => el === month + 1) } + +const contributionLinkCode = (date: Date): string => { + const time = date.getTime().toString(16) + return ( + randomBytes(12) + .toString('hex') + .substring(0, 24 - time.length) + time + ) +} + From fd8444bc4047ab4349b754af3d7e22b3935ce093 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Thu, 9 Jun 2022 01:46:37 +0200 Subject: [PATCH 05/25] backend with correct db-version --- backend/src/config/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index ec469c183..df3e20648 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -10,7 +10,7 @@ Decimal.set({ }) const constants = { - DB_VERSION: '0037-add_contribution_links_table/ContributionLinks', + DB_VERSION: '0037-add_contribution_links_table', DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0 LOG4JS_CONFIG: 'log4js-config.json', // default log level on production should be info @@ -54,6 +54,7 @@ const community = { COMMUNITY_URL: process.env.COMMUNITY_URL || 'http://localhost/', COMMUNITY_REGISTER_URL: process.env.COMMUNITY_REGISTER_URL || 'http://localhost/register', COMMUNITY_REDEEM_URL: process.env.COMMUNITY_REDEEM_URL || 'http://localhost/redeem/{code}', + COMMUNITY_CONTRIBUTION_URL: process.env.COMMUNITY_CONTRIBUTION_URL || 'http://localhost/redeem/CL-{code}', COMMUNITY_DESCRIPTION: process.env.COMMUNITY_DESCRIPTION || 'Die lokale Entwicklungsumgebung von Gradido.', } From 77e266e389438d325964d4d5d571ee37c1f04dd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Thu, 9 Jun 2022 01:48:07 +0200 Subject: [PATCH 06/25] input and output types for creatingContributionLink --- .../graphql/arg/CreateContributionLinkArgs.ts | 2 +- backend/src/graphql/model/ContributionLink.ts | 78 +++++++++++++++++++ 2 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 backend/src/graphql/model/ContributionLink.ts diff --git a/backend/src/graphql/arg/CreateContributionLinkArgs.ts b/backend/src/graphql/arg/CreateContributionLinkArgs.ts index 2e3da86b3..3beda53e0 100644 --- a/backend/src/graphql/arg/CreateContributionLinkArgs.ts +++ b/backend/src/graphql/arg/CreateContributionLinkArgs.ts @@ -1,4 +1,4 @@ -import { ArgsType, Field, InputType } from 'type-graphql' +import { ArgsType, Field, Int, InputType } from 'type-graphql' import Decimal from 'decimal.js-light' @InputType() diff --git a/backend/src/graphql/model/ContributionLink.ts b/backend/src/graphql/model/ContributionLink.ts new file mode 100644 index 000000000..dd4b65aee --- /dev/null +++ b/backend/src/graphql/model/ContributionLink.ts @@ -0,0 +1,78 @@ +import { ObjectType, Field, Int } from 'type-graphql' +import Decimal from 'decimal.js-light' +import { ContributionLinks as dbContributionLinks } from '@entity/ContributionLinks' +import CONFIG from '@/config' + +@ObjectType() +export class ContributionLink { + constructor(contributionLink: dbContributionLinks) { + this.amount = contributionLink.amount + this.code = contributionLink.code + this.createdAt = contributionLink.createdAt + this.cycle = contributionLink.cycle + this.deletedAt = contributionLink.deletedAt + this.endDate = contributionLink.validTo + this.id = contributionLink.id + this.linkEnabled = contributionLink.linkEnabled + this.link = CONFIG.COMMUNITY_CONTRIBUTION_URL.replace(/{code}/g, contributionLink.code) + this.maxAccountBalance = contributionLink.maxAccountBalance + this.maxAmountPerMonth = contributionLink.maxAmountPerMonth + this.memo = contributionLink.memo + this.minGapHours = contributionLink.minGapHours + this.name = contributionLink.name + this.repetition = contributionLink.maxPerCycle + this.startDate = contributionLink.validFrom + this.totalMaxCountOfContribution = contributionLink.totalMaxCountOfContribution + } + + @Field(() => Decimal) + amount: Decimal + + @Field(() => String) + code: string + + @Field(() => Date, { nullable: true }) + createdAt: Date | null + + @Field(() => String) + cycle: string + + @Field(() => Date, { nullable: true }) + deletedAt: Date | null + + @Field(() => Date, { nullable: true }) + endDate: Date | null + + @Field(() => Int) + id?: number + + @Field(() => Boolean, { nullable: true }) + linkEnabled: boolean | null + + @Field(() => String) + link: string + + @Field(() => Decimal) + maxAccountBalance: Decimal + + @Field(() => Decimal) + maxAmountPerMonth: Decimal + + @Field(() => String) + memo: string + + @Field(() => Int, { nullable: true }) + minGapHours: number | null + + @Field(() => String) + name: string + + @Field(() => Int) + repetition: number + + @Field(() => Date, { nullable: true }) + startDate: Date | null + + @Field(() => Int, { nullable: true }) + totalMaxCountOfContribution: number | null +} From fadaaf85b084c8608ebc6128148fe66083775a1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Thu, 9 Jun 2022 01:48:27 +0200 Subject: [PATCH 07/25] new method createContributionLink --- backend/src/graphql/resolver/AdminResolver.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index 9e7a3a031..7b6ceb906 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -41,7 +41,7 @@ import { checkOptInCode, activationLink, printTimeDuration } from './UserResolve import { sendAccountActivationEmail } from '@/mailer/sendAccountActivationEmail' import { ContributionLinks as dbContributionLinks } from '@entity/ContributionLinks' import CreateContributionLinkArgs from '@arg/CreateContributionLinkArgs' -import { ContributionCycleType } from '@enum/ContributionCycleType' +import { ContributionLink } from '../model/ContributionLink' import CONFIG from '@/config' import { backendLogger as logger } from '@/server/logger' import _ from 'lodash' @@ -472,7 +472,7 @@ export class AdminResolver { } @Authorized([RIGHTS.CONTRIBUTION_LINK_CREATE]) - @Mutation(() => dbContributionLinks) + @Mutation(() => ContributionLink) async createContributionLink( @Args() { @@ -486,7 +486,10 @@ export class AdminResolver { maxAmount, }: CreateContributionLinkArgs, @Ctx() context: Context, - ): Promise { + ): Promise { + logger.trace( + `createContributionLink(startDate=${startDate}, endDate=${endDate}, name=${name}, amount=${amount}, memo=${memo}, cycle=${cycle}, repetition=${repetition}, maxAmount=${maxAmount})`, + ) if (!isStartEndDateValid(startDate, endDate)) { logger.error(`The startDate=${startDate} must be before or equals the endDate=${endDate}!`) throw new Error(`The startDate=${startDate} must be before or equals the endDate=${endDate}!`) @@ -539,7 +542,7 @@ export class AdminResolver { contributionLink.validTo = endDateObj await dbContributionLinks.save(contributionLink) - return dbContributionLinks.findOneOrFail(contributionLink.code) + return new ContributionLink(await dbContributionLinks.findOneOrFail(contributionLink.code)) } } From e769390868d430127697783cbd0579008773c01d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Thu, 9 Jun 2022 22:54:26 +0200 Subject: [PATCH 08/25] correct nullable columns vs nullable attributes --- backend/src/graphql/model/ContributionLink.ts | 20 +++++++++---------- .../0037-add_contribution_links_table.ts | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/backend/src/graphql/model/ContributionLink.ts b/backend/src/graphql/model/ContributionLink.ts index dd4b65aee..427def187 100644 --- a/backend/src/graphql/model/ContributionLink.ts +++ b/backend/src/graphql/model/ContributionLink.ts @@ -31,8 +31,8 @@ export class ContributionLink { @Field(() => String) code: string - @Field(() => Date, { nullable: true }) - createdAt: Date | null + @Field(() => Date) + createdAt: Date @Field(() => String) cycle: string @@ -46,17 +46,17 @@ export class ContributionLink { @Field(() => Int) id?: number - @Field(() => Boolean, { nullable: true }) - linkEnabled: boolean | null + @Field(() => Boolean) + linkEnabled: boolean @Field(() => String) link: string - @Field(() => Decimal) - maxAccountBalance: Decimal + @Field(() => Decimal, { nullable: true }) + maxAccountBalance: Decimal | null - @Field(() => Decimal) - maxAmountPerMonth: Decimal + @Field(() => Decimal, { nullable: true }) + maxAmountPerMonth: Decimal | null @Field(() => String) memo: string @@ -70,8 +70,8 @@ export class ContributionLink { @Field(() => Int) repetition: number - @Field(() => Date, { nullable: true }) - startDate: Date | null + @Field(() => Date) + startDate: Date @Field(() => Int, { nullable: true }) totalMaxCountOfContribution: number | null diff --git a/database/migrations/0037-add_contribution_links_table.ts b/database/migrations/0037-add_contribution_links_table.ts index 76956faa8..3ac6821d6 100644 --- a/database/migrations/0037-add_contribution_links_table.ts +++ b/database/migrations/0037-add_contribution_links_table.ts @@ -12,7 +12,7 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis \`id\` int(10) unsigned NOT NULL AUTO_INCREMENT, \`name\` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL, \`memo\` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL, - \`valid_from\` datetime NULL, + \`valid_from\` datetime NOT NULL, \`valid_to\` datetime NULL, \`amount\` bigint(20) NOT NULL, \`cycle\` varchar(12) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT 'ONCE', From f327aac5827d5d1170299445faa7377313af5a18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Fri, 10 Jun 2022 00:17:06 +0200 Subject: [PATCH 09/25] shift enum from ticket #1920 Merge remote-tracking branch 'origin/1920-feature-create-contribution-link-table' into 1921-feature-contribution-link-crud-in-admin-resolver --- .../src/graphql/enum/ContributionCycleType.ts | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 backend/src/graphql/enum/ContributionCycleType.ts diff --git a/backend/src/graphql/enum/ContributionCycleType.ts b/backend/src/graphql/enum/ContributionCycleType.ts new file mode 100644 index 000000000..5fe494a02 --- /dev/null +++ b/backend/src/graphql/enum/ContributionCycleType.ts @@ -0,0 +1,28 @@ +import { registerEnumType } from 'type-graphql' + +export enum ContributionCycleType { + ONCE = 'once', + HOUR = 'hour', + TWO_HOURS = 'two_hours', + FOUR_HOURS = 'four_hours', + EIGHT_HOURS = 'eight_hours', + HALF_DAY = 'half_day', + DAY = 'day', + TWO_DAYS = 'two_days', + THREE_DAYS = 'three_days', + FOUR_DAYS = 'four_days', + FIVE_DAYS = 'five_days', + SIX_DAYS = 'six_days', + WEEK = 'week', + TWO_WEEKS = 'two_weeks', + MONTH = 'month', + TWO_MONTH = 'two_month', + QUARTER = 'quarter', + HALF_YEAR = 'half_year', + YEAR = 'year', +} + +registerEnumType(ContributionCycleType, { + name: 'ContributionCycleType', // this one is mandatory + description: 'Name of the Type of the ContributionCycle', // this one is optional +}) From 786f03a2029f8a8b025edf126fe5bbacb4bc5d1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Mon, 13 Jun 2022 17:46:16 +0200 Subject: [PATCH 10/25] begin tests for createContributionLink --- .../graphql/arg/CreateContributionLinkArgs.ts | 13 +- backend/src/graphql/model/ContributionLink.ts | 8 +- .../graphql/resolver/AdminResolver.test.ts | 175 ++++++++++++++++++ backend/src/graphql/resolver/AdminResolver.ts | 7 +- database/entity/index.ts | 2 + 5 files changed, 190 insertions(+), 15 deletions(-) diff --git a/backend/src/graphql/arg/CreateContributionLinkArgs.ts b/backend/src/graphql/arg/CreateContributionLinkArgs.ts index 3beda53e0..1e7523ee4 100644 --- a/backend/src/graphql/arg/CreateContributionLinkArgs.ts +++ b/backend/src/graphql/arg/CreateContributionLinkArgs.ts @@ -1,5 +1,4 @@ import { ArgsType, Field, Int, InputType } from 'type-graphql' -import Decimal from 'decimal.js-light' @InputType() @ArgsType() @@ -13,8 +12,8 @@ export default class CreateContributionLinkArgs { @Field(() => String) name: string - @Field(() => Decimal) - amount: Decimal + @Field(() => String) + amount: string @Field(() => String) memo: string @@ -22,9 +21,9 @@ export default class CreateContributionLinkArgs { @Field(() => String) cycle: string - @Field(() => Int) - repetition: number + @Field(() => String) + repetition: string - @Field(() => Decimal) - maxAmount: Decimal + @Field(() => String) + maxAmount: string } diff --git a/backend/src/graphql/model/ContributionLink.ts b/backend/src/graphql/model/ContributionLink.ts index 427def187..dd772dbb5 100644 --- a/backend/src/graphql/model/ContributionLink.ts +++ b/backend/src/graphql/model/ContributionLink.ts @@ -28,8 +28,8 @@ export class ContributionLink { @Field(() => Decimal) amount: Decimal - @Field(() => String) - code: string + @Field(() => String, { nullable: true }) + code: string | null @Field(() => Date) createdAt: Date @@ -49,8 +49,8 @@ export class ContributionLink { @Field(() => Boolean) linkEnabled: boolean - @Field(() => String) - link: string + @Field(() => String, { nullable: true }) + link: string | null @Field(() => Decimal, { nullable: true }) maxAccountBalance: Decimal | null diff --git a/backend/src/graphql/resolver/AdminResolver.test.ts b/backend/src/graphql/resolver/AdminResolver.test.ts index acf880efb..a2c4c3b82 100644 --- a/backend/src/graphql/resolver/AdminResolver.test.ts +++ b/backend/src/graphql/resolver/AdminResolver.test.ts @@ -1328,6 +1328,181 @@ describe('AdminResolver', () => { }) }) }) + // Tests for creating ContributionLinks + describe('createContributionLink', () => { + beforeAll(async () => { + const now = new Date() + creation = await creationFactory(testEnv, { + startDate: new Date(2022, 6, 18).toISOString(), + endDate, + name, + amount, + memo, + cycle, + repetition, + maxAmount, + + email: 'peter@lustig.de', + amount: 400, + memo: 'Herzlich Willkommen bei Gradido!', + creationDate: new Date(now.getFullYear(), now.getMonth() - 1, 1).toISOString(), + }) + }) + + describe('user to create for does not exist', () => { + it('throws an error', async () => { + await expect( + mutate({ mutation: createContributionLink, variables }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('Could not find user with email: bibi@bloxberg.de')], + }), + ) + }) + }) + + describe('user to create for is deleted', () => { + beforeAll(async () => { + user = await userFactory(testEnv, stephenHawking) + variables.email = 'stephen@hawking.uk' + }) + + it('throws an error', async () => { + await expect(mutate({ mutation: createPendingCreation, variables })).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('This user was deleted. Cannot make a creation.')], + }), + ) + }) + }) + + describe('user to create for has email not confirmed', () => { + beforeAll(async () => { + user = await userFactory(testEnv, garrickOllivander) + variables.email = 'garrick@ollivander.com' + }) + + it('throws an error', async () => { + await expect(mutate({ mutation: createPendingCreation, variables })).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('Creation could not be saved, Email is not activated')], + }), + ) + }) + }) + + describe('valid user to create for', () => { + beforeAll(async () => { + user = await userFactory(testEnv, bibiBloxberg) + variables.email = 'bibi@bloxberg.de' + }) + + describe('date of creation is not a date string', () => { + it('throws an error', async () => { + await expect( + mutate({ mutation: createPendingCreation, variables }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [ + new GraphQLError('No information for available creations for the given date'), + ], + }), + ) + }) + }) + + describe('date of creation is four months ago', () => { + it('throws an error', async () => { + const now = new Date() + variables.creationDate = new Date( + now.getFullYear(), + now.getMonth() - 4, + 1, + ).toString() + await expect( + mutate({ mutation: createPendingCreation, variables }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [ + new GraphQLError('No information for available creations for the given date'), + ], + }), + ) + }) + }) + + describe('date of creation is in the future', () => { + it('throws an error', async () => { + const now = new Date() + variables.creationDate = new Date( + now.getFullYear(), + now.getMonth() + 4, + 1, + ).toString() + await expect( + mutate({ mutation: createPendingCreation, variables }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [ + new GraphQLError('No information for available creations for the given date'), + ], + }), + ) + }) + }) + + describe('amount of creation is too high', () => { + it('throws an error', async () => { + variables.creationDate = new Date().toString() + await expect( + mutate({ mutation: createPendingCreation, variables }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [ + new GraphQLError( + 'The amount (2000 GDD) to be created exceeds the amount (1000 GDD) still available for this month.', + ), + ], + }), + ) + }) + }) + + describe('creation is valid', () => { + it('returns an array of the open creations for the last three months', async () => { + variables.amount = new Decimal(200) + await expect( + mutate({ mutation: createPendingCreation, variables }), + ).resolves.toEqual( + expect.objectContaining({ + data: { + createPendingCreation: [1000, 1000, 800], + }, + }), + ) + }) + }) + + describe('second creation surpasses the available amount ', () => { + it('returns an array of the open creations for the last three months', async () => { + variables.amount = new Decimal(1000) + await expect( + mutate({ mutation: createPendingCreation, variables }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [ + new GraphQLError( + 'The amount (1000 GDD) to be created exceeds the amount (800 GDD) still available for this month.', + ), + ], + }), + ) + }) + }) + }) + }) + + }) }) }) diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index 7b6ceb906..829b9a705 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -519,7 +519,7 @@ export class AdminResolver { throw new Error(`The amount=${amount} must be initialized with a positiv value!`) } const contributionLink = dbContributionLinks.create() - contributionLink.amount = amount + contributionLink.amount = amountObj contributionLink.code = contributionLinkCode(startDateObj) contributionLink.createdAt = new Date() contributionLink.cycle = cycle // ? cycle : ContributionCycleType.NONE @@ -528,8 +528,8 @@ export class AdminResolver { /* not supported in the 1st expansion stage contributionLink.maxAccountBalance = null */ - contributionLink.maxAmountPerMonth = maxAmount - contributionLink.maxPerCycle = repetition + contributionLink.maxAmountPerMonth = null // maxAmount + contributionLink.maxPerCycle = Number(repetition) contributionLink.memo = memo /* not supported in the 1st expansion stage contributionLink.minGapHours = null @@ -669,4 +669,3 @@ const contributionLinkCode = (date: Date): string => { .substring(0, 24 - time.length) + time ) } - diff --git a/database/entity/index.ts b/database/entity/index.ts index 542333755..770fcdda7 100644 --- a/database/entity/index.ts +++ b/database/entity/index.ts @@ -6,9 +6,11 @@ import { TransactionLink } from './TransactionLink' import { User } from './User' import { UserSetting } from './UserSetting' import { AdminPendingCreation } from './AdminPendingCreation' +import { ContributionLinks } from './ContributionLinks' export const entities = [ AdminPendingCreation, + ContributionLinks, LoginElopageBuys, LoginEmailOptIn, Migration, From d3571fdf5f7d7257059c0357afb79426d0964e68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Mon, 13 Jun 2022 20:09:49 +0200 Subject: [PATCH 11/25] upgrade database version to 0038 --- .dbeaver/credentials-config.json | 5 ++--- .dbeaver/data-sources.json | 4 ++-- backend/src/config/index.ts | 3 ++- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.dbeaver/credentials-config.json b/.dbeaver/credentials-config.json index d814bdfcf..f56152022 100644 --- a/.dbeaver/credentials-config.json +++ b/.dbeaver/credentials-config.json @@ -1,3 +1,2 @@ -4k1,fbAqĬc##s8-1&;"7djM?bljfBq= -my -vV \ No newline at end of file +;5'm?v7y " ,8EY>'S:ƂR֒el#2 ++s7!`!X8|Zu(ӴAMx \ No newline at end of file diff --git a/.dbeaver/data-sources.json b/.dbeaver/data-sources.json index 096f0d57e..fe96e923d 100644 --- a/.dbeaver/data-sources.json +++ b/.dbeaver/data-sources.json @@ -1,10 +1,10 @@ { "folders": {}, "connections": { - "mariaDB-1813fbbc7bc-107c0b3aeaeb91ab": { + "mariaDB-1815e3cb8a7-3b4d7a27c954779d": { "provider": "mysql", "driver": "mariaDB", - "name": "gradido", + "name": "localhost", "save-password": true, "read-only": false, "configuration": { diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index 685e2659f..e325c6690 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -54,7 +54,8 @@ const community = { COMMUNITY_URL: process.env.COMMUNITY_URL || 'http://localhost/', COMMUNITY_REGISTER_URL: process.env.COMMUNITY_REGISTER_URL || 'http://localhost/register', COMMUNITY_REDEEM_URL: process.env.COMMUNITY_REDEEM_URL || 'http://localhost/redeem/{code}', - COMMUNITY_CONTRIBUTION_URL: process.env.COMMUNITY_CONTRIBUTION_URL || 'http://localhost/redeem/CL-{code}', + COMMUNITY_CONTRIBUTION_URL: + process.env.COMMUNITY_CONTRIBUTION_URL || 'http://localhost/redeem/CL-{code}', COMMUNITY_DESCRIPTION: process.env.COMMUNITY_DESCRIPTION || 'Die lokale Entwicklungsumgebung von Gradido.', } From 16b22c122e3bab2d5044fad85ace9a20fd0b7ad3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Mon, 13 Jun 2022 20:11:15 +0200 Subject: [PATCH 12/25] correct number columns and deletedAt column name --- .../0038-add_contribution_links_table/ContributionLinks.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/database/entity/0038-add_contribution_links_table/ContributionLinks.ts b/database/entity/0038-add_contribution_links_table/ContributionLinks.ts index 7b391606f..1e0995aa7 100644 --- a/database/entity/0038-add_contribution_links_table/ContributionLinks.ts +++ b/database/entity/0038-add_contribution_links_table/ContributionLinks.ts @@ -51,7 +51,7 @@ export class ContributionLinks extends BaseEntity { nullable: true, default: null, }) - totalMaxCountOfContribution: number | null + totalMaxCountOfContribution: number @Column({ name: 'max_account_balance', @@ -70,12 +70,12 @@ export class ContributionLinks extends BaseEntity { nullable: true, default: null, }) - minGapHours: number | null + minGapHours: number @Column({ name: 'created_at', type: 'datetime', default: () => 'CURRENT_TIMESTAMP' }) createdAt: Date - @DeleteDateColumn() + @DeleteDateColumn({ name: 'deleted_at', type: 'datetime', default: null }) deletedAt: Date | null @Column({ length: 24, nullable: true, collation: 'utf8mb4_unicode_ci' }) From 66a526e69c70a7b85d5caf3180214db3386b94f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Mon, 13 Jun 2022 20:34:32 +0200 Subject: [PATCH 13/25] remove "| null" behind the columns --- .../ContributionLinks.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/database/entity/0038-add_contribution_links_table/ContributionLinks.ts b/database/entity/0038-add_contribution_links_table/ContributionLinks.ts index 1e0995aa7..3cad65a01 100644 --- a/database/entity/0038-add_contribution_links_table/ContributionLinks.ts +++ b/database/entity/0038-add_contribution_links_table/ContributionLinks.ts @@ -17,7 +17,7 @@ export class ContributionLinks extends BaseEntity { validFrom: Date @Column({ name: 'valid_to', type: 'datetime', nullable: true, default: null }) - validTo: Date | null + validTo: Date @Column({ type: 'decimal', @@ -43,7 +43,7 @@ export class ContributionLinks extends BaseEntity { default: null, transformer: DecimalTransformer, }) - maxAmountPerMonth: Decimal | null + maxAmountPerMonth: Decimal @Column({ name: 'total_max_count_of_contribution', @@ -62,7 +62,7 @@ export class ContributionLinks extends BaseEntity { default: null, transformer: DecimalTransformer, }) - maxAccountBalance: Decimal | null + maxAccountBalance: Decimal @Column({ name: 'min_gap_hours', @@ -76,10 +76,10 @@ export class ContributionLinks extends BaseEntity { createdAt: Date @DeleteDateColumn({ name: 'deleted_at', type: 'datetime', default: null }) - deletedAt: Date | null + deletedAt: Date @Column({ length: 24, nullable: true, collation: 'utf8mb4_unicode_ci' }) - code: string | null + code: string @Column({ name: 'link_enabled', type: 'boolean', default: true }) linkEnabled: boolean From ccb69b2631ce955286bd1068cb43cee28308f89b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Tue, 14 Jun 2022 00:37:11 +0200 Subject: [PATCH 14/25] Tests for createContributionLink --- .dbeaver/credentials-config.json | 3 +- .dbeaver/data-sources.json | 21 +- backend/src/config/index.ts | 2 +- .../graphql/resolver/AdminResolver.test.ts | 220 +++++------------- backend/src/graphql/resolver/AdminResolver.ts | 6 +- 5 files changed, 77 insertions(+), 175 deletions(-) diff --git a/.dbeaver/credentials-config.json b/.dbeaver/credentials-config.json index f56152022..492e05f38 100644 --- a/.dbeaver/credentials-config.json +++ b/.dbeaver/credentials-config.json @@ -1,2 +1 @@ -;5'm?v7y " ,8EY>'S:ƂR֒el#2 -+s7!`!X8|Zu(ӴAMx \ No newline at end of file +&tfGNK=xnO$WZ;β-ZĊS̿d&ͺ1gt2 k-IrYC}#.؛?g(B \ No newline at end of file diff --git a/.dbeaver/data-sources.json b/.dbeaver/data-sources.json index fe96e923d..7e9676d89 100644 --- a/.dbeaver/data-sources.json +++ b/.dbeaver/data-sources.json @@ -13,8 +13,25 @@ "url": "jdbc:mariadb://localhost:3306/", "home": "mysql_client", "type": "dev", - "auth-model": "native", - "handlers": {} + "auth-model": "native" + }, + "custom-properties": { + "resultset.binary.representation": "base64" + } + } + }, + "virtual-models": { + "mariaDB-1815e3cb8a7-3b4d7a27c954779d": { + "gradido_community": { + ":users": { + "attributes": { + "public_key": { + "transforms": { + "custom": "resultset.binary.representation" + } + } + } + } } } }, diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index e325c6690..b4351599d 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -14,7 +14,7 @@ const constants = { DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0 LOG4JS_CONFIG: 'log4js-config.json', // default log level on production should be info - LOG_LEVEL: process.env.LOG_LEVEL || 'info', + LOG_LEVEL: process.env.LOG_LEVEL || 'debug', CONFIG_VERSION: { DEFAULT: 'DEFAULT', EXPECTED: 'v6.2022-04-21', diff --git a/backend/src/graphql/resolver/AdminResolver.test.ts b/backend/src/graphql/resolver/AdminResolver.test.ts index a2c4c3b82..fbfbfb65f 100644 --- a/backend/src/graphql/resolver/AdminResolver.test.ts +++ b/backend/src/graphql/resolver/AdminResolver.test.ts @@ -20,6 +20,7 @@ import { updatePendingCreation, deletePendingCreation, confirmPendingCreation, + createContributionLink, } from '@/seeds/graphql/mutations' import { getPendingCreations, @@ -34,6 +35,8 @@ import { sendAccountActivationEmail } from '@/mailer/sendAccountActivationEmail' import Decimal from 'decimal.js-light' import { AdminPendingCreation } from '@entity/AdminPendingCreation' import { Transaction as DbTransaction } from '@entity/Transaction' +// import { contributionFactory } from '@/seeds/factory/contribution' +// import CONFIG from '@/config' // mock account activation email to avoid console spam jest.mock('@/mailer/sendAccountActivationEmail', () => { @@ -496,6 +499,17 @@ describe('AdminResolver', () => { creationDate: 'not-valid', } + const contributionLinkVariables = { + startDate: '18.06.2022', + endDate: '30.09.2022', + name: 'Dokumenta 2022', + amount: '100,00', + memo: 'Startguthaben Dokumenta', + cycle: 'ONCE', + repetition: '1', + maxAmount: '500,00', + } + describe('unauthenticated', () => { describe('createPendingCreation', () => { it('returns an error', async () => { @@ -1330,179 +1344,51 @@ describe('AdminResolver', () => { }) // Tests for creating ContributionLinks describe('createContributionLink', () => { + /* beforeAll(async () => { const now = new Date() - creation = await creationFactory(testEnv, { - startDate: new Date(2022, 6, 18).toISOString(), - endDate, - name, - amount, - memo, - cycle, - repetition, - maxAmount, - - email: 'peter@lustig.de', - amount: 400, - memo: 'Herzlich Willkommen bei Gradido!', - creationDate: new Date(now.getFullYear(), now.getMonth() - 1, 1).toISOString(), + const contributionLink = await contributionFactory(testEnv, { + startDate: '18.06.2022', + endDate: '30.09.2022', + name: 'Dokumenta 2022', + amount: '100.00', + memo: 'Startguthaben Dokumenta', + cycle: 'once', + repetition: '1', + maxAmount: '500.00', }) }) - - describe('user to create for does not exist', () => { - it('throws an error', async () => { - await expect( - mutate({ mutation: createContributionLink, variables }), - ).resolves.toEqual( - expect.objectContaining({ - errors: [new GraphQLError('Could not find user with email: bibi@bloxberg.de')], - }), - ) - }) - }) - - describe('user to create for is deleted', () => { - beforeAll(async () => { - user = await userFactory(testEnv, stephenHawking) - variables.email = 'stephen@hawking.uk' - }) - - it('throws an error', async () => { - await expect(mutate({ mutation: createPendingCreation, variables })).resolves.toEqual( - expect.objectContaining({ - errors: [new GraphQLError('This user was deleted. Cannot make a creation.')], - }), - ) - }) - }) - - describe('user to create for has email not confirmed', () => { - beforeAll(async () => { - user = await userFactory(testEnv, garrickOllivander) - variables.email = 'garrick@ollivander.com' - }) - - it('throws an error', async () => { - await expect(mutate({ mutation: createPendingCreation, variables })).resolves.toEqual( - expect.objectContaining({ - errors: [new GraphQLError('Creation could not be saved, Email is not activated')], - }), - ) - }) - }) - - describe('valid user to create for', () => { - beforeAll(async () => { - user = await userFactory(testEnv, bibiBloxberg) - variables.email = 'bibi@bloxberg.de' - }) - - describe('date of creation is not a date string', () => { - it('throws an error', async () => { - await expect( - mutate({ mutation: createPendingCreation, variables }), - ).resolves.toEqual( - expect.objectContaining({ - errors: [ - new GraphQLError('No information for available creations for the given date'), - ], - }), - ) - }) - }) - - describe('date of creation is four months ago', () => { - it('throws an error', async () => { - const now = new Date() - variables.creationDate = new Date( - now.getFullYear(), - now.getMonth() - 4, - 1, - ).toString() - await expect( - mutate({ mutation: createPendingCreation, variables }), - ).resolves.toEqual( - expect.objectContaining({ - errors: [ - new GraphQLError('No information for available creations for the given date'), - ], - }), - ) - }) - }) - - describe('date of creation is in the future', () => { - it('throws an error', async () => { - const now = new Date() - variables.creationDate = new Date( - now.getFullYear(), - now.getMonth() + 4, - 1, - ).toString() - await expect( - mutate({ mutation: createPendingCreation, variables }), - ).resolves.toEqual( - expect.objectContaining({ - errors: [ - new GraphQLError('No information for available creations for the given date'), - ], - }), - ) - }) - }) - - describe('amount of creation is too high', () => { - it('throws an error', async () => { - variables.creationDate = new Date().toString() - await expect( - mutate({ mutation: createPendingCreation, variables }), - ).resolves.toEqual( - expect.objectContaining({ - errors: [ - new GraphQLError( - 'The amount (2000 GDD) to be created exceeds the amount (1000 GDD) still available for this month.', - ), - ], - }), - ) - }) - }) - - describe('creation is valid', () => { - it('returns an array of the open creations for the last three months', async () => { - variables.amount = new Decimal(200) - await expect( - mutate({ mutation: createPendingCreation, variables }), - ).resolves.toEqual( - expect.objectContaining({ - data: { - createPendingCreation: [1000, 1000, 800], - }, - }), - ) - }) - }) - - describe('second creation surpasses the available amount ', () => { - it('returns an array of the open creations for the last three months', async () => { - variables.amount = new Decimal(1000) - await expect( - mutate({ mutation: createPendingCreation, variables }), - ).resolves.toEqual( - expect.objectContaining({ - errors: [ - new GraphQLError( - 'The amount (1000 GDD) to be created exceeds the amount (800 GDD) still available for this month.', - ), - ], - }), - ) - }) - }) + */ + it('throws an error', async () => { + await expect( + mutate({ mutation: createContributionLink, contributionLinkVariables }), + ).resolves.toEqual( + expect.objectContaining({ + data: { + ContributionLink: { + amount: '100.00', + code: expect.any(String), + createdAt: expect.any(Date), + cycle: 'once', + deletedAt: null, + endDate: expect.any(Date), + id: expect.any(Number), + linkEnabled: true, + link: expect.stringMatching('http://localhost/redeem/CL-'), + maxAccountBalance: null, + maxAmountPerMonth: null, + memo: 'Startguthaben Dokumenta', + minGapHours: null, + name: 'Dokumenta 2022', + repetition: 1, + startDate: expect.any(Date), + totalMaxCountOfContribution: null, + }, + }, + }), + ) }) }) - - }) }) }) diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index 829b9a705..1f9ecbaa6 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -487,7 +487,7 @@ export class AdminResolver { }: CreateContributionLinkArgs, @Ctx() context: Context, ): Promise { - logger.trace( + logger.debug( `createContributionLink(startDate=${startDate}, endDate=${endDate}, name=${name}, amount=${amount}, memo=${memo}, cycle=${cycle}, repetition=${repetition}, maxAmount=${maxAmount})`, ) if (!isStartEndDateValid(startDate, endDate)) { @@ -523,12 +523,12 @@ export class AdminResolver { contributionLink.code = contributionLinkCode(startDateObj) contributionLink.createdAt = new Date() contributionLink.cycle = cycle // ? cycle : ContributionCycleType.NONE - contributionLink.deletedAt = null + // contributionLink.deletedAt = null contributionLink.linkEnabled = true /* not supported in the 1st expansion stage contributionLink.maxAccountBalance = null */ - contributionLink.maxAmountPerMonth = null // maxAmount + // contributionLink.maxAmountPerMonth = null // maxAmount contributionLink.maxPerCycle = Number(repetition) contributionLink.memo = memo /* not supported in the 1st expansion stage From 0ce0e9b2d71e787979146a3b8769f4b1283a2f19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Tue, 14 Jun 2022 01:43:10 +0200 Subject: [PATCH 15/25] extensions to test contributionLink more detailed --- .../seeds/creation/ContributionInterface.ts | 10 ++++ backend/src/seeds/factory/contribution.ts | 59 +++++++++++++++++++ backend/src/seeds/graphql/mutations.ts | 10 ++++ 3 files changed, 79 insertions(+) create mode 100644 backend/src/seeds/creation/ContributionInterface.ts create mode 100644 backend/src/seeds/factory/contribution.ts diff --git a/backend/src/seeds/creation/ContributionInterface.ts b/backend/src/seeds/creation/ContributionInterface.ts new file mode 100644 index 000000000..34ac6be0e --- /dev/null +++ b/backend/src/seeds/creation/ContributionInterface.ts @@ -0,0 +1,10 @@ +export interface ContributionInterface { + startDate: string + endDate: string + name: string + amount: string + memo: string + cycle: string + repetition: string + maxAmount: string +} diff --git a/backend/src/seeds/factory/contribution.ts b/backend/src/seeds/factory/contribution.ts new file mode 100644 index 000000000..63327a971 --- /dev/null +++ b/backend/src/seeds/factory/contribution.ts @@ -0,0 +1,59 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ + +import { createContributionLink } from '@/seeds/graphql/mutations' +// import { User } from '@entity/User' +import { login } from '@/seeds/graphql/queries' +import { ContributionInterface } from '@/seeds/creation/ContributionInterface' +import { ApolloServerTestClient } from 'apollo-server-testing' +import { ContributionLink } from '@/graphql/model/ContributionLink' +// import { ContributionLinks } from '@entity/ContributionLinks' + +// import CONFIG from '@/config/index' + +export const nMonthsBefore = (date: Date, months = 1): string => { + return new Date(date.getFullYear(), date.getMonth() - months, 1).toISOString() +} + +export const contributionFactory = async ( + client: ApolloServerTestClient, + contribution: ContributionInterface, +): Promise => { + const { mutate, query } = client + + await query({ query: login, variables: { email: 'peter@lustig.de', password: 'Aa12345_' } }) + + // let contributionLink: ContributionLink + // TODO it would be nice to have this mutation return the id + const contributionLink = await mutate({ + mutation: createContributionLink, + variables: { ...contribution }, + }) + + // const user = await User.findOneOrFail({ where: { email: creation.email } }) + + /* + if (contribution.linkEnabled) { + await mutate({ mutation: confirmPendingCreation, variables: { id: pendingCreation.id } }) + + if (creation.moveCreationDate) { + const transaction = await Transaction.findOneOrFail({ + where: { userId: user.id, creationDate: new Date(creation.creationDate) }, + order: { balanceDate: 'DESC' }, + }) + if (transaction.decay.equals(0) && transaction.creationDate) { + transaction.creationDate = new Date( + nMonthsBefore(transaction.creationDate, creation.moveCreationDate), + ) + transaction.balanceDate = new Date( + nMonthsBefore(transaction.balanceDate, creation.moveCreationDate), + ) + await transaction.save() + } + } + } else { + return pendingCreation + } + */ + return contributionLink +} diff --git a/backend/src/seeds/graphql/mutations.ts b/backend/src/seeds/graphql/mutations.ts index e66827566..02d20ee2a 100644 --- a/backend/src/seeds/graphql/mutations.ts +++ b/backend/src/seeds/graphql/mutations.ts @@ -137,3 +137,13 @@ export const deletePendingCreation = gql` deletePendingCreation(id: $id) } ` + +export const createContributionLink = gql` + mutation ($pendingCreations: [CreateContributionLinkArgs!]!) { + createContributionLink(pendingCreations: $pendingCreations) { + success + successfulCreation + failedCreation + } + } +` From b9c48d87608edbcb4be140eaef0b408ac4a7ad73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Wed, 15 Jun 2022 23:09:32 +0200 Subject: [PATCH 16/25] ignore .dbeaver --- .dbeaver/credentials-config.json | 4 +--- .dbeaver/data-sources.json | 4 ++-- .gitignore | 2 ++ 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.dbeaver/credentials-config.json b/.dbeaver/credentials-config.json index d814bdfcf..2b7661ad9 100644 --- a/.dbeaver/credentials-config.json +++ b/.dbeaver/credentials-config.json @@ -1,3 +1 @@ -4k1,fbAqĬc##s8-1&;"7djM?bljfBq= -my -vV \ No newline at end of file + ' jd=ǯ"RYqs锿WS}ťQ.QôgaV6bZ9.ϻ3%H33ge` \ No newline at end of file diff --git a/.dbeaver/data-sources.json b/.dbeaver/data-sources.json index 096f0d57e..8fe7dafb8 100644 --- a/.dbeaver/data-sources.json +++ b/.dbeaver/data-sources.json @@ -1,10 +1,10 @@ { "folders": {}, "connections": { - "mariaDB-1813fbbc7bc-107c0b3aeaeb91ab": { + "mariaDB-181692a0054-5276c99900718d4f": { "provider": "mysql", "driver": "mariaDB", - "name": "gradido", + "name": "localhost", "save-password": true, "read-only": false, "configuration": { diff --git a/.gitignore b/.gitignore index ced6746aa..f1a8e9157 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +/.dbeaver/* +.project *.log *.bak /node_modules/* From a73ff0aadf3cea6e99cb37ef283f051ad422c604 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Thu, 16 Jun 2022 00:32:30 +0200 Subject: [PATCH 17/25] correct check amount lte zero --- 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 f2b369d68..f8769f35d 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -518,7 +518,7 @@ export class AdminResolver { throw new Error('The amount must be initialized!') } const amountObj = new Decimal(amount) - if (amountObj.isZero || amountObj.isNegative()) { + if (amountObj.lessThanOrEqualTo(new Decimal(0))) { logger.error(`The amount=${amount} must be initialized with a positiv value!`) throw new Error(`The amount=${amount} must be initialized with a positiv value!`) } From 9947fff2568b5c3ea9a0bb0c0fe3d88e1852557a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Thu, 16 Jun 2022 00:51:23 +0200 Subject: [PATCH 18/25] change expected version --- database/src/config/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database/src/config/index.ts b/database/src/config/index.ts index ba41f11d4..d8cd78eae 100644 --- a/database/src/config/index.ts +++ b/database/src/config/index.ts @@ -6,7 +6,7 @@ dotenv.config() const constants = { CONFIG_VERSION: { DEFAULT: 'DEFAULT', - EXPECTED: 'v1.2022-03-18', + EXPECTED: 'v7.2022-06-15', CURRENT: '', }, } From 0edd295dbb8bc8033ba3fcad9d08ce77235a9101 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Mon, 20 Jun 2022 23:47:41 +0200 Subject: [PATCH 19/25] rework PR-Comments --- backend/src/graphql/resolver/AdminResolver.ts | 34 +++++++++---------- 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index 95412002d..3cb6cb9f6 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -527,7 +527,7 @@ export class AdminResolver { logger.error(`The validFrom=${validFrom} must be before or equals the validTo=${validTo}!`) throw new Error(`The validFrom=${validFrom} must be before or equals the validTo=${validTo}!`) } - if (name == null) { + if (!name) { logger.error(`The name must be initialized!`) throw new Error(`The name must be initialized!`) } @@ -539,6 +539,10 @@ export class AdminResolver { logger.error(`${msg}`) throw new Error(`${msg}`) } + if (!memo) { + logger.error(`The memo must be initialized!`) + throw new Error(`The memo must be initialized!`) + } if ( memo.length < CONTRIBUTIONLINK_MEMO_MIN_CHARS || memo.length > CONTRIBUTIONLINK_MEMO_MAX_CHARS @@ -547,12 +551,11 @@ export class AdminResolver { logger.error(`${msg}`) throw new Error(`${msg}`) } - if (amount == null) { + if (!amount) { logger.error(`The amount must be initialized!`) throw new Error('The amount must be initialized!') } - const amountObj = new Decimal(amount) - if (amountObj.lessThanOrEqualTo(new Decimal(0))) { + if (!new Decimal(amount).isPositive()) { logger.error(`The amount=${amount} must be initialized with a positiv value!`) throw new Error(`The amount=${amount} must be initialized with a positiv value!`) } @@ -736,24 +739,19 @@ function isStartEndDateValid( startDate: string | null | undefined, endDate: string | null | undefined, ) { - if (startDate == null && endDate == null) { - logger.error('Start- and End-Date are not initialized. At least a startDate must be set!') - throw new Error('Start- and End-Date are not initialized. At least a startDate must be set!') + if (!startDate) { + logger.error('Start-Date is not initialized. A Start-Date must be set!') + throw new Error('Start-Date is not initialized. A Start-Date must be set!') } - if (startDate == null) { - logger.error('StartDate is not initialized. At least a startDate must be set!') - throw new Error('Start-Date is not initialized. At least a startDate must be set!') + if (!endDate) { + logger.error('End-Date is not initialized. An End-Date must be set!') + throw new Error('End-Date is not initialized. An End-Date must be set!') } - if (startDate != null && endDate != null) { - const startDateObj = new Date(startDate) - const endDateObj = new Date(endDate) - - // check if endDate is before startDate - if (endDateObj.getTime() - startDateObj.getTime() < 0) { - return false - } + // check if endDate is before startDate + if (new Date(endDate).getTime() - new Date(startDate).getTime() < 0) { + return false } return true } From 56baf51ccdc2779ded71e6652c91b3581aacafe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Mon, 20 Jun 2022 23:50:21 +0200 Subject: [PATCH 20/25] add Tests for parameter checks of createContributionLink --- .../graphql/resolver/AdminResolver.test.ts | 205 ++++++++++++++++++ 1 file changed, 205 insertions(+) diff --git a/backend/src/graphql/resolver/AdminResolver.test.ts b/backend/src/graphql/resolver/AdminResolver.test.ts index 2a973f1e8..eb1edf978 100644 --- a/backend/src/graphql/resolver/AdminResolver.test.ts +++ b/backend/src/graphql/resolver/AdminResolver.test.ts @@ -1809,6 +1809,211 @@ describe('AdminResolver', () => { }) }) + describe('createContributionLink', () => { + it('returns an error if missing startDate', async () => { + await expect( + mutate({ + mutation: createContributionLink, + variables: { + ...variables, + validFrom: null, + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [ + new GraphQLError('Start-Date is not initialized. A Start-Date must be set!'), + ], + }), + ) + }) + }) + + describe('createContributionLink', () => { + it('returns an error if missing endDate', async () => { + await expect( + mutate({ + mutation: createContributionLink, + variables: { + ...variables, + validTo: null, + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('End-Date is not initialized. An End-Date must be set!')], + }), + ) + }) + }) + + describe('createContributionLink', () => { + it('returns an error if endDate is before startDate', async () => { + await expect( + mutate({ + mutation: createContributionLink, + variables: { + ...variables, + validFrom: new Date('2022-06-18T00:00:00.001Z').toISOString(), + validTo: new Date('2022-06-18T00:00:00.000Z').toISOString(), + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [ + new GraphQLError( + `The validFrom=2022-06-18T00:00:00.001Z must be before or equals the validTo=2022-06-18T00:00:00.000Z!`, + ), + ], + }), + ) + }) + }) + + describe('createContributionLink', () => { + it('returns an error if name is an empty string', async () => { + await expect( + mutate({ + mutation: createContributionLink, + variables: { + ...variables, + name: '', + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('The name must be initialized!')], + }), + ) + }) + }) + + describe('createContributionLink', () => { + it('returns an error if name is shorter than 5 characters', async () => { + await expect( + mutate({ + mutation: createContributionLink, + variables: { + ...variables, + name: '123', + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [ + new GraphQLError( + 'The name=123 with a length of 3 did not fulfill the requested bounderies min=5 and max=100', + ), + ], + }), + ) + }) + }) + + describe('createContributionLink', () => { + it('returns an error if name is longer than 100 characters', async () => { + await expect( + mutate({ + mutation: createContributionLink, + variables: { + ...variables, + name: '12345678901234567892123456789312345678941234567895123456789612345678971234567898123456789912345678901', + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [ + new GraphQLError( + 'The name=12345678901234567892123456789312345678941234567895123456789612345678971234567898123456789912345678901 with a length of 101 did not fulfill the requested bounderies min=5 and max=100', + ), + ], + }), + ) + }) + }) + + describe('createContributionLink', () => { + it('returns an error if memo is an empty string', async () => { + await expect( + mutate({ + mutation: createContributionLink, + variables: { + ...variables, + memo: '', + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('The memo must be initialized!')], + }), + ) + }) + }) + + describe('createContributionLink', () => { + it('returns an error if memo is shorter than 5 characters', async () => { + await expect( + mutate({ + mutation: createContributionLink, + variables: { + ...variables, + memo: '123', + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [ + new GraphQLError( + 'The memo=123 with a length of 3 did not fulfill the requested bounderies min=5 and max=255', + ), + ], + }), + ) + }) + }) + + describe('createContributionLink', () => { + it('returns an error if memo is longer than 255 characters', async () => { + await expect( + mutate({ + mutation: createContributionLink, + variables: { + ...variables, + memo: '1234567890123456789212345678931234567894123456789512345678961234567897123456789812345678991234567890123456789012345678921234567893123456789412345678951234567896123456789712345678981234567899123456789012345678901234567892123456789312345678941234567895123456', + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [ + new GraphQLError( + 'The memo=1234567890123456789212345678931234567894123456789512345678961234567897123456789812345678991234567890123456789012345678921234567893123456789412345678951234567896123456789712345678981234567899123456789012345678901234567892123456789312345678941234567895123456 with a length of 256 did not fulfill the requested bounderies min=5 and max=255', + ), + ], + }), + ) + }) + }) + + describe('createContributionLink', () => { + it('returns an error if amount is not positive', async () => { + await expect( + mutate({ + mutation: createContributionLink, + variables: { + ...variables, + amount: new Decimal(0), + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [ + new GraphQLError('The amount=0 must be initialized with a positiv value!'), + ], + }), + ) + }) + }) + describe('listContributionLinks', () => { describe('one link in DB', () => { it('returns the link and count 1', async () => { From 59ef2ea5d8cc93461e023a45216ed7bb28c579f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Tue, 21 Jun 2022 00:01:02 +0200 Subject: [PATCH 21/25] next try to remove .dbeaver from repo --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index f1a8e9157..1a111760f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -/.dbeaver/* +.dbeaver .project *.log *.bak From 47772a37b207d0ef30331a90bed9b38877df38b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Thu, 23 Jun 2022 02:42:20 +0200 Subject: [PATCH 22/25] rework PR-comments --- .../graphql/resolver/AdminResolver.test.ts | 32 +++---------------- backend/src/graphql/resolver/AdminResolver.ts | 26 ++++----------- 2 files changed, 12 insertions(+), 46 deletions(-) diff --git a/backend/src/graphql/resolver/AdminResolver.test.ts b/backend/src/graphql/resolver/AdminResolver.test.ts index eb1edf978..2dd9b837f 100644 --- a/backend/src/graphql/resolver/AdminResolver.test.ts +++ b/backend/src/graphql/resolver/AdminResolver.test.ts @@ -1807,9 +1807,7 @@ describe('AdminResolver', () => { }), ) }) - }) - describe('createContributionLink', () => { it('returns an error if missing startDate', async () => { await expect( mutate({ @@ -1827,9 +1825,7 @@ describe('AdminResolver', () => { }), ) }) - }) - describe('createContributionLink', () => { it('returns an error if missing endDate', async () => { await expect( mutate({ @@ -1845,9 +1841,7 @@ describe('AdminResolver', () => { }), ) }) - }) - describe('createContributionLink', () => { it('returns an error if endDate is before startDate', async () => { await expect( mutate({ @@ -1861,16 +1855,12 @@ describe('AdminResolver', () => { ).resolves.toEqual( expect.objectContaining({ errors: [ - new GraphQLError( - `The validFrom=2022-06-18T00:00:00.001Z must be before or equals the validTo=2022-06-18T00:00:00.000Z!`, - ), + new GraphQLError(`The value of validFrom must before or equals the validTo!`), ], }), ) }) - }) - describe('createContributionLink', () => { it('returns an error if name is an empty string', async () => { await expect( mutate({ @@ -1886,9 +1876,7 @@ describe('AdminResolver', () => { }), ) }) - }) - describe('createContributionLink', () => { it('returns an error if name is shorter than 5 characters', async () => { await expect( mutate({ @@ -1902,15 +1890,13 @@ describe('AdminResolver', () => { expect.objectContaining({ errors: [ new GraphQLError( - 'The name=123 with a length of 3 did not fulfill the requested bounderies min=5 and max=100', + `The value of 'name' with a length of 3 did not fulfill the requested bounderies min=5 and max=100`, ), ], }), ) }) - }) - describe('createContributionLink', () => { it('returns an error if name is longer than 100 characters', async () => { await expect( mutate({ @@ -1924,15 +1910,13 @@ describe('AdminResolver', () => { expect.objectContaining({ errors: [ new GraphQLError( - 'The name=12345678901234567892123456789312345678941234567895123456789612345678971234567898123456789912345678901 with a length of 101 did not fulfill the requested bounderies min=5 and max=100', + `The value of 'name' with a length of 101 did not fulfill the requested bounderies min=5 and max=100`, ), ], }), ) }) - }) - describe('createContributionLink', () => { it('returns an error if memo is an empty string', async () => { await expect( mutate({ @@ -1948,9 +1932,7 @@ describe('AdminResolver', () => { }), ) }) - }) - describe('createContributionLink', () => { it('returns an error if memo is shorter than 5 characters', async () => { await expect( mutate({ @@ -1964,15 +1946,13 @@ describe('AdminResolver', () => { expect.objectContaining({ errors: [ new GraphQLError( - 'The memo=123 with a length of 3 did not fulfill the requested bounderies min=5 and max=255', + `The value of 'memo' with a length of 3 did not fulfill the requested bounderies min=5 and max=255`, ), ], }), ) }) - }) - describe('createContributionLink', () => { it('returns an error if memo is longer than 255 characters', async () => { await expect( mutate({ @@ -1986,15 +1966,13 @@ describe('AdminResolver', () => { expect.objectContaining({ errors: [ new GraphQLError( - 'The memo=1234567890123456789212345678931234567894123456789512345678961234567897123456789812345678991234567890123456789012345678921234567893123456789412345678951234567896123456789712345678981234567899123456789012345678901234567892123456789312345678941234567895123456 with a length of 256 did not fulfill the requested bounderies min=5 and max=255', + `The value of 'memo' with a length of 256 did not fulfill the requested bounderies min=5 and max=255`, ), ], }), ) }) - }) - describe('createContributionLink', () => { it('returns an error if amount is not positive', async () => { await expect( mutate({ diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index 3cb6cb9f6..dca35ebaf 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -179,7 +179,6 @@ export class AdminResolver { @Args() { email, amount, memo, creationDate }: AdminCreateContributionArgs, @Ctx() context: Context, ): Promise { - logger.trace('adminCreateContribution...') const user = await dbUser.findOne({ email }, { withDeleted: true }) if (!user) { throw new Error(`Could not find user with email: ${email}`) @@ -520,13 +519,7 @@ export class AdminResolver { maxPerCycle, }: ContributionLinkArgs, ): Promise { - logger.debug( - `createContributionLink(validFrom=${validFrom}, validTo=${validTo}, name=${name}, amount=${amount}, memo=${memo}, cycle=${cycle}, maxPerCycle=${maxPerCycle}, maxAmountPerMonth=${maxAmountPerMonth})...`, - ) - if (!isStartEndDateValid(validFrom, validTo)) { - logger.error(`The validFrom=${validFrom} must be before or equals the validTo=${validTo}!`) - throw new Error(`The validFrom=${validFrom} must be before or equals the validTo=${validTo}!`) - } + isStartEndDateValid(validFrom, validTo) if (!name) { logger.error(`The name must be initialized!`) throw new Error(`The name must be initialized!`) @@ -535,7 +528,7 @@ export class AdminResolver { name.length < CONTRIBUTIONLINK_NAME_MIN_CHARS || name.length > CONTRIBUTIONLINK_NAME_MAX_CHARS ) { - const msg = `The name=${name} with a length of ${name.length} did not fulfill the requested bounderies min=${CONTRIBUTIONLINK_NAME_MIN_CHARS} and max=${CONTRIBUTIONLINK_NAME_MAX_CHARS}` + const msg = `The value of 'name' with a length of ${name.length} did not fulfill the requested bounderies min=${CONTRIBUTIONLINK_NAME_MIN_CHARS} and max=${CONTRIBUTIONLINK_NAME_MAX_CHARS}` logger.error(`${msg}`) throw new Error(`${msg}`) } @@ -547,7 +540,7 @@ export class AdminResolver { memo.length < CONTRIBUTIONLINK_MEMO_MIN_CHARS || memo.length > CONTRIBUTIONLINK_MEMO_MAX_CHARS ) { - const msg = `The memo=${memo} with a length of ${memo.length} did not fulfill the requested bounderies min=${CONTRIBUTIONLINK_MEMO_MIN_CHARS} and max=${CONTRIBUTIONLINK_MEMO_MAX_CHARS}` + const msg = `The value of 'memo' with a length of ${memo.length} did not fulfill the requested bounderies min=${CONTRIBUTIONLINK_MEMO_MIN_CHARS} and max=${CONTRIBUTIONLINK_MEMO_MAX_CHARS}` logger.error(`${msg}`) throw new Error(`${msg}`) } @@ -581,7 +574,6 @@ export class AdminResolver { @Args() { currentPage = 1, pageSize = 5, order = Order.DESC }: Paginated, ): Promise { - logger.debug('listContributionLinks()...') const [links, count] = await DbContributionLink.findAndCount({ order: { createdAt: order }, skip: (currentPage - 1) * pageSize, @@ -596,7 +588,6 @@ export class AdminResolver { @Authorized([RIGHTS.DELETE_CONTRIBUTION_LINK]) @Mutation(() => Date, { nullable: true }) async deleteContributionLink(@Arg('id', () => Int) id: number): Promise { - logger.debug(`deleteContributionLink(id=${id})`) const contributionLink = await DbContributionLink.findOne(id) if (!contributionLink) { logger.error(`Contribution Link not found to given id: ${id}`) @@ -624,9 +615,6 @@ export class AdminResolver { }: ContributionLinkArgs, @Arg('id', () => Int) id: number, ): Promise { - logger.debug( - `updateContributionLink(id=${id}, amount=${amount}, name=${name}, memo=${memo}, cycle=${cycle}, validFrom=${validFrom}, validTo=${validTo}, maxAmountPerMonth=${maxAmountPerMonth}, maxPerCycle=${maxPerCycle})...`, - ) const dbContributionLink = await DbContributionLink.findOne(id) if (!dbContributionLink) { logger.error(`Contribution Link not found to given id: ${id}`) @@ -735,10 +723,10 @@ export const isContributionValid = ( return true } -function isStartEndDateValid( +const isStartEndDateValid = ( startDate: string | null | undefined, endDate: string | null | undefined, -) { +): void => { if (!startDate) { logger.error('Start-Date is not initialized. A Start-Date must be set!') throw new Error('Start-Date is not initialized. A Start-Date must be set!') @@ -751,9 +739,9 @@ function isStartEndDateValid( // check if endDate is before startDate if (new Date(endDate).getTime() - new Date(startDate).getTime() < 0) { - return false + logger.error(`The value of validFrom must before or equals the validTo!`) + throw new Error(`The value of validFrom must before or equals the validTo!`) } - return true } const getCreationMonths = (): number[] => { From e2149a6ce4bccfa140cf3063f9f2c26e449ff913 Mon Sep 17 00:00:00 2001 From: clauspeterhuebner <86960882+clauspeterhuebner@users.noreply.github.com> Date: Thu, 23 Jun 2022 02:49:16 +0200 Subject: [PATCH 23/25] Delete .dbeaver directory --- .dbeaver/.credentials-config.json.bak | 1 - .dbeaver/.data-sources.json.bak | 55 --------------------------- .dbeaver/credentials-config.json | 0 .dbeaver/data-sources.json | 55 --------------------------- 4 files changed, 111 deletions(-) delete mode 100644 .dbeaver/.credentials-config.json.bak delete mode 100644 .dbeaver/.data-sources.json.bak delete mode 100644 .dbeaver/credentials-config.json delete mode 100644 .dbeaver/data-sources.json diff --git a/.dbeaver/.credentials-config.json.bak b/.dbeaver/.credentials-config.json.bak deleted file mode 100644 index 254ff7949..000000000 --- a/.dbeaver/.credentials-config.json.bak +++ /dev/null @@ -1 +0,0 @@ -l"a`ù& YOl>uAWTL`4)4$;?'RX+!a"X[(0"l hq[؂,C) \ No newline at end of file diff --git a/.dbeaver/.data-sources.json.bak b/.dbeaver/.data-sources.json.bak deleted file mode 100644 index cd5d6163f..000000000 --- a/.dbeaver/.data-sources.json.bak +++ /dev/null @@ -1,55 +0,0 @@ -{ - "folders": {}, - "connections": { - "mariaDB-180637bab9c-385a8c5454123150": { - "provider": "mysql", - "driver": "mariaDB", - "name": "gradido_community", - "save-password": true, - "read-only": false, - "configuration": { - "host": "localhost", - "port": "3306", - "database": "gradido_community", - "url": "jdbc:mariadb://localhost:3306/gradido_community", - "home": "mysql_client", - "type": "dev", - "auth-model": "native" - }, - "custom-properties": { - "resultset.binary.representation": "hex" - } - } - }, - "virtual-models": { - "mariaDB-180637bab9c-385a8c5454123150": { - "gradido_community": { - ":users": { - "properties": { - "erd.diagram.state": { - "serialized": "" - } - }, - "attributes": { - "public_key": { - "transforms": { - "custom": "resultset.binary.representation" - } - } - } - } - } - } - }, - "connection-types": { - "dev": { - "name": "Development", - "color": "255,255,255", - "description": "Regular development database", - "auto-commit": true, - "confirm-execute": false, - "confirm-data-change": false, - "auto-close-transactions": false - } - } -} \ No newline at end of file diff --git a/.dbeaver/credentials-config.json b/.dbeaver/credentials-config.json deleted file mode 100644 index e69de29bb..000000000 diff --git a/.dbeaver/data-sources.json b/.dbeaver/data-sources.json deleted file mode 100644 index e0ca3441f..000000000 --- a/.dbeaver/data-sources.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "folders": {}, - "connections": { - "mariaDB-180637bab9c-385a8c5454123150": { - "provider": "mysql", - "driver": "mariaDB", - "name": "gradido_community", - "save-password": true, - "read-only": false, - "configuration": { - "host": "localhost", - "port": "3306", - "database": "gradido_community", - "url": "jdbc:mariadb://localhost:3306/gradido_community", - "home": "mysql_client", - "type": "dev", - "auth-model": "native" - }, - "custom-properties": { - "resultset.binary.representation": "hex" - } - } - }, - "virtual-models": { - "mariaDB-180637bab9c-385a8c5454123150": { - "gradido_community": { - ":users": { - "properties": { - "erd.diagram.state": { - "serialized": "" - } - }, - "attributes": { - "public_key": { - "transforms": { - "custom": "resultset.binary.representation" - } - } - } - } - } - } - }, - "connection-types": { - "dev": { - "name": "Development", - "color": "255,255,255", - "description": "Regular development database", - "auto-commit": true, - "confirm-execute": false, - "confirm-data-change": false, - "auto-close-transactions": false - } - } -} \ No newline at end of file From a675364ba0ee0a0bf0bdc4595f810b03188fcb1d Mon Sep 17 00:00:00 2001 From: clauspeterhuebner <86960882+clauspeterhuebner@users.noreply.github.com> Date: Thu, 23 Jun 2022 02:50:06 +0200 Subject: [PATCH 24/25] Delete .project --- .project | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 .project diff --git a/.project b/.project deleted file mode 100644 index 5d9663f32..000000000 --- a/.project +++ /dev/null @@ -1,18 +0,0 @@ - - - Gradido - - - - - - org.eclipse.wst.validation.validationbuilder - - - - - - org.jkiss.dbeaver.DBeaverNature - org.eclipse.wst.jsdt.core.jsNature - - From e1fca7fb142d66c0c4cbbb01ebdc8ca5376c3785 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Fri, 24 Jun 2022 00:07:37 +0200 Subject: [PATCH 25/25] correct version of database --- database/src/config/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database/src/config/index.ts b/database/src/config/index.ts index d8cd78eae..ba41f11d4 100644 --- a/database/src/config/index.ts +++ b/database/src/config/index.ts @@ -6,7 +6,7 @@ dotenv.config() const constants = { CONFIG_VERSION: { DEFAULT: 'DEFAULT', - EXPECTED: 'v7.2022-06-15', + EXPECTED: 'v1.2022-03-18', CURRENT: '', }, }