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/15] 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/15] 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/15] 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/15] 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/15] 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/15] 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/15] 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/15] 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/15] 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/15] 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/15] 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/15] 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/15] 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/15] 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/15] 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 + } + } +`