From 4a9f3e666d67f3b166f786fc5412dbe0b1794d46 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 7 Mar 2023 00:02:31 +0100 Subject: [PATCH 01/49] database update, include contribution & transaction link ids --- backend/src/config/index.ts | 2 +- .../entity/0063-event_link_fields/Event.ts | 99 +++++++++++++++++++ database/entity/Event.ts | 2 +- database/migrations/0063-event_link_fields.ts | 29 ++++++ dht-node/src/config/index.ts | 2 +- federation/src/config/index.ts | 2 +- 6 files changed, 132 insertions(+), 4 deletions(-) create mode 100644 database/entity/0063-event_link_fields/Event.ts create mode 100644 database/migrations/0063-event_link_fields.ts diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index 9aabaf4ad..ef537d804 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -10,7 +10,7 @@ Decimal.set({ }) const constants = { - DB_VERSION: '0062-event_contribution_confirm', + DB_VERSION: '0063-event_link_fields', 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 diff --git a/database/entity/0063-event_link_fields/Event.ts b/database/entity/0063-event_link_fields/Event.ts new file mode 100644 index 000000000..bd3616cf8 --- /dev/null +++ b/database/entity/0063-event_link_fields/Event.ts @@ -0,0 +1,99 @@ +import { Contribution } from '../Contribution' +import { ContributionMessage } from '../ContributionMessage' +import { User } from '../User' +import { Transaction } from '../Transaction' +import Decimal from 'decimal.js-light' +import { + BaseEntity, + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + ManyToOne, + JoinColumn, +} from 'typeorm' +import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer' +import { TransactionLink } from '../TransactionLink' +import { ContributionLink } from '../ContributionLink' + +@Entity('events') +export class Event extends BaseEntity { + @PrimaryGeneratedColumn('increment', { unsigned: true }) + id: number + + @Column({ length: 100, nullable: false, collation: 'utf8mb4_unicode_ci' }) + type: string + + @CreateDateColumn({ + name: 'created_at', + type: 'datetime', + default: () => 'CURRENT_TIMESTAMP()', + nullable: false, + }) + createdAt: Date + + @Column({ name: 'affected_user_id', unsigned: true, nullable: false }) + affectedUserId: number + + @ManyToOne(() => User) + @JoinColumn({ name: 'affected_user_id', referencedColumnName: 'id' }) + affectedUser: User + + @Column({ name: 'acting_user_id', unsigned: true, nullable: false }) + actingUserId: number + + @ManyToOne(() => User) + @JoinColumn({ name: 'acting_user_id', referencedColumnName: 'id' }) + actingUser: User + + @Column({ name: 'involved_user_id', type: 'int', unsigned: true, nullable: true }) + involvedUserId: number | null + + @ManyToOne(() => User) + @JoinColumn({ name: 'involved_user_id', referencedColumnName: 'id' }) + involvedUser: User | null + + @Column({ name: 'involved_transaction_id', type: 'int', unsigned: true, nullable: true }) + involvedTransactionId: number | null + + @ManyToOne(() => Transaction) + @JoinColumn({ name: 'involved_transaction_id', referencedColumnName: 'id' }) + involvedTransaction: Transaction | null + + @Column({ name: 'involved_contribution_id', type: 'int', unsigned: true, nullable: true }) + involvedContributionId: number | null + + @ManyToOne(() => Contribution) + @JoinColumn({ name: 'involved_contribution_id', referencedColumnName: 'id' }) + involvedContribution: Contribution | null + + @Column({ name: 'involved_contribution_message_id', type: 'int', unsigned: true, nullable: true }) + involvedContributionMessageId: number | null + + @ManyToOne(() => ContributionMessage) + @JoinColumn({ name: 'involved_contribution_message_id', referencedColumnName: 'id' }) + involvedContributionMessage: ContributionMessage | null + + @Column({ name: 'involved_transaction_link_id', type: 'int', unsigned: true, nullable: true }) + involvedTransactionLinkId: number | null + + @ManyToOne(() => TransactionLink) + @JoinColumn({ name: 'involved_transaction_link_id', referencedColumnName: 'id' }) + involvedTransactionLink: TransactionLink | null + + @Column({ name: 'involved_contribution_link_id', type: 'int', unsigned: true, nullable: true }) + involvedContributionLinkId: number | null + + @ManyToOne(() => ContributionLink) + @JoinColumn({ name: 'involved_contribution_link_id', referencedColumnName: 'id' }) + involvedContributionLink: ContributionLink | null + + @Column({ + type: 'decimal', + precision: 40, + scale: 20, + nullable: true, + transformer: DecimalTransformer, + }) + amount: Decimal | null +} diff --git a/database/entity/Event.ts b/database/entity/Event.ts index e53085f2f..04cbaf458 100644 --- a/database/entity/Event.ts +++ b/database/entity/Event.ts @@ -1 +1 @@ -export { Event } from './0061-event_refactoring/Event' +export { Event } from './0063-event_link_fields/Event' diff --git a/database/migrations/0063-event_link_fields.ts b/database/migrations/0063-event_link_fields.ts new file mode 100644 index 000000000..3b383ad07 --- /dev/null +++ b/database/migrations/0063-event_link_fields.ts @@ -0,0 +1,29 @@ +/* MIGRATION TO ADD LINK ID FIELDS TO EVENT TABLE + * + * This migration add two fields to store a TransactionLinkId and a ContributionLinkId + * in the event table. Furthermore the event `REDEEM_REGISTER` is rewritten to use the + * new fields. + */ + +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +export async function upgrade(queryFn: (query: string, values?: any[]) => Promise>) { + await queryFn( + 'ALTER TABLE `events` ADD COLUMN `involved_transaction_link_id` int(10) unsigned DEFAULT NULL AFTER `involved_contribution_message_id`;', + ) + await queryFn( + 'ALTER TABLE `events` ADD COLUMN `involved_contribution_link_id` int(10) unsigned DEFAULT NULL AFTER `involved_transaction_link_id`;', + ) + await queryFn( + 'UPDATE `events` SET `involved_transaction_link_id` = `involved_transaction_id`, `involved_transaction_id` = NULL, `involved_contribution_link_id` = `involved_contribution_id`, `involved_contribution_id` = NULL WHERE `type` = "REDEEM_REGISTER";', + ) +} + +export async function downgrade(queryFn: (query: string, values?: any[]) => Promise>) { + await queryFn( + 'UPDATE `events` SET `involved_transaction_id` = `involved_transaction_link_id`, `involved_contribution_id` = `involved_contribution_link_id` WHERE `type` = "REDEEM_REGISTER";', + ) + await queryFn('ALTER TABLE `events` DROP COLUMN `involved_contribution_link_id`;') + await queryFn('ALTER TABLE `events` DROP COLUMN `involved_transaction_link_id`;') +} diff --git a/dht-node/src/config/index.ts b/dht-node/src/config/index.ts index 7ca44e52c..78f2b162c 100644 --- a/dht-node/src/config/index.ts +++ b/dht-node/src/config/index.ts @@ -3,7 +3,7 @@ import dotenv from 'dotenv' dotenv.config() const constants = { - DB_VERSION: '0062-event_contribution_confirm', + DB_VERSION: '0063-event_link_fields', LOG4JS_CONFIG: 'log4js-config.json', // default log level on production should be info LOG_LEVEL: process.env.LOG_LEVEL || 'info', diff --git a/federation/src/config/index.ts b/federation/src/config/index.ts index b3b529e20..61204ca37 100644 --- a/federation/src/config/index.ts +++ b/federation/src/config/index.ts @@ -11,7 +11,7 @@ Decimal.set({ */ const constants = { - DB_VERSION: '0062-event_contribution_confirm', + DB_VERSION: '0063-event_link_fields', // 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 From e3377652d4aea0302ce00ab5fbb79f42d9d1b2b9 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 7 Mar 2023 00:04:08 +0100 Subject: [PATCH 02/49] fix redeem event, new events for contribution links, refactor contribution links resolver --- .../event/EVENT_ADMIN_CONTRIBUTION_CONFIRM.ts | 2 ++ .../event/EVENT_ADMIN_CONTRIBUTION_CREATE.ts | 2 ++ .../event/EVENT_ADMIN_CONTRIBUTION_DELETE.ts | 2 ++ .../event/EVENT_ADMIN_CONTRIBUTION_DENY.ts | 2 ++ .../EVENT_ADMIN_CONTRIBUTION_LINK_CREATE.ts | 23 +++++++++++++ .../EVENT_ADMIN_CONTRIBUTION_LINK_DELETE.ts | 20 +++++++++++ .../EVENT_ADMIN_CONTRIBUTION_LINK_UPDATE.ts | 23 +++++++++++++ .../event/EVENT_ADMIN_CONTRIBUTION_UPDATE.ts | 2 ++ .../src/event/EVENT_CONTRIBUTION_CREATE.ts | 13 +++++++- .../src/event/EVENT_CONTRIBUTION_DELETE.ts | 13 +++++++- .../src/event/EVENT_CONTRIBUTION_UPDATE.ts | 13 +++++++- .../src/event/EVENT_TRANSACTION_RECEIVE.ts | 2 ++ backend/src/event/EVENT_TRANSACTION_SEND.ts | 2 ++ backend/src/event/Event.ts | 13 ++++++-- backend/src/event/EventType.ts | 5 +-- .../resolver/ContributionLinkResolver.ts | 33 ++++++++++++++----- backend/src/graphql/resolver/UserResolver.ts | 4 +-- 17 files changed, 156 insertions(+), 18 deletions(-) create mode 100644 backend/src/event/EVENT_ADMIN_CONTRIBUTION_LINK_CREATE.ts create mode 100644 backend/src/event/EVENT_ADMIN_CONTRIBUTION_LINK_DELETE.ts create mode 100644 backend/src/event/EVENT_ADMIN_CONTRIBUTION_LINK_UPDATE.ts diff --git a/backend/src/event/EVENT_ADMIN_CONTRIBUTION_CONFIRM.ts b/backend/src/event/EVENT_ADMIN_CONTRIBUTION_CONFIRM.ts index 140ba8497..c85a7a12c 100644 --- a/backend/src/event/EVENT_ADMIN_CONTRIBUTION_CONFIRM.ts +++ b/backend/src/event/EVENT_ADMIN_CONTRIBUTION_CONFIRM.ts @@ -18,5 +18,7 @@ export const EVENT_ADMIN_CONTRIBUTION_CONFIRM = async ( null, contribution, null, + null, + null, amount, ).save() diff --git a/backend/src/event/EVENT_ADMIN_CONTRIBUTION_CREATE.ts b/backend/src/event/EVENT_ADMIN_CONTRIBUTION_CREATE.ts index c95ba5b9b..a10ff1a35 100644 --- a/backend/src/event/EVENT_ADMIN_CONTRIBUTION_CREATE.ts +++ b/backend/src/event/EVENT_ADMIN_CONTRIBUTION_CREATE.ts @@ -18,5 +18,7 @@ export const EVENT_ADMIN_CONTRIBUTION_CREATE = async ( null, contribution, null, + null, + null, amount, ).save() diff --git a/backend/src/event/EVENT_ADMIN_CONTRIBUTION_DELETE.ts b/backend/src/event/EVENT_ADMIN_CONTRIBUTION_DELETE.ts index 30cfd8b93..d3dd5508e 100644 --- a/backend/src/event/EVENT_ADMIN_CONTRIBUTION_DELETE.ts +++ b/backend/src/event/EVENT_ADMIN_CONTRIBUTION_DELETE.ts @@ -18,5 +18,7 @@ export const EVENT_ADMIN_CONTRIBUTION_DELETE = async ( null, contribution, null, + null, + null, amount, ).save() diff --git a/backend/src/event/EVENT_ADMIN_CONTRIBUTION_DENY.ts b/backend/src/event/EVENT_ADMIN_CONTRIBUTION_DENY.ts index d84467f4f..5f1203766 100644 --- a/backend/src/event/EVENT_ADMIN_CONTRIBUTION_DENY.ts +++ b/backend/src/event/EVENT_ADMIN_CONTRIBUTION_DENY.ts @@ -18,5 +18,7 @@ export const EVENT_ADMIN_CONTRIBUTION_DENY = async ( null, contribution, null, + null, + null, amount, ).save() diff --git a/backend/src/event/EVENT_ADMIN_CONTRIBUTION_LINK_CREATE.ts b/backend/src/event/EVENT_ADMIN_CONTRIBUTION_LINK_CREATE.ts new file mode 100644 index 000000000..2ead791ed --- /dev/null +++ b/backend/src/event/EVENT_ADMIN_CONTRIBUTION_LINK_CREATE.ts @@ -0,0 +1,23 @@ +import Decimal from 'decimal.js-light' +import { User as DbUser } from '@entity/User' +import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' +import { Event as DbEvent } from '@entity/Event' +import { Event, EventType } from './Event' + +export const EVENT_ADMIN_CONTRIBUTION_LINK_CREATE = async ( + moderator: DbUser, + contributionLink: DbContributionLink, + amount: Decimal, +): Promise => + Event( + EventType.ADMIN_CONTRIBUTION_LINK_CREATE, + { id: 0 } as DbUser, + moderator, + null, + null, + null, + null, + null, + contributionLink, + amount, + ).save() diff --git a/backend/src/event/EVENT_ADMIN_CONTRIBUTION_LINK_DELETE.ts b/backend/src/event/EVENT_ADMIN_CONTRIBUTION_LINK_DELETE.ts new file mode 100644 index 000000000..b5816e45d --- /dev/null +++ b/backend/src/event/EVENT_ADMIN_CONTRIBUTION_LINK_DELETE.ts @@ -0,0 +1,20 @@ +import { User as DbUser } from '@entity/User' +import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' +import { Event as DbEvent } from '@entity/Event' +import { Event, EventType } from './Event' + +export const EVENT_ADMIN_CONTRIBUTION_LINK_DELETE = async ( + moderator: DbUser, + contributionLink: DbContributionLink, +): Promise => + Event( + EventType.ADMIN_CONTRIBUTION_LINK_DELETE, + { id: 0 } as DbUser, + moderator, + null, + null, + null, + null, + null, + contributionLink, + ).save() diff --git a/backend/src/event/EVENT_ADMIN_CONTRIBUTION_LINK_UPDATE.ts b/backend/src/event/EVENT_ADMIN_CONTRIBUTION_LINK_UPDATE.ts new file mode 100644 index 000000000..6824833b8 --- /dev/null +++ b/backend/src/event/EVENT_ADMIN_CONTRIBUTION_LINK_UPDATE.ts @@ -0,0 +1,23 @@ +import Decimal from 'decimal.js-light' +import { User as DbUser } from '@entity/User' +import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' +import { Event as DbEvent } from '@entity/Event' +import { Event, EventType } from './Event' + +export const EVENT_ADMIN_CONTRIBUTION_LINK_UPDATE = async ( + moderator: DbUser, + contributionLink: DbContributionLink, + amount: Decimal, +): Promise => + Event( + EventType.ADMIN_CONTRIBUTION_LINK_UPDATE, + { id: 0 } as DbUser, + moderator, + null, + null, + null, + null, + null, + contributionLink, + amount, + ).save() diff --git a/backend/src/event/EVENT_ADMIN_CONTRIBUTION_UPDATE.ts b/backend/src/event/EVENT_ADMIN_CONTRIBUTION_UPDATE.ts index 3fc17f7d2..60315249a 100644 --- a/backend/src/event/EVENT_ADMIN_CONTRIBUTION_UPDATE.ts +++ b/backend/src/event/EVENT_ADMIN_CONTRIBUTION_UPDATE.ts @@ -18,5 +18,7 @@ export const EVENT_ADMIN_CONTRIBUTION_UPDATE = async ( null, contribution, null, + null, + null, amount, ).save() diff --git a/backend/src/event/EVENT_CONTRIBUTION_CREATE.ts b/backend/src/event/EVENT_CONTRIBUTION_CREATE.ts index cbc514dc8..50cdbcd18 100644 --- a/backend/src/event/EVENT_CONTRIBUTION_CREATE.ts +++ b/backend/src/event/EVENT_CONTRIBUTION_CREATE.ts @@ -9,4 +9,15 @@ export const EVENT_CONTRIBUTION_CREATE = async ( contribution: DbContribution, amount: Decimal, ): Promise => - Event(EventType.CONTRIBUTION_CREATE, user, user, null, null, contribution, null, amount).save() + Event( + EventType.CONTRIBUTION_CREATE, + user, + user, + null, + null, + contribution, + null, + null, + null, + amount, + ).save() diff --git a/backend/src/event/EVENT_CONTRIBUTION_DELETE.ts b/backend/src/event/EVENT_CONTRIBUTION_DELETE.ts index b15e57ea8..eab04bf47 100644 --- a/backend/src/event/EVENT_CONTRIBUTION_DELETE.ts +++ b/backend/src/event/EVENT_CONTRIBUTION_DELETE.ts @@ -9,4 +9,15 @@ export const EVENT_CONTRIBUTION_DELETE = async ( contribution: DbContribution, amount: Decimal, ): Promise => - Event(EventType.CONTRIBUTION_DELETE, user, user, null, null, contribution, null, amount).save() + Event( + EventType.CONTRIBUTION_DELETE, + user, + user, + null, + null, + contribution, + null, + null, + null, + amount, + ).save() diff --git a/backend/src/event/EVENT_CONTRIBUTION_UPDATE.ts b/backend/src/event/EVENT_CONTRIBUTION_UPDATE.ts index 2fb56dc77..82f14edd6 100644 --- a/backend/src/event/EVENT_CONTRIBUTION_UPDATE.ts +++ b/backend/src/event/EVENT_CONTRIBUTION_UPDATE.ts @@ -9,4 +9,15 @@ export const EVENT_CONTRIBUTION_UPDATE = async ( contribution: DbContribution, amount: Decimal, ): Promise => - Event(EventType.CONTRIBUTION_UPDATE, user, user, null, null, contribution, null, amount).save() + Event( + EventType.CONTRIBUTION_UPDATE, + user, + user, + null, + null, + contribution, + null, + null, + null, + amount, + ).save() diff --git a/backend/src/event/EVENT_TRANSACTION_RECEIVE.ts b/backend/src/event/EVENT_TRANSACTION_RECEIVE.ts index 78f561148..acb2f5881 100644 --- a/backend/src/event/EVENT_TRANSACTION_RECEIVE.ts +++ b/backend/src/event/EVENT_TRANSACTION_RECEIVE.ts @@ -18,5 +18,7 @@ export const EVENT_TRANSACTION_RECEIVE = async ( transaction, null, null, + null, + null, amount, ).save() diff --git a/backend/src/event/EVENT_TRANSACTION_SEND.ts b/backend/src/event/EVENT_TRANSACTION_SEND.ts index e281b0d30..a342cb0aa 100644 --- a/backend/src/event/EVENT_TRANSACTION_SEND.ts +++ b/backend/src/event/EVENT_TRANSACTION_SEND.ts @@ -18,5 +18,7 @@ export const EVENT_TRANSACTION_SEND = async ( transaction, null, null, + null, + null, amount, ).save() diff --git a/backend/src/event/Event.ts b/backend/src/event/Event.ts index 163b0b646..2e7cca6af 100644 --- a/backend/src/event/Event.ts +++ b/backend/src/event/Event.ts @@ -1,8 +1,10 @@ import { Event as DbEvent } from '@entity/Event' import { User as DbUser } from '@entity/User' -import { ContributionMessage as DbContributionMessage } from '@entity/ContributionMessage' -import { Contribution as DbContribution } from '@entity/Contribution' import { Transaction as DbTransaction } from '@entity/Transaction' +import { TransactionLink as DbTransactionLink } from '@entity/TransactionLink' +import { Contribution as DbContribution } from '@entity/Contribution' +import { ContributionMessage as DbContributionMessage } from '@entity/ContributionMessage' +import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' import Decimal from 'decimal.js-light' import { EventType } from './Event' @@ -14,6 +16,8 @@ export const Event = ( involvedTransaction: DbTransaction | null = null, involvedContribution: DbContribution | null = null, involvedContributionMessage: DbContributionMessage | null = null, + involvedTransactionLink: DbTransactionLink | null = null, + involvedContributionLink: DbContributionLink | null = null, amount: Decimal | null = null, ): DbEvent => { const event = new DbEvent() @@ -24,6 +28,8 @@ export const Event = ( event.involvedTransaction = involvedTransaction event.involvedContribution = involvedContribution event.involvedContributionMessage = involvedContributionMessage + event.involvedTransactionLink = involvedTransactionLink + event.involvedContributionLink = involvedContributionLink event.amount = amount return event } @@ -36,6 +42,9 @@ export { EVENT_ADMIN_CONTRIBUTION_CREATE } from './EVENT_ADMIN_CONTRIBUTION_CREA export { EVENT_ADMIN_CONTRIBUTION_DELETE } from './EVENT_ADMIN_CONTRIBUTION_DELETE' export { EVENT_ADMIN_CONTRIBUTION_DENY } from './EVENT_ADMIN_CONTRIBUTION_DENY' export { EVENT_ADMIN_CONTRIBUTION_UPDATE } from './EVENT_ADMIN_CONTRIBUTION_UPDATE' +export { EVENT_ADMIN_CONTRIBUTION_LINK_CREATE } from './EVENT_ADMIN_CONTRIBUTION_LINK_CREATE' +export { EVENT_ADMIN_CONTRIBUTION_LINK_DELETE } from './EVENT_ADMIN_CONTRIBUTION_LINK_DELETE' +export { EVENT_ADMIN_CONTRIBUTION_LINK_UPDATE } from './EVENT_ADMIN_CONTRIBUTION_LINK_UPDATE' export { EVENT_ADMIN_SEND_CONFIRMATION_EMAIL } from './EVENT_ADMIN_SEND_CONFIRMATION_EMAIL' export { EVENT_CONTRIBUTION_CREATE } from './EVENT_CONTRIBUTION_CREATE' export { EVENT_CONTRIBUTION_DELETE } from './EVENT_CONTRIBUTION_DELETE' diff --git a/backend/src/event/EventType.ts b/backend/src/event/EventType.ts index 241923ffd..e40aa91ab 100644 --- a/backend/src/event/EventType.ts +++ b/backend/src/event/EventType.ts @@ -11,6 +11,9 @@ export enum EventType { ADMIN_CONTRIBUTION_DELETE = 'ADMIN_CONTRIBUTION_DELETE', ADMIN_CONTRIBUTION_DENY = 'ADMIN_CONTRIBUTION_DENY', ADMIN_CONTRIBUTION_UPDATE = 'ADMIN_CONTRIBUTION_UPDATE', + ADMIN_CONTRIBUTION_LINK_CREATE = 'ADMIN_CONTRIBUTION_LINK_CREATE', + ADMIN_CONTRIBUTION_LINK_DELETE = 'ADMIN_CONTRIBUTION_LINK_DELETE', + ADMIN_CONTRIBUTION_LINK_UPDATE = 'ADMIN_CONTRIBUTION_LINK_UPDATE', ADMIN_SEND_CONFIRMATION_EMAIL = 'ADMIN_SEND_CONFIRMATION_EMAIL', CONTRIBUTION_CREATE = 'CONTRIBUTION_CREATE', CONTRIBUTION_DELETE = 'CONTRIBUTION_DELETE', @@ -40,8 +43,6 @@ export enum EventType { // SEND_TRANSACTION_LINK_REDEEM_EMAIL = 'SEND_TRANSACTION_LINK_REDEEM_EMAIL', // SEND_ADDED_CONTRIBUTION_EMAIL = 'SEND_ADDED_CONTRIBUTION_EMAIL', // SEND_CONTRIBUTION_CONFIRM_EMAIL = 'SEND_CONTRIBUTION_CONFIRM_EMAIL', - // CONTRIBUTION_DENY = 'CONTRIBUTION_DENY', - // CONTRIBUTION_LINK_DEFINE = 'CONTRIBUTION_LINK_DEFINE', // CONTRIBUTION_LINK_ACTIVATE_REDEEM = 'CONTRIBUTION_LINK_ACTIVATE_REDEEM', // USER_CREATE_CONTRIBUTION_MESSAGE = 'USER_CREATE_CONTRIBUTION_MESSAGE', // ADMIN_CREATE_CONTRIBUTION_MESSAGE = 'ADMIN_CREATE_CONTRIBUTION_MESSAGE', diff --git a/backend/src/graphql/resolver/ContributionLinkResolver.ts b/backend/src/graphql/resolver/ContributionLinkResolver.ts index d3c77cb82..850117084 100644 --- a/backend/src/graphql/resolver/ContributionLinkResolver.ts +++ b/backend/src/graphql/resolver/ContributionLinkResolver.ts @@ -1,5 +1,5 @@ import Decimal from 'decimal.js-light' -import { Resolver, Args, Arg, Authorized, Mutation, Query, Int } from 'type-graphql' +import { Resolver, Args, Arg, Authorized, Mutation, Query, Int, Ctx } from 'type-graphql' import { MoreThan, IsNull } from '@dbTools/typeorm' import { @@ -21,6 +21,12 @@ import Paginated from '@arg/Paginated' // TODO: this is a strange construct import { transactionLinkCode as contributionLinkCode } from './TransactionLinkResolver' import LogError from '@/server/LogError' +import { Context, getUser } from '@/server/context' +import { + EVENT_ADMIN_CONTRIBUTION_LINK_CREATE, + EVENT_ADMIN_CONTRIBUTION_LINK_DELETE, + EVENT_ADMIN_CONTRIBUTION_LINK_UPDATE, +} from '@/event/Event' @Resolver() export class ContributionLinkResolver { @@ -38,6 +44,7 @@ export class ContributionLinkResolver { maxAmountPerMonth, maxPerCycle, }: ContributionLinkArgs, + @Ctx() context: Context, ): Promise { isStartEndDateValid(validFrom, validTo) if (name.length < CONTRIBUTIONLINK_NAME_MIN_CHARS) { @@ -68,7 +75,8 @@ export class ContributionLinkResolver { dbContributionLink.maxAmountPerMonth = maxAmountPerMonth dbContributionLink.maxPerCycle = maxPerCycle await dbContributionLink.save() - logger.debug(`createContributionLink successful!`) + await EVENT_ADMIN_CONTRIBUTION_LINK_CREATE(getUser(context), dbContributionLink, amount) + return new ContributionLink(dbContributionLink) } @@ -92,15 +100,18 @@ export class ContributionLinkResolver { @Authorized([RIGHTS.ADMIN_DELETE_CONTRIBUTION_LINK]) @Mutation(() => Date, { nullable: true }) - async deleteContributionLink(@Arg('id', () => Int) id: number): Promise { - const contributionLink = await DbContributionLink.findOne(id) - if (!contributionLink) { + async deleteContributionLink( + @Arg('id', () => Int) id: number, + @Ctx() context: Context, + ): Promise { + const dbContributionLink = await DbContributionLink.findOne(id) + if (!dbContributionLink) { throw new LogError('Contribution Link not found', id) } - await contributionLink.softRemove() - logger.debug(`deleteContributionLink successful!`) - const newContributionLink = await DbContributionLink.findOne({ id }, { withDeleted: true }) - return newContributionLink ? newContributionLink.deletedAt : null + await dbContributionLink.softRemove() + await EVENT_ADMIN_CONTRIBUTION_LINK_DELETE(getUser(context), dbContributionLink) + + return true } @Authorized([RIGHTS.ADMIN_UPDATE_CONTRIBUTION_LINK]) @@ -118,6 +129,7 @@ export class ContributionLinkResolver { maxPerCycle, }: ContributionLinkArgs, @Arg('id', () => Int) id: number, + @Ctx() context: Context, ): Promise { const dbContributionLink = await DbContributionLink.findOne(id) if (!dbContributionLink) { @@ -133,6 +145,9 @@ export class ContributionLinkResolver { dbContributionLink.maxPerCycle = maxPerCycle await dbContributionLink.save() logger.debug(`updateContributionLink successful!`) + + await EVENT_ADMIN_CONTRIBUTION_LINK_UPDATE(getUser(context), dbContributionLink, amount) + return new ContributionLink(dbContributionLink) } } diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 1ddcc942a..d89e1c498 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -290,7 +290,7 @@ export class UserResolver { if (contributionLink) { dbUser.contributionLinkId = contributionLink.id // TODO this is so wrong - eventRegisterRedeem.involvedContribution = { id: contributionLink.id } as DbContribution + eventRegisterRedeem.involvedContributionLink = contributionLink } } else { const transactionLink = await DbTransactionLink.findOne({ code: redeemCode }) @@ -298,7 +298,7 @@ export class UserResolver { if (transactionLink) { dbUser.referrerId = transactionLink.userId // TODO this is so wrong - eventRegisterRedeem.involvedTransaction = { id: transactionLink.id } as DbTransaction + eventRegisterRedeem.involvedTransactionLink = transactionLink } } } From 49612871a310a76d040b7546ebca3ed84ca558cc Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 7 Mar 2023 00:05:14 +0100 Subject: [PATCH 03/49] removed fixed todos --- backend/src/graphql/resolver/UserResolver.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index d89e1c498..f7d6be9fb 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -289,7 +289,6 @@ export class UserResolver { logger.info('redeemCode found contributionLink=' + contributionLink) if (contributionLink) { dbUser.contributionLinkId = contributionLink.id - // TODO this is so wrong eventRegisterRedeem.involvedContributionLink = contributionLink } } else { @@ -297,7 +296,6 @@ export class UserResolver { logger.info('redeemCode found transactionLink=' + transactionLink) if (transactionLink) { dbUser.referrerId = transactionLink.userId - // TODO this is so wrong eventRegisterRedeem.involvedTransactionLink = transactionLink } } From 8399363f05393c9a4604794b60890f5699a3d210 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 7 Mar 2023 00:11:56 +0100 Subject: [PATCH 04/49] removed comments of already implemented event types --- backend/src/event/EventType.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/backend/src/event/EventType.ts b/backend/src/event/EventType.ts index e40aa91ab..5d69eba2d 100644 --- a/backend/src/event/EventType.ts +++ b/backend/src/event/EventType.ts @@ -49,9 +49,4 @@ export enum EventType { // DELETE_USER = 'DELETE_USER', // UNDELETE_USER = 'UNDELETE_USER', // CHANGE_USER_ROLE = 'CHANGE_USER_ROLE', - // ADMIN_UPDATE_CONTRIBUTION = 'ADMIN_UPDATE_CONTRIBUTION', - // ADMIN_DELETE_CONTRIBUTION = 'ADMIN_DELETE_CONTRIBUTION', - // CREATE_CONTRIBUTION_LINK = 'CREATE_CONTRIBUTION_LINK', - // DELETE_CONTRIBUTION_LINK = 'DELETE_CONTRIBUTION_LINK', - // UPDATE_CONTRIBUTION_LINK = 'UPDATE_CONTRIBUTION_LINK', } From 3979e84a8c590c73973c74d06064fec15f2151ee Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 7 Mar 2023 00:14:52 +0100 Subject: [PATCH 05/49] fixed lint --- backend/src/graphql/resolver/UserResolver.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index f7d6be9fb..2cd40938f 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -16,9 +16,7 @@ import { getConnection, getCustomRepository, IsNull, Not } from '@dbTools/typeor import { User as DbUser } from '@entity/User' import { UserContact as DbUserContact } from '@entity/UserContact' import { TransactionLink as DbTransactionLink } from '@entity/TransactionLink' -import { Transaction as DbTransaction } from '@entity/Transaction' import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' -import { Contribution as DbContribution } from '@entity/Contribution' import { UserRepository } from '@repository/User' import { User } from '@model/User' From dac2cf7bba779ec800a4272d63b569a9fed2bfc0 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 7 Mar 2023 11:27:47 +0100 Subject: [PATCH 06/49] fixed tests --- backend/src/graphql/resolver/ContributionLinkResolver.test.ts | 2 +- backend/src/graphql/resolver/ContributionLinkResolver.ts | 2 +- backend/src/graphql/resolver/UserResolver.test.ts | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionLinkResolver.test.ts b/backend/src/graphql/resolver/ContributionLinkResolver.test.ts index 62f273829..42966fa82 100644 --- a/backend/src/graphql/resolver/ContributionLinkResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionLinkResolver.test.ts @@ -560,7 +560,7 @@ describe('Contribution Links', () => { ).resolves.toEqual( expect.objectContaining({ data: { - deleteContributionLink: expect.any(String), + deleteContributionLink: true, }, }), ) diff --git a/backend/src/graphql/resolver/ContributionLinkResolver.ts b/backend/src/graphql/resolver/ContributionLinkResolver.ts index 850117084..3a8c6c85b 100644 --- a/backend/src/graphql/resolver/ContributionLinkResolver.ts +++ b/backend/src/graphql/resolver/ContributionLinkResolver.ts @@ -99,7 +99,7 @@ export class ContributionLinkResolver { } @Authorized([RIGHTS.ADMIN_DELETE_CONTRIBUTION_LINK]) - @Mutation(() => Date, { nullable: true }) + @Mutation(() => Boolean, { nullable: true }) async deleteContributionLink( @Arg('id', () => Int) id: number, @Ctx() context: Context, diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index 3bcc229b1..b382b2627 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -374,7 +374,7 @@ describe('UserResolver', () => { type: EventType.REDEEM_REGISTER, affectedUserId: result.data.createUser.id, actingUserId: result.data.createUser.id, - involvedContributionId: link.id, + involvedContributionLinkId: link.id, }), ) }) @@ -459,7 +459,7 @@ describe('UserResolver', () => { type: EventType.REDEEM_REGISTER, affectedUserId: newUser.data.createUser.id, actingUserId: newUser.data.createUser.id, - involvedTransactionId: transactionLink.id, + involvedTransactionLinkId: transactionLink.id, }), ) }) From ccccf75fa5dd53afa3be60f867a681ea3d2d5ddb Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 7 Mar 2023 11:32:39 +0100 Subject: [PATCH 07/49] removed automatically included files --- backend/src/event/EventType.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/backend/src/event/EventType.ts b/backend/src/event/EventType.ts index 5d69eba2d..b219a49ba 100644 --- a/backend/src/event/EventType.ts +++ b/backend/src/event/EventType.ts @@ -1,8 +1,3 @@ -export { EVENT_SEND_ACCOUNT_MULTIREGISTRATION_EMAIL } from './EVENT_SEND_ACCOUNT_MULTIREGISTRATION_EMAIL' -export { EVENT_SEND_CONFIRMATION_EMAIL } from './EVENT_SEND_CONFIRMATION_EMAIL' -export { EVENT_TRANSACTION_SEND } from './EVENT_TRANSACTION_SEND' -export { EVENT_TRANSACTION_RECEIVE } from './EVENT_TRANSACTION_RECEIVE' - export enum EventType { ACTIVATE_ACCOUNT = 'ACTIVATE_ACCOUNT', // TODO CONTRIBUTION_CONFIRM = 'CONTRIBUTION_CONFIRM', From ff9df408e30d76705bf494fe9099c9c7150564da Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 7 Mar 2023 11:34:38 +0100 Subject: [PATCH 08/49] corrected test name --- backend/src/graphql/resolver/ContributionLinkResolver.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/ContributionLinkResolver.test.ts b/backend/src/graphql/resolver/ContributionLinkResolver.test.ts index 42966fa82..3c95db047 100644 --- a/backend/src/graphql/resolver/ContributionLinkResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionLinkResolver.test.ts @@ -554,7 +554,7 @@ describe('Contribution Links', () => { linkId = links.data.listContributionLinks.links[0].id }) - it('returns a date string', async () => { + it('returns true', async () => { await expect( mutate({ mutation: deleteContributionLink, variables: { id: linkId } }), ).resolves.toEqual( From fa2916ef4df08ab62fae31b7e3069cc6c0de3cf8 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 7 Mar 2023 11:41:59 +0100 Subject: [PATCH 09/49] test for first event in ContributionLinkResolver --- .../resolver/ContributionLinkResolver.test.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/backend/src/graphql/resolver/ContributionLinkResolver.test.ts b/backend/src/graphql/resolver/ContributionLinkResolver.test.ts index 3c95db047..ed56fd5af 100644 --- a/backend/src/graphql/resolver/ContributionLinkResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionLinkResolver.test.ts @@ -15,6 +15,8 @@ import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { peterLustig } from '@/seeds/users/peter-lustig' import { userFactory } from '@/seeds/factory/user' import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' +import { EventType } from '@/event/Event' +import { Event as DbEvent } from '@entity/Event' let mutate: any, query: any, con: any let testEnv: any @@ -566,6 +568,17 @@ describe('Contribution Links', () => { ) }) + it('stores the ADMIN_CONTRIBUTION_LINK_DELETE event in the database', async () => { + await expect(DbEvent.find()).resolves.toContainEqual( + expect.objectContaining({ + type: EventType.ADMIN_CONTRIBUTION_LINK_DELETE, + affectedUserId: 0, + actingUserId: expect.any(Number), + involvedContributionLinkId: linkId, + }), + ) + }) + it('does not list this contribution link anymore', async () => { await expect(query({ query: listContributionLinks })).resolves.toEqual( expect.objectContaining({ From 7583619058fff4eb3baf2f26c612bb4b32ef41c7 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 7 Mar 2023 11:49:04 +0100 Subject: [PATCH 10/49] test for the other two events --- .../resolver/ContributionLinkResolver.test.ts | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/backend/src/graphql/resolver/ContributionLinkResolver.test.ts b/backend/src/graphql/resolver/ContributionLinkResolver.test.ts index ed56fd5af..3462a05a9 100644 --- a/backend/src/graphql/resolver/ContributionLinkResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionLinkResolver.test.ts @@ -247,6 +247,18 @@ describe('Contribution Links', () => { ) }) + it('stores the ADMIN_CONTRIBUTION_LINK_CREATE event in the database', async () => { + await expect(DbEvent.find()).resolves.toContainEqual( + expect.objectContaining({ + type: EventType.ADMIN_CONTRIBUTION_LINK_CREATE, + affectedUserId: 0, + actingUserId: expect.any(Number), + involvedContributionLinkId: expect.any(Number), + amount: expect.decimalEqual(200), + }), + ) + }) + it('returns an error if missing startDate', async () => { jest.clearAllMocks() await expect( @@ -529,6 +541,18 @@ describe('Contribution Links', () => { }), ) }) + + it('stores the ADMIN_CONTRIBUTION_LINK_UPDATE event in the database', async () => { + await expect(DbEvent.find()).resolves.toContainEqual( + expect.objectContaining({ + type: EventType.ADMIN_CONTRIBUTION_LINK_UPDATE, + affectedUserId: 0, + actingUserId: expect.any(Number), + involvedContributionLinkId: expect.any(Number), + amount: expect.decimalEqual(400), + }), + ) + }) }) }) From d1f72891e03dec94a15b10ec18c3347204d26746 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 7 Mar 2023 12:00:09 +0100 Subject: [PATCH 11/49] increase coverage requirement to 81% in backend --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5eadf1e94..a02aa4b5b 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -427,7 +427,7 @@ jobs: report_name: Coverage Backend type: lcov result_path: ./backend/coverage/lcov.info - min_coverage: 80 + min_coverage: 81 token: ${{ github.token }} ########################################################################## From cf0af5dc856e4725c4b546b7e74e0f6830a7421c Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 7 Mar 2023 12:35:40 +0100 Subject: [PATCH 12/49] missing change for changed event database model --- database/entity/0063-event_link_fields/Event.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database/entity/0063-event_link_fields/Event.ts b/database/entity/0063-event_link_fields/Event.ts index bd3616cf8..dc7fa776c 100644 --- a/database/entity/0063-event_link_fields/Event.ts +++ b/database/entity/0063-event_link_fields/Event.ts @@ -27,7 +27,7 @@ export class Event extends BaseEntity { @CreateDateColumn({ name: 'created_at', type: 'datetime', - default: () => 'CURRENT_TIMESTAMP()', + default: () => 'CURRENT_TIMESTAMP(3)', nullable: false, }) createdAt: Date From d65948ed81738801d38e5540218ff4224fd436b9 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 7 Mar 2023 12:47:44 +0100 Subject: [PATCH 13/49] cleanup --- backend/src/graphql/resolver/ContributionLinkResolver.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionLinkResolver.ts b/backend/src/graphql/resolver/ContributionLinkResolver.ts index 3a8c6c85b..b5f423bda 100644 --- a/backend/src/graphql/resolver/ContributionLinkResolver.ts +++ b/backend/src/graphql/resolver/ContributionLinkResolver.ts @@ -144,8 +144,6 @@ export class ContributionLinkResolver { dbContributionLink.maxAmountPerMonth = maxAmountPerMonth dbContributionLink.maxPerCycle = maxPerCycle await dbContributionLink.save() - logger.debug(`updateContributionLink successful!`) - await EVENT_ADMIN_CONTRIBUTION_LINK_UPDATE(getUser(context), dbContributionLink, amount) return new ContributionLink(dbContributionLink) From cdb7fe32c8f3ab0f303f5f5370f1d617c878a173 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 7 Mar 2023 13:16:27 +0100 Subject: [PATCH 14/49] lint fixes --- backend/src/graphql/resolver/ContributionLinkResolver.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/src/graphql/resolver/ContributionLinkResolver.ts b/backend/src/graphql/resolver/ContributionLinkResolver.ts index b5f423bda..6c396e73d 100644 --- a/backend/src/graphql/resolver/ContributionLinkResolver.ts +++ b/backend/src/graphql/resolver/ContributionLinkResolver.ts @@ -12,7 +12,6 @@ import { isStartEndDateValid } from './util/creations' import { ContributionLinkList } from '@model/ContributionLinkList' import { ContributionLink } from '@model/ContributionLink' import ContributionLinkArgs from '@arg/ContributionLinkArgs' -import { backendLogger as logger } from '@/server/logger' import { RIGHTS } from '@/auth/RIGHTS' import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' import { Order } from '@enum/Order' From 933e9168bc123899b4204c60727d97aabbd44d18 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 7 Mar 2023 13:05:26 +0100 Subject: [PATCH 15/49] events for contributionMessageResolver --- ...EVENT_ADMIN_CONTRIBUTION_MESSAGE_CREATE.ts | 23 +++++++++++++++++++ .../EVENT_CONTRIBUTION_MESSAGE_CREATE.ts | 22 ++++++++++++++++++ backend/src/event/Event.ts | 2 ++ backend/src/event/EventType.ts | 2 ++ .../resolver/ContributionMessageResolver.ts | 17 ++++++++++---- 5 files changed, 61 insertions(+), 5 deletions(-) create mode 100644 backend/src/event/EVENT_ADMIN_CONTRIBUTION_MESSAGE_CREATE.ts create mode 100644 backend/src/event/EVENT_CONTRIBUTION_MESSAGE_CREATE.ts diff --git a/backend/src/event/EVENT_ADMIN_CONTRIBUTION_MESSAGE_CREATE.ts b/backend/src/event/EVENT_ADMIN_CONTRIBUTION_MESSAGE_CREATE.ts new file mode 100644 index 000000000..f07d38e98 --- /dev/null +++ b/backend/src/event/EVENT_ADMIN_CONTRIBUTION_MESSAGE_CREATE.ts @@ -0,0 +1,23 @@ +import { User as DbUser } from '@entity/User' +import { Contribution as DbContribution } from '@entity/Contribution' +import { ContributionMessage as DbContributionMessage } from '@entity/ContributionMessage' +import { Event as DbEvent } from '@entity/Event' +import { Event, EventType } from './Event' + +export const EVENT_ADMIN_CONTRIBUTION_MESSAGE_CREATE = async ( + user: DbUser, + moderator: DbUser, + contribution: DbContribution, + contributionMessage: DbContributionMessage, +): Promise => + Event( + EventType.ADMIN_CONTRIBUTION_MESSAGE_CREATE, + user, + moderator, + null, + null, + contribution, + contributionMessage, + null, + null, + ).save() diff --git a/backend/src/event/EVENT_CONTRIBUTION_MESSAGE_CREATE.ts b/backend/src/event/EVENT_CONTRIBUTION_MESSAGE_CREATE.ts new file mode 100644 index 000000000..b06685a6d --- /dev/null +++ b/backend/src/event/EVENT_CONTRIBUTION_MESSAGE_CREATE.ts @@ -0,0 +1,22 @@ +import { User as DbUser } from '@entity/User' +import { Contribution as DbContribution } from '@entity/Contribution' +import { ContributionMessage as DbContributionMessage } from '@entity/ContributionMessage' +import { Event as DbEvent } from '@entity/Event' +import { Event, EventType } from './Event' + +export const EVENT_CONTRIBUTION_MESSAGE_CREATE = async ( + user: DbUser, + contribution: DbContribution, + contributionMessage: DbContributionMessage, +): Promise => + Event( + EventType.CONTRIBUTION_MESSAGE_CREATE, + user, + user, + null, + null, + contribution, + contributionMessage, + null, + null, + ).save() diff --git a/backend/src/event/Event.ts b/backend/src/event/Event.ts index 2e7cca6af..f1c4269c9 100644 --- a/backend/src/event/Event.ts +++ b/backend/src/event/Event.ts @@ -45,10 +45,12 @@ export { EVENT_ADMIN_CONTRIBUTION_UPDATE } from './EVENT_ADMIN_CONTRIBUTION_UPDA export { EVENT_ADMIN_CONTRIBUTION_LINK_CREATE } from './EVENT_ADMIN_CONTRIBUTION_LINK_CREATE' export { EVENT_ADMIN_CONTRIBUTION_LINK_DELETE } from './EVENT_ADMIN_CONTRIBUTION_LINK_DELETE' export { EVENT_ADMIN_CONTRIBUTION_LINK_UPDATE } from './EVENT_ADMIN_CONTRIBUTION_LINK_UPDATE' +export { EVENT_ADMIN_CONTRIBUTION_MESSAGE_CREATE } from './EVENT_ADMIN_CONTRIBUTION_MESSAGE_CREATE' export { EVENT_ADMIN_SEND_CONFIRMATION_EMAIL } from './EVENT_ADMIN_SEND_CONFIRMATION_EMAIL' export { EVENT_CONTRIBUTION_CREATE } from './EVENT_CONTRIBUTION_CREATE' export { EVENT_CONTRIBUTION_DELETE } from './EVENT_CONTRIBUTION_DELETE' export { EVENT_CONTRIBUTION_UPDATE } from './EVENT_CONTRIBUTION_UPDATE' +export { EVENT_CONTRIBUTION_MESSAGE_CREATE } from './EVENT_CONTRIBUTION_MESSAGE_CREATE' export { EVENT_LOGIN } from './EVENT_LOGIN' export { EVENT_REGISTER } from './EVENT_REGISTER' export { EVENT_SEND_ACCOUNT_MULTIREGISTRATION_EMAIL } from './EVENT_SEND_ACCOUNT_MULTIREGISTRATION_EMAIL' diff --git a/backend/src/event/EventType.ts b/backend/src/event/EventType.ts index b219a49ba..dda571b5a 100644 --- a/backend/src/event/EventType.ts +++ b/backend/src/event/EventType.ts @@ -9,10 +9,12 @@ export enum EventType { ADMIN_CONTRIBUTION_LINK_CREATE = 'ADMIN_CONTRIBUTION_LINK_CREATE', ADMIN_CONTRIBUTION_LINK_DELETE = 'ADMIN_CONTRIBUTION_LINK_DELETE', ADMIN_CONTRIBUTION_LINK_UPDATE = 'ADMIN_CONTRIBUTION_LINK_UPDATE', + ADMIN_CONTRIBUTION_MESSAGE_CREATE = 'ADMIN_CONTRIBUTION_MESSAGE_CREATE', ADMIN_SEND_CONFIRMATION_EMAIL = 'ADMIN_SEND_CONFIRMATION_EMAIL', CONTRIBUTION_CREATE = 'CONTRIBUTION_CREATE', CONTRIBUTION_DELETE = 'CONTRIBUTION_DELETE', CONTRIBUTION_UPDATE = 'CONTRIBUTION_UPDATE', + CONTRIBUTION_MESSAGE_CREATE = 'CONTRIBUTION_MESSAGE_CREATE', LOGIN = 'LOGIN', REGISTER = 'REGISTER', REDEEM_REGISTER = 'REDEEM_REGISTER', diff --git a/backend/src/graphql/resolver/ContributionMessageResolver.ts b/backend/src/graphql/resolver/ContributionMessageResolver.ts index adfcdf160..d4cab2340 100644 --- a/backend/src/graphql/resolver/ContributionMessageResolver.ts +++ b/backend/src/graphql/resolver/ContributionMessageResolver.ts @@ -16,6 +16,7 @@ import { RIGHTS } from '@/auth/RIGHTS' import { Context, getUser } from '@/server/context' import { sendAddedContributionMessageEmail } from '@/emails/sendEmailVariants' import LogError from '@/server/LogError' +import { EVENT_CONTRIBUTION_MESSAGE_CREATE } from '@/event/Event' @Resolver() export class ContributionMessageResolver { @@ -56,6 +57,11 @@ export class ContributionMessageResolver { await queryRunner.manager.update(DbContribution, { id: contributionId }, contribution) } await queryRunner.commitTransaction() + await EVENT_CONTRIBUTION_MESSAGE_CREATE( + user, + { id: contributionMessage.contributionId } as DbContribution, + contributionMessage, + ) } catch (e) { await queryRunner.rollbackTransaction() throw new LogError(`ContributionMessage was not sent successfully: ${e}`, e) @@ -97,7 +103,7 @@ export class ContributionMessageResolver { @Args() { contributionId, message }: ContributionMessageArgs, @Ctx() context: Context, ): Promise { - const user = getUser(context) + const moderator = getUser(context) const queryRunner = getConnection().createQueryRunner() await queryRunner.connect() @@ -111,7 +117,7 @@ export class ContributionMessageResolver { if (!contribution) { throw new LogError('Contribution not found', contributionId) } - if (contribution.userId === user.id) { + if (contribution.userId === moderator.id) { throw new LogError('Admin can not answer on his own contribution', contributionId) } if (!contribution.user.emailContact) { @@ -122,7 +128,7 @@ export class ContributionMessageResolver { contributionMessage.contributionId = contributionId contributionMessage.createdAt = new Date() contributionMessage.message = message - contributionMessage.userId = user.id + contributionMessage.userId = moderator.id contributionMessage.type = ContributionMessageType.DIALOG contributionMessage.isModerator = true await queryRunner.manager.insert(DbContributionMessage, contributionMessage) @@ -141,11 +147,12 @@ export class ContributionMessageResolver { lastName: contribution.user.lastName, email: contribution.user.emailContact.email, language: contribution.user.language, - senderFirstName: user.firstName, - senderLastName: user.lastName, + senderFirstName: moderator.firstName, + senderLastName: moderator.lastName, contributionMemo: contribution.memo, }) await queryRunner.commitTransaction() + await EVENT_ADMIN_CONTRIBUTION_MESSAGE_CREATE({id: contribution.userId} as DbUser, moderator, contribution, contributionMessage) } catch (e) { await queryRunner.rollbackTransaction() throw new LogError(`ContributionMessage was not sent successfully: ${e}`, e) From fd912fb6c8596a2502e52b08c970a9e684bf8c20 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 7 Mar 2023 13:12:39 +0100 Subject: [PATCH 16/49] tests for the two new events --- .../ContributionMessageResolver.test.ts | 26 +++++++++++++++++++ .../resolver/ContributionMessageResolver.ts | 19 ++++++++++---- 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionMessageResolver.test.ts b/backend/src/graphql/resolver/ContributionMessageResolver.test.ts index f3e5e865d..307eef8c5 100644 --- a/backend/src/graphql/resolver/ContributionMessageResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionMessageResolver.test.ts @@ -15,6 +15,8 @@ import { userFactory } from '@/seeds/factory/user' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { peterLustig } from '@/seeds/users/peter-lustig' import { sendAddedContributionMessageEmail } from '@/emails/sendEmailVariants' +import { EventType } from '@/event/Event' +import { Event as DbEvent } from '@entity/Event' jest.mock('@/emails/sendEmailVariants', () => { const originalModule = jest.requireActual('@/emails/sendEmailVariants') @@ -192,6 +194,18 @@ describe('ContributionMessageResolver', () => { contributionMemo: 'Test env contribution', }) }) + + it('stores the ADMIN_CONTRIBUTION_MESSAGE_CREATE event in the database', async () => { + await expect(DbEvent.find()).resolves.toContainEqual( + expect.objectContaining({ + type: EventType.ADMIN_CONTRIBUTION_MESSAGE_CREATE, + affectedUserId: expect.any(Number), + actingUserId: expect.any(Number), + involvedContributionId: result.data.createContribution.id, + involvedContributionMessageId: expect.any(Number), + }), + ) + }) }) }) }) @@ -317,6 +331,18 @@ describe('ContributionMessageResolver', () => { }), ) }) + + it('stores the CONTRIBUTION_MESSAGE_CREATE event in the database', async () => { + await expect(DbEvent.find()).resolves.toContainEqual( + expect.objectContaining({ + type: EventType.CONTRIBUTION_MESSAGE_CREATE, + affectedUserId: expect.any(Number), + actingUserId: expect.any(Number), + involvedContributionId: result.data.createContribution.id, + involvedContributionMessageId: expect.any(Number), + }), + ) + }) }) }) }) diff --git a/backend/src/graphql/resolver/ContributionMessageResolver.ts b/backend/src/graphql/resolver/ContributionMessageResolver.ts index d4cab2340..c8378bcf4 100644 --- a/backend/src/graphql/resolver/ContributionMessageResolver.ts +++ b/backend/src/graphql/resolver/ContributionMessageResolver.ts @@ -3,7 +3,8 @@ import { getConnection } from '@dbTools/typeorm' import { ContributionMessage as DbContributionMessage } from '@entity/ContributionMessage' import { Contribution as DbContribution } from '@entity/Contribution' -import { UserContact } from '@entity/UserContact' +import { UserContact as DbUserContact } from '@entity/UserContact' +import { User as DbUser } from '@entity/User' import { ContributionMessage, ContributionMessageListResult } from '@model/ContributionMessage' import ContributionMessageArgs from '@arg/ContributionMessageArgs' @@ -16,7 +17,10 @@ import { RIGHTS } from '@/auth/RIGHTS' import { Context, getUser } from '@/server/context' import { sendAddedContributionMessageEmail } from '@/emails/sendEmailVariants' import LogError from '@/server/LogError' -import { EVENT_CONTRIBUTION_MESSAGE_CREATE } from '@/event/Event' +import { + EVENT_ADMIN_CONTRIBUTION_MESSAGE_CREATE, + EVENT_CONTRIBUTION_MESSAGE_CREATE, +} from '@/event/Event' @Resolver() export class ContributionMessageResolver { @@ -121,7 +125,7 @@ export class ContributionMessageResolver { throw new LogError('Admin can not answer on his own contribution', contributionId) } if (!contribution.user.emailContact) { - contribution.user.emailContact = await UserContact.findOneOrFail({ + contribution.user.emailContact = await DbUserContact.findOneOrFail({ where: { id: contribution.user.emailId }, }) } @@ -152,13 +156,18 @@ export class ContributionMessageResolver { contributionMemo: contribution.memo, }) await queryRunner.commitTransaction() - await EVENT_ADMIN_CONTRIBUTION_MESSAGE_CREATE({id: contribution.userId} as DbUser, moderator, contribution, contributionMessage) + await EVENT_ADMIN_CONTRIBUTION_MESSAGE_CREATE( + { id: contribution.userId } as DbUser, + moderator, + contribution, + contributionMessage, + ) } catch (e) { await queryRunner.rollbackTransaction() throw new LogError(`ContributionMessage was not sent successfully: ${e}`, e) } finally { await queryRunner.release() } - return new ContributionMessage(contributionMessage, user) + return new ContributionMessage(contributionMessage, moderator) } } From 920f16aad51574e3a09cf40c1199ce4ff68b1505 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 7 Mar 2023 13:33:08 +0100 Subject: [PATCH 17/49] corrected test name, some code style fixes --- .../graphql/resolver/ContributionResolver.test.ts | 2 +- .../src/graphql/resolver/ContributionResolver.ts | 13 ------------- 2 files changed, 1 insertion(+), 14 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index 053e434ea..2b59bde8b 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -2541,7 +2541,7 @@ describe('ContributionResolver', () => { ) }) - it('stores the CONTRIBUTION_CONFIRM event in the database', async () => { + it('stores the ADMIN_CONTRIBUTION_CONFIRM event in the database', async () => { await expect(DbEvent.find()).resolves.toContainEqual( expect.objectContaining({ type: EventType.ADMIN_CONTRIBUTION_CONFIRM, diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 62c53d993..34a27997b 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -89,7 +89,6 @@ export class ContributionResolver { logger.trace('contribution to save', contribution) await DbContribution.save(contribution) - await EVENT_CONTRIBUTION_CREATE(user, contribution, amount) return new UnconfirmedContribution(contribution, user, creations) @@ -117,7 +116,6 @@ export class ContributionResolver { contribution.deletedBy = user.id contribution.deletedAt = new Date() await contribution.save() - await EVENT_CONTRIBUTION_DELETE(user, contribution, contribution.amount) const res = await contribution.softRemove() @@ -254,7 +252,6 @@ export class ContributionResolver { contributionToUpdate.contributionStatus = ContributionStatus.PENDING contributionToUpdate.updatedAt = new Date() DbContribution.save(contributionToUpdate) - await EVENT_CONTRIBUTION_UPDATE(user, contributionToUpdate, amount) return new UnconfirmedContribution(contributionToUpdate, user, creations) @@ -307,11 +304,8 @@ export class ContributionResolver { contribution.moderatorId = moderator.id contribution.contributionType = ContributionType.ADMIN contribution.contributionStatus = ContributionStatus.PENDING - logger.trace('contribution to save', contribution) - await DbContribution.save(contribution) - await EVENT_ADMIN_CONTRIBUTION_CREATE(emailContact.user, moderator, contribution, amount) return getUserCreation(emailContact.userId, clientTimezoneOffset) @@ -377,9 +371,7 @@ export class ContributionResolver { result.amount = amount result.memo = contributionToUpdate.memo result.date = contributionToUpdate.contributionDate - result.creation = await getUserCreation(emailContact.user.id, clientTimezoneOffset) - await EVENT_ADMIN_CONTRIBUTION_UPDATE( emailContact.user, moderator, @@ -440,14 +432,12 @@ export class ContributionResolver { contribution.deletedBy = moderator.id await contribution.save() const res = await contribution.softRemove() - await EVENT_ADMIN_CONTRIBUTION_DELETE( { id: contribution.userId } as DbUser, moderator, contribution, contribution.amount, ) - sendContributionDeletedEmail({ firstName: user.firstName, lastName: user.lastName, @@ -558,7 +548,6 @@ export class ContributionResolver { } finally { await queryRunner.release() } - await EVENT_ADMIN_CONTRIBUTION_CONFIRM(user, moderatorUser, contribution, contribution.amount) } finally { releaseLock() @@ -648,14 +637,12 @@ export class ContributionResolver { contributionToUpdate.deniedBy = moderator.id contributionToUpdate.deniedAt = new Date() const res = await contributionToUpdate.save() - await EVENT_ADMIN_CONTRIBUTION_DENY( user, moderator, contributionToUpdate, contributionToUpdate.amount, ) - sendContributionDeniedEmail({ firstName: user.firstName, lastName: user.lastName, From 9493ed58d94e4ea7dd9d65290caebab30a8158ef Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 7 Mar 2023 21:38:17 +0100 Subject: [PATCH 18/49] events for transactionLinkResolver --- .../event/EVENT_CONTRIBUTION_LINK_REDEEM.ts | 27 +++++++++++++++++++ .../event/EVENT_TRANSACTION_LINK_CREATE.ts | 23 ++++++++++++++++ .../event/EVENT_TRANSACTION_LINK_DELETE.ts | 19 +++++++++++++ .../event/EVENT_TRANSACTION_LINK_REDEEM.ts | 24 +++++++++++++++++ backend/src/event/Event.ts | 4 +++ backend/src/event/EventType.ts | 4 +++ .../resolver/TransactionLinkResolver.ts | 23 +++++++++++++++- 7 files changed, 123 insertions(+), 1 deletion(-) create mode 100644 backend/src/event/EVENT_CONTRIBUTION_LINK_REDEEM.ts create mode 100644 backend/src/event/EVENT_TRANSACTION_LINK_CREATE.ts create mode 100644 backend/src/event/EVENT_TRANSACTION_LINK_DELETE.ts create mode 100644 backend/src/event/EVENT_TRANSACTION_LINK_REDEEM.ts diff --git a/backend/src/event/EVENT_CONTRIBUTION_LINK_REDEEM.ts b/backend/src/event/EVENT_CONTRIBUTION_LINK_REDEEM.ts new file mode 100644 index 000000000..395772ac9 --- /dev/null +++ b/backend/src/event/EVENT_CONTRIBUTION_LINK_REDEEM.ts @@ -0,0 +1,27 @@ +import Decimal from 'decimal.js-light' +import { User as DbUser } from '@entity/User' +import { Transaction as DbTransaction } from '@entity/Transaction' +import { Contribution as DbContribution } from '@entity/Contribution' +import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' +import { Event as DbEvent } from '@entity/Event' +import { Event, EventType } from './Event' + +export const EVENT_CONTRIBUTION_LINK_REDEEM = async ( + user: DbUser, + transaction: DbTransaction, + contribution: DbContribution, + contributionLink: DbContributionLink, + amount: Decimal, +): Promise => + Event( + EventType.CONTRIBUTION_LINK_REDEEM, + user, + user, + null, + transaction, + contribution, + null, + null, + contributionLink, + amount, + ).save() diff --git a/backend/src/event/EVENT_TRANSACTION_LINK_CREATE.ts b/backend/src/event/EVENT_TRANSACTION_LINK_CREATE.ts new file mode 100644 index 000000000..36fdb3ff0 --- /dev/null +++ b/backend/src/event/EVENT_TRANSACTION_LINK_CREATE.ts @@ -0,0 +1,23 @@ +import Decimal from 'decimal.js-light' +import { User as DbUser } from '@entity/User' +import { TransactionLink as DbTransactionLink } from '@entity/TransactionLink' +import { Event as DbEvent } from '@entity/Event' +import { Event, EventType } from './Event' + +export const EVENT_TRANSACTION_LINK_CREATE = async ( + user: DbUser, + transactionLink: DbTransactionLink, + amount: Decimal, +): Promise => + Event( + EventType.TRANSACTION_LINK_CREATE, + user, + user, + null, + null, + null, + null, + transactionLink, + null, + amount, + ).save() diff --git a/backend/src/event/EVENT_TRANSACTION_LINK_DELETE.ts b/backend/src/event/EVENT_TRANSACTION_LINK_DELETE.ts new file mode 100644 index 000000000..d15c786a8 --- /dev/null +++ b/backend/src/event/EVENT_TRANSACTION_LINK_DELETE.ts @@ -0,0 +1,19 @@ +import { User as DbUser } from '@entity/User' +import { TransactionLink as DbTransactionLink } from '@entity/TransactionLink' +import { Event as DbEvent } from '@entity/Event' +import { Event, EventType } from './Event' + +export const EVENT_TRANSACTION_LINK_DELETE = async ( + user: DbUser, + transactionLink: DbTransactionLink, +): Promise => + Event( + EventType.TRANSACTION_LINK_DELETE, + user, + user, + null, + null, + null, + null, + transactionLink, + ).save() diff --git a/backend/src/event/EVENT_TRANSACTION_LINK_REDEEM.ts b/backend/src/event/EVENT_TRANSACTION_LINK_REDEEM.ts new file mode 100644 index 000000000..58307a4e1 --- /dev/null +++ b/backend/src/event/EVENT_TRANSACTION_LINK_REDEEM.ts @@ -0,0 +1,24 @@ +import Decimal from 'decimal.js-light' +import { User as DbUser } from '@entity/User' +import { TransactionLink as DbTransactionLink } from '@entity/TransactionLink' +import { Event as DbEvent } from '@entity/Event' +import { Event, EventType } from './Event' + +export const EVENT_TRANSACTION_LINK_REDEEM = async ( + user: DbUser, + senderUser: DbUser, + transactionLink: DbTransactionLink, + amount: Decimal, +): Promise => + Event( + EventType.TRANSACTION_LINK_REDEEM, + user, + user, + senderUser, + null, + null, + null, + transactionLink, + null, + amount, + ).save() diff --git a/backend/src/event/Event.ts b/backend/src/event/Event.ts index f1c4269c9..cdb05748c 100644 --- a/backend/src/event/Event.ts +++ b/backend/src/event/Event.ts @@ -51,9 +51,13 @@ export { EVENT_CONTRIBUTION_CREATE } from './EVENT_CONTRIBUTION_CREATE' export { EVENT_CONTRIBUTION_DELETE } from './EVENT_CONTRIBUTION_DELETE' export { EVENT_CONTRIBUTION_UPDATE } from './EVENT_CONTRIBUTION_UPDATE' export { EVENT_CONTRIBUTION_MESSAGE_CREATE } from './EVENT_CONTRIBUTION_MESSAGE_CREATE' +export { EVENT_CONTRIBUTION_LINK_REDEEM } from './EVENT_CONTRIBUTION_LINK_REDEEM' export { EVENT_LOGIN } from './EVENT_LOGIN' export { EVENT_REGISTER } from './EVENT_REGISTER' export { EVENT_SEND_ACCOUNT_MULTIREGISTRATION_EMAIL } from './EVENT_SEND_ACCOUNT_MULTIREGISTRATION_EMAIL' export { EVENT_SEND_CONFIRMATION_EMAIL } from './EVENT_SEND_CONFIRMATION_EMAIL' export { EVENT_TRANSACTION_SEND } from './EVENT_TRANSACTION_SEND' export { EVENT_TRANSACTION_RECEIVE } from './EVENT_TRANSACTION_RECEIVE' +export { EVENT_TRANSACTION_LINK_CREATE } from './EVENT_TRANSACTION_LINK_CREATE' +export { EVENT_TRANSACTION_LINK_DELETE } from './EVENT_TRANSACTION_LINK_DELETE' +export { EVENT_TRANSACTION_LINK_REDEEM } from './EVENT_TRANSACTION_LINK_REDEEM' diff --git a/backend/src/event/EventType.ts b/backend/src/event/EventType.ts index dda571b5a..47056f05e 100644 --- a/backend/src/event/EventType.ts +++ b/backend/src/event/EventType.ts @@ -15,6 +15,7 @@ export enum EventType { CONTRIBUTION_DELETE = 'CONTRIBUTION_DELETE', CONTRIBUTION_UPDATE = 'CONTRIBUTION_UPDATE', CONTRIBUTION_MESSAGE_CREATE = 'CONTRIBUTION_MESSAGE_CREATE', + CONTRIBUTION_LINK_REDEEM = 'CONTRIBUTION_LINK_REDEEM', LOGIN = 'LOGIN', REGISTER = 'REGISTER', REDEEM_REGISTER = 'REDEEM_REGISTER', @@ -22,6 +23,9 @@ export enum EventType { SEND_CONFIRMATION_EMAIL = 'SEND_CONFIRMATION_EMAIL', TRANSACTION_SEND = 'TRANSACTION_SEND', TRANSACTION_RECEIVE = 'TRANSACTION_RECEIVE', + TRANSACTION_LINK_CREATE = 'TRANSACTION_LINK_CREATE', + TRANSACTION_LINK_DELETE = 'TRANSACTION_LINK_DELETE', + TRANSACTION_LINK_REDEEM = 'TRANSACTION_LINK_REDEEM', // VISIT_GRADIDO = 'VISIT_GRADIDO', // VERIFY_REDEEM = 'VERIFY_REDEEM', // INACTIVE_ACCOUNT = 'INACTIVE_ACCOUNT', diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.ts b/backend/src/graphql/resolver/TransactionLinkResolver.ts index 66d0fbb4b..c8539510e 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.ts @@ -35,6 +35,12 @@ import LogError from '@/server/LogError' import { getLastTransaction } from './util/getLastTransaction' import transactionLinkList from './util/transactionLinkList' +import { + EVENT_CONTRIBUTION_LINK_REDEEM, + EVENT_TRANSACTION_LINK_CREATE, + EVENT_TRANSACTION_LINK_DELETE, + EVENT_TRANSACTION_LINK_REDEEM, +} from '@/event/Event' // TODO: do not export, test it inside the resolver export const transactionLinkCode = (date: Date): string => { @@ -89,6 +95,7 @@ export class TransactionLinkResolver { await DbTransactionLink.save(transactionLink).catch((e) => { throw new LogError('Unable to save transaction link', e) }) + await EVENT_TRANSACTION_LINK_CREATE(user, transactionLink, amount) return new TransactionLink(transactionLink, new User(user)) } @@ -122,6 +129,8 @@ export class TransactionLinkResolver { throw new LogError('Transaction link could not be deleted', e) }) + await EVENT_TRANSACTION_LINK_DELETE(user, transactionLink) + return true } @@ -272,7 +281,13 @@ export class TransactionLinkResolver { await queryRunner.manager.update(DbContribution, { id: contribution.id }, contribution) await queryRunner.commitTransaction() - logger.info('creation from contribution link commited successfuly.') + await EVENT_CONTRIBUTION_LINK_REDEEM( + user, + transaction, + contribution, + contributionLink, + contributionLink.amount, + ) } catch (e) { await queryRunner.rollbackTransaction() throw new LogError('Creation from contribution link was not successful', e) @@ -313,6 +328,12 @@ export class TransactionLinkResolver { user, transactionLink, ) + await EVENT_TRANSACTION_LINK_REDEEM( + user, + { id: transactionLink.userId } as DbUser, + transactionLink, + transactionLink.amount, + ) return true } From 09c5aff33e65fc0b5d0f0c2941a90b95f92818b7 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Thu, 9 Mar 2023 12:40:29 +0100 Subject: [PATCH 19/49] test contribution link redeem --- .../resolver/TransactionLinkResolver.test.ts | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.test.ts b/backend/src/graphql/resolver/TransactionLinkResolver.test.ts index 60b4551be..14065a9f4 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.test.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.test.ts @@ -26,6 +26,9 @@ import Decimal from 'decimal.js-light' import { GraphQLError } from 'graphql' import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK' import { logger } from '@test/testSetup' +import { EventType } from '@/event/Event' +import { Event as DbEvent } from '@entity/Event' +import { UserContact } from '@entity/UserContact' // mock semaphore to allow use fake timers jest.mock('@/util/TRANSACTIONS_LOCK') @@ -432,6 +435,24 @@ describe('TransactionLinkResolver', () => { }) }) + it('stores the CONTRIBUTION_LINK_REDEEM event in the database', async () => { + const userConatct = await UserContact.findOneOrFail( + { email: 'bibi@bloxberg.de' }, + { relations: ['user'] }, + ) + expect(DbEvent.find()).resolves.toContainEqual( + expect.objectContaining({ + type: EventType.CONTRIBUTION_LINK_REDEEM, + affectedUserId: userConatct.user.id, + actingUserId: userConatct.user.id, + involvedTransactionId: expect.any(Number), + involvedContributionId: expect.any(Number), + involvedContributionLinkId: contributionLink?.id, + amount: contributionLink?.amount, + }), + ) + }) + it('does not allow the user to redeem the contribution link a second time on the same day', async () => { jest.clearAllMocks() await expect( From c8b9de35d8b6bf0c070a72b36e0d543e33d15f9f Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Fri, 10 Mar 2023 13:08:57 +0100 Subject: [PATCH 20/49] eslint-plugin-jest --- backend/.eslintrc.js | 8 ++++++- backend/package.json | 1 + backend/yarn.lock | 55 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/backend/.eslintrc.js b/backend/.eslintrc.js index 096e4d60a..5eafeffa3 100644 --- a/backend/.eslintrc.js +++ b/backend/.eslintrc.js @@ -4,7 +4,7 @@ module.exports = { node: true, }, parser: '@typescript-eslint/parser', - plugins: ['prettier', '@typescript-eslint', 'type-graphql'], + plugins: ['prettier', '@typescript-eslint', 'type-graphql', 'jest'], extends: ['standard', 'eslint:recommended', 'plugin:prettier/recommended'], // add your custom rules here rules: { @@ -16,6 +16,12 @@ module.exports = { htmlWhitespaceSensitivity: 'ignore', }, ], + // jest + 'jest/no-disabled-tests': 'off', // TODO + 'jest/no-focused-tests': 'error', + 'jest/no-identical-title': 'error', + 'jest/prefer-to-have-length': 'warn', + 'jest/valid-expect': 'error', }, overrides: [ // only for ts files diff --git a/backend/package.json b/backend/package.json index dab5e50af..69cb26c93 100644 --- a/backend/package.json +++ b/backend/package.json @@ -62,6 +62,7 @@ "eslint-config-prettier": "^8.3.0", "eslint-config-standard": "^16.0.3", "eslint-plugin-import": "^2.23.4", + "eslint-plugin-jest": "^27.2.1", "eslint-plugin-node": "^11.1.0", "eslint-plugin-prettier": "^3.4.0", "eslint-plugin-promise": "^5.1.0", diff --git a/backend/yarn.lock b/backend/yarn.lock index 3151557ab..7d896258f 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -1239,6 +1239,14 @@ "@typescript-eslint/types" "5.53.0" "@typescript-eslint/visitor-keys" "5.53.0" +"@typescript-eslint/scope-manager@5.54.1": + version "5.54.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.54.1.tgz#6d864b4915741c608a58ce9912edf5a02bb58735" + integrity sha512-zWKuGliXxvuxyM71UA/EcPxaviw39dB2504LqAmFDjmkpO8qNLHcmzlh6pbHs1h/7YQ9bnsO8CCcYCSA8sykUg== + dependencies: + "@typescript-eslint/types" "5.54.1" + "@typescript-eslint/visitor-keys" "5.54.1" + "@typescript-eslint/types@4.33.0": version "4.33.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.33.0.tgz#a1e59036a3b53ae8430ceebf2a919dc7f9af6d72" @@ -1249,6 +1257,11 @@ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.53.0.tgz#f79eca62b97e518ee124086a21a24f3be267026f" integrity sha512-5kcDL9ZUIP756K6+QOAfPkigJmCPHcLN7Zjdz76lQWWDdzfOhZDTj1irs6gPBKiXx5/6O3L0+AvupAut3z7D2A== +"@typescript-eslint/types@5.54.1": + version "5.54.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.54.1.tgz#29fbac29a716d0f08c62fe5de70c9b6735de215c" + integrity sha512-G9+1vVazrfAfbtmCapJX8jRo2E4MDXxgm/IMOF4oGh3kq7XuK3JRkOg6y2Qu1VsTRmWETyTkWt1wxy7X7/yLkw== + "@typescript-eslint/typescript-estree@4.33.0": version "4.33.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz#0dfb51c2908f68c5c08d82aefeaf166a17c24609" @@ -1275,6 +1288,19 @@ semver "^7.3.7" tsutils "^3.21.0" +"@typescript-eslint/typescript-estree@5.54.1": + version "5.54.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.54.1.tgz#df7b6ae05fd8fef724a87afa7e2f57fa4a599be1" + integrity sha512-bjK5t+S6ffHnVwA0qRPTZrxKSaFYocwFIkZx5k7pvWfsB1I57pO/0M0Skatzzw1sCkjJ83AfGTL0oFIFiDX3bg== + dependencies: + "@typescript-eslint/types" "5.54.1" + "@typescript-eslint/visitor-keys" "5.54.1" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.3.7" + tsutils "^3.21.0" + "@typescript-eslint/utils@5.53.0": version "5.53.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.53.0.tgz#e55eaad9d6fffa120575ffaa530c7e802f13bce8" @@ -1289,6 +1315,20 @@ eslint-utils "^3.0.0" semver "^7.3.7" +"@typescript-eslint/utils@^5.10.0": + version "5.54.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.54.1.tgz#7a3ee47409285387b9d4609ea7e1020d1797ec34" + integrity sha512-IY5dyQM8XD1zfDe5X8jegX6r2EVU5o/WJnLu/znLPWCBF7KNGC+adacXnt5jEYS9JixDcoccI6CvE4RCjHMzCQ== + dependencies: + "@types/json-schema" "^7.0.9" + "@types/semver" "^7.3.12" + "@typescript-eslint/scope-manager" "5.54.1" + "@typescript-eslint/types" "5.54.1" + "@typescript-eslint/typescript-estree" "5.54.1" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + semver "^7.3.7" + "@typescript-eslint/visitor-keys@4.33.0": version "4.33.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz#2a22f77a41604289b7a186586e9ec48ca92ef1dd" @@ -1305,6 +1345,14 @@ "@typescript-eslint/types" "5.53.0" eslint-visitor-keys "^3.3.0" +"@typescript-eslint/visitor-keys@5.54.1": + version "5.54.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.54.1.tgz#d7a8a0f7181d6ac748f4d47b2306e0513b98bf8b" + integrity sha512-q8iSoHTgwCfgcRJ2l2x+xCbu8nBlRAlsQ33k24Adj8eoVBE0f8dUeI+bAa8F84Mv05UGbAx57g2zrRsYIooqQg== + dependencies: + "@typescript-eslint/types" "5.54.1" + eslint-visitor-keys "^3.3.0" + "@wry/equality@^0.1.2": version "0.1.11" resolved "https://registry.yarnpkg.com/@wry/equality/-/equality-0.1.11.tgz#35cb156e4a96695aa81a9ecc4d03787bc17f1790" @@ -2714,6 +2762,13 @@ eslint-plugin-import@^2.23.4: resolve "^1.20.0" tsconfig-paths "^3.11.0" +eslint-plugin-jest@^27.2.1: + version "27.2.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-27.2.1.tgz#b85b4adf41c682ea29f1f01c8b11ccc39b5c672c" + integrity sha512-l067Uxx7ZT8cO9NJuf+eJHvt6bqJyz2Z29wykyEdz/OtmcELQl2MQGQLX8J94O1cSJWAwUSEvCjwjA7KEK3Hmg== + dependencies: + "@typescript-eslint/utils" "^5.10.0" + eslint-plugin-node@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz#c95544416ee4ada26740a30474eefc5402dc671d" From 04a87be90d7c8f3621fb3f89b82c75d9dea3ba6e Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Fri, 10 Mar 2023 13:09:35 +0100 Subject: [PATCH 21/49] fix eslint jest errors --- .../resolver/ContributionLinkResolver.test.ts | 20 +++--- .../ContributionMessageResolver.test.ts | 8 +-- .../resolver/ContributionResolver.test.ts | 72 +++++++++---------- .../resolver/TransactionLinkResolver.test.ts | 22 +++--- 4 files changed, 61 insertions(+), 61 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionLinkResolver.test.ts b/backend/src/graphql/resolver/ContributionLinkResolver.test.ts index 4563d2a6a..606bce109 100644 --- a/backend/src/graphql/resolver/ContributionLinkResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionLinkResolver.test.ts @@ -266,7 +266,7 @@ describe('Contribution Links', () => { ) }) - it('logs the error thrown', () => { + it('logs the error "A Start-Date must be set"', () => { expect(logger.error).toBeCalledWith('A Start-Date must be set') }) @@ -287,7 +287,7 @@ describe('Contribution Links', () => { ) }) - it('logs the error thrown', () => { + it('logs the error "An End-Date must be set"', () => { expect(logger.error).toBeCalledWith('An End-Date must be set') }) @@ -311,7 +311,7 @@ describe('Contribution Links', () => { ) }) - it('logs the error thrown', () => { + it('logs the error "The value of validFrom must before or equals the validTo"', () => { expect(logger.error).toBeCalledWith( `The value of validFrom must before or equals the validTo`, ) @@ -334,7 +334,7 @@ describe('Contribution Links', () => { ) }) - it('logs the error thrown', () => { + it('logs the error "The value of name is too short"', () => { expect(logger.error).toBeCalledWith('The value of name is too short', 3) }) @@ -355,7 +355,7 @@ describe('Contribution Links', () => { ) }) - it('logs the error thrown', () => { + it('logs the error "The value of name is too long"', () => { expect(logger.error).toBeCalledWith('The value of name is too long', 101) }) @@ -376,7 +376,7 @@ describe('Contribution Links', () => { ) }) - it('logs the error thrown', () => { + it('logs the error "The value of memo is too short"', () => { expect(logger.error).toBeCalledWith('The value of memo is too short', 3) }) @@ -397,7 +397,7 @@ describe('Contribution Links', () => { ) }) - it('logs the error thrown', () => { + it('logs the error "The value of memo is too long"', () => { expect(logger.error).toBeCalledWith('The value of memo is too long', 256) }) @@ -418,7 +418,7 @@ describe('Contribution Links', () => { ) }) - it('logs the error thrown', () => { + it('logs the error "The amount must be a positiv value"', () => { expect(logger.error).toBeCalledWith('The amount must be a positiv value', new Decimal(0)) }) }) @@ -476,7 +476,7 @@ describe('Contribution Links', () => { }) }) - it('logs the error thrown', () => { + it('logs the error "Contribution Link not found"', () => { expect(logger.error).toBeCalledWith('Contribution Link not found', -1) }) @@ -546,7 +546,7 @@ describe('Contribution Links', () => { ) }) - it('logs the error thrown', () => { + it('logs the error "Contribution Link not found"', () => { expect(logger.error).toBeCalledWith('Contribution Link not found', -1) }) }) diff --git a/backend/src/graphql/resolver/ContributionMessageResolver.test.ts b/backend/src/graphql/resolver/ContributionMessageResolver.test.ts index 8b5c5a0a7..642844e31 100644 --- a/backend/src/graphql/resolver/ContributionMessageResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionMessageResolver.test.ts @@ -113,7 +113,7 @@ describe('ContributionMessageResolver', () => { ) }) - it('logs the error thrown', () => { + it('logs the error "ContributionMessage was not sent successfully: Error: Contribution not found"', () => { expect(logger.error).toBeCalledWith( 'ContributionMessage was not sent successfully: Error: Contribution not found', new Error('Contribution not found'), @@ -153,7 +153,7 @@ describe('ContributionMessageResolver', () => { ) }) - it('logs the error thrown', () => { + it('logs the error "ContributionMessage was not sent successfully: Error: Admin can not answer on his own contribution"', () => { expect(logger.error).toBeCalledWith( 'ContributionMessage was not sent successfully: Error: Admin can not answer on his own contribution', new Error('Admin can not answer on his own contribution'), @@ -251,7 +251,7 @@ describe('ContributionMessageResolver', () => { ) }) - it('logs the error thrown', () => { + it('logs the error "ContributionMessage was not sent successfully: Error: Contribution not found"', () => { expect(logger.error).toBeCalledWith( 'ContributionMessage was not sent successfully: Error: Contribution not found', new Error('Contribution not found'), @@ -283,7 +283,7 @@ describe('ContributionMessageResolver', () => { ) }) - it('logs the error thrown', () => { + it('logs the error "ContributionMessage was not sent successfully: Error: Can not send message to contribution of another user"', () => { expect(logger.error).toBeCalledWith( 'ContributionMessage was not sent successfully: Error: Can not send message to contribution of another user', new Error('Can not send message to contribution of another user'), diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index 274067ba0..cc7357e99 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -201,7 +201,7 @@ describe('ContributionResolver', () => { expect(errorObjects).toEqual([new GraphQLError('Memo text is too short')]) }) - it('logs the error found', () => { + it('logs the error "Memo text is too short"', () => { expect(logger.error).toBeCalledWith('Memo text is too short', 4) }) @@ -219,7 +219,7 @@ describe('ContributionResolver', () => { expect(errorObjects).toEqual([new GraphQLError('Memo text is too long')]) }) - it('logs the error found', () => { + it('logs the error "Memo text is too long"', () => { expect(logger.error).toBeCalledWith('Memo text is too long', 259) }) @@ -238,7 +238,7 @@ describe('ContributionResolver', () => { ]) }) - it('logs the error found', () => { + it('logs the error "No information for available creations for the given date"', () => { expect(logger.error).toBeCalledWith( 'No information for available creations for the given date', expect.any(Date), @@ -261,7 +261,7 @@ describe('ContributionResolver', () => { ]) }) - it('logs the error found', () => { + it('logs the error "No information for available creations for the given date" again', () => { expect(logger.error).toBeCalledWith( 'No information for available creations for the given date', expect.any(Date), @@ -336,7 +336,7 @@ describe('ContributionResolver', () => { expect(errorObjects).toEqual([new GraphQLError('Memo text is too short')]) }) - it('logs the error found', () => { + it('logs the error "Memo text is too short"', () => { expect(logger.error).toBeCalledWith('Memo text is too short', 4) }) }) @@ -357,7 +357,7 @@ describe('ContributionResolver', () => { expect(errorObjects).toEqual([new GraphQLError('Memo text is too long')]) }) - it('logs the error found', () => { + it('logs the error "Memo text is too long"', () => { expect(logger.error).toBeCalledWith('Memo text is too long', 259) }) }) @@ -382,7 +382,7 @@ describe('ContributionResolver', () => { ) }) - it('logs the error found', () => { + it('logs the error "Contribution not found"', () => { expect(logger.error).toBeCalledWith('Contribution not found', -1) }) }) @@ -411,7 +411,7 @@ describe('ContributionResolver', () => { ]) }) - it('logs the error found', () => { + it('logs the error "Can not update contribution of another user"', () => { expect(logger.error).toBeCalledWith( 'Can not update contribution of another user', expect.any(Object), @@ -445,7 +445,7 @@ describe('ContributionResolver', () => { ]) }) - it('logs the error found', () => { + it('logs the error "An admin is not allowed to update an user contribution"', () => { expect(logger.error).toBeCalledWith( 'An admin is not allowed to update an user contribution', ) @@ -491,7 +491,7 @@ describe('ContributionResolver', () => { ) }) - it('logs the error found', () => { + it('logs the error "Contribution can not be updated due to status"', () => { expect(logger.error).toBeCalledWith( 'Contribution can not be updated due to status', ContributionStatus.DELETED, @@ -526,7 +526,7 @@ describe('ContributionResolver', () => { ]) }) - it('logs the error found', () => { + it('logs the error "The amount to be created exceeds the amount still available for this month"', () => { expect(logger.error).toBeCalledWith( 'The amount to be created exceeds the amount still available for this month', new Decimal(1019), @@ -553,7 +553,7 @@ describe('ContributionResolver', () => { ]) }) - it('logs the error found', () => { + it('logs the error "Month of contribution can not be changed"', () => { expect(logger.error).toBeCalledWith('Month of contribution can not be changed') }) }) @@ -657,7 +657,7 @@ describe('ContributionResolver', () => { expect(errorObjects).toEqual([new GraphQLError('Contribution not found')]) }) - it('logs the error found', () => { + it('logs the error "Contribution not found"', () => { expect(logger.error).toBeCalledWith('Contribution not found', -1) }) }) @@ -701,7 +701,7 @@ describe('ContributionResolver', () => { expect(errorObjects).toEqual([new GraphQLError('Contribution not found')]) }) - it('logs the error found', () => { + it('logs the error "Contribution not found"', () => { expect(logger.error).toBeCalledWith('Contribution not found', expect.any(Number)) }) }) @@ -746,7 +746,7 @@ describe('ContributionResolver', () => { expect(errorObjects).toEqual([new GraphQLError('Contribution not found')]) }) - it('logs the error found', () => { + it('logs the error "Contribution not found"', () => { expect(logger.error).toBeCalledWith(`Contribution not found`, expect.any(Number)) }) }) @@ -791,7 +791,7 @@ describe('ContributionResolver', () => { expect(errorObjects).toEqual([new GraphQLError('Contribution not found')]) }) - it('logs the error found', () => { + it('logs the error "Contribution not found"', () => { expect(logger.error).toBeCalledWith(`Contribution not found`, expect.any(Number)) }) }) @@ -877,7 +877,7 @@ describe('ContributionResolver', () => { expect(errorObjects).toEqual([new GraphQLError('Contribution not found')]) }) - it('logs the error found', () => { + it('logs the error "Contribution not found"', () => { expect(logger.error).toBeCalledWith('Contribution not found', expect.any(Number)) }) }) @@ -907,7 +907,7 @@ describe('ContributionResolver', () => { ]) }) - it('logs the error found', () => { + it('logs the error "Can not delete contribution of another user"', () => { expect(logger.error).toBeCalledWith( 'Can not delete contribution of another user', expect.any(Contribution), @@ -981,7 +981,7 @@ describe('ContributionResolver', () => { ]) }) - it('logs the error found', () => { + it('logs the error "A confirmed contribution can not be deleted"', () => { expect(logger.error).toBeCalledWith( 'A confirmed contribution can not be deleted', expect.objectContaining({ contributionStatus: 'CONFIRMED' }), @@ -1846,7 +1846,7 @@ describe('ContributionResolver', () => { ) }) - it('logs the error thrown', () => { + it('logs the error "Could not find user"', () => { expect(logger.error).toBeCalledWith('Could not find user', 'some@fake.email') }) }) @@ -1873,7 +1873,7 @@ describe('ContributionResolver', () => { ) }) - it('logs the error thrown', () => { + it('logs the error "Cannot create contribution since the user was deleted"', () => { expect(logger.error).toBeCalledWith( 'Cannot create contribution since the user was deleted', expect.objectContaining({ @@ -1909,7 +1909,7 @@ describe('ContributionResolver', () => { ) }) - it('logs the error thrown', () => { + it('logs the error "Cannot create contribution since the users email is not activated"', () => { expect(logger.error).toBeCalledWith( 'Cannot create contribution since the users email is not activated', expect.objectContaining({ emailChecked: false }), @@ -1935,7 +1935,7 @@ describe('ContributionResolver', () => { ) }) - it('logs the error thrown', () => { + it('logs the error "CreationDate is invalid"', () => { expect(logger.error).toBeCalledWith('CreationDate is invalid', 'invalid-date') }) }) @@ -1957,7 +1957,7 @@ describe('ContributionResolver', () => { ) }) - it('logs the error thrown', () => { + it('logs the error "No information for available creations for the given date"', () => { expect(logger.error).toBeCalledWith( 'No information for available creations for the given date', new Date(variables.creationDate), @@ -1982,7 +1982,7 @@ describe('ContributionResolver', () => { ) }) - it('logs the error thrown', () => { + it('logs the error "No information for available creations for the given date"', () => { expect(logger.error).toBeCalledWith( 'No information for available creations for the given date', new Date(variables.creationDate), @@ -2007,7 +2007,7 @@ describe('ContributionResolver', () => { ) }) - it('logs the error thrown', () => { + it('logs the error "The amount to be created exceeds the amount still available for this month"', () => { expect(logger.error).toBeCalledWith( 'The amount to be created exceeds the amount still available for this month', new Decimal(2000), @@ -2058,7 +2058,7 @@ describe('ContributionResolver', () => { ) }) - it('logs the error thrown', () => { + it('logs the error "The amount to be created exceeds the amount still available for this month"', () => { expect(logger.error).toBeCalledWith( 'The amount to be created exceeds the amount still available for this month', new Decimal(1000), @@ -2097,7 +2097,7 @@ describe('ContributionResolver', () => { ) }) - it('logs the error thrown', () => { + it('logs the error "Could not find User"', () => { expect(logger.error).toBeCalledWith('Could not find User', 'bob@baumeister.de') }) }) @@ -2123,7 +2123,7 @@ describe('ContributionResolver', () => { ) }) - it('logs the error thrown', () => { + it('logs the error "User was deleted"', () => { expect(logger.error).toBeCalledWith('User was deleted', 'stephen@hawking.uk') }) }) @@ -2149,7 +2149,7 @@ describe('ContributionResolver', () => { ) }) - it('logs the error thrown', () => { + it('logs the error "Contribution not found"', () => { expect(logger.error).toBeCalledWith('Contribution not found', -1) }) }) @@ -2181,7 +2181,7 @@ describe('ContributionResolver', () => { ) }) - it('logs the error thrown', () => { + it('logs the error "User of the pending contribution and send user does not correspond"', () => { expect(logger.error).toBeCalledWith( 'User of the pending contribution and send user does not correspond', ) @@ -2216,7 +2216,7 @@ describe('ContributionResolver', () => { ) }) - it('logs the error thrown', () => { + it('logs the error "The amount to be created exceeds the amount still available for this month"', () => { expect(logger.error).toBeCalledWith( 'The amount to be created exceeds the amount still available for this month', new Decimal(1900), @@ -2326,7 +2326,7 @@ describe('ContributionResolver', () => { ) }) - it('logs the error thrown', () => { + it('logs the error "Contribution not found"', () => { expect(logger.error).toBeCalledWith('Contribution not found', -1) }) }) @@ -2466,7 +2466,7 @@ describe('ContributionResolver', () => { ) }) - it('logs the error thrown', () => { + it('logs the error "Contribution not found"', () => { expect(logger.error).toBeCalledWith('Contribution not found', -1) }) }) @@ -2500,7 +2500,7 @@ describe('ContributionResolver', () => { ) }) - it('logs the error thrown', () => { + it('logs the error "Moderator can not confirm own contribution"', () => { expect(logger.error).toBeCalledWith('Moderator can not confirm own contribution') }) }) @@ -2595,7 +2595,7 @@ describe('ContributionResolver', () => { }) }) - it('logs the error thrown', () => { + it('logs the error "Contribution already confirmed"', () => { expect(logger.error).toBeCalledWith( 'Contribution already confirmed', expect.any(Number), diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.test.ts b/backend/src/graphql/resolver/TransactionLinkResolver.test.ts index fc5ca170a..c6b733d0d 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.test.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.test.ts @@ -94,7 +94,7 @@ describe('TransactionLinkResolver', () => { errors: [new GraphQLError('Amount must be a positive number')], }) }) - it('logs the error thrown', () => { + it('logs the error "Amount must be a positive number" - 0', () => { expect(logger.error).toBeCalledWith('Amount must be a positive number', new Decimal(0)) }) @@ -112,7 +112,7 @@ describe('TransactionLinkResolver', () => { errors: [new GraphQLError('Amount must be a positive number')], }) }) - it('logs the error thrown', () => { + it('logs the error "Amount must be a positive number" - -10', () => { expect(logger.error).toBeCalledWith('Amount must be a positive number', new Decimal(-10)) }) @@ -130,7 +130,7 @@ describe('TransactionLinkResolver', () => { errors: [new GraphQLError('User has not enough GDD')], }) }) - it('logs the error thrown', () => { + it('logs the error "User has not enough GDD"', () => { expect(logger.error).toBeCalledWith('User has not enough GDD', expect.any(Number)) }) }) @@ -180,7 +180,7 @@ describe('TransactionLinkResolver', () => { }) }) - it('logs the error thrown', () => { + it('logs the error "No contribution link found to given code"', () => { expect(logger.error).toBeCalledWith( 'No contribution link found to given code', 'CL-123456', @@ -224,7 +224,7 @@ describe('TransactionLinkResolver', () => { await resetEntity(DbContributionLink) }) - it('logs the error thrown', () => { + it('logs the error "Contribution link is not valid yet"', () => { expect(logger.error).toBeCalledWith('Contribution link is not valid yet', validFrom) expect(logger.error).toBeCalledWith( 'Creation from contribution link was not successful', @@ -263,7 +263,7 @@ describe('TransactionLinkResolver', () => { await resetEntity(DbContributionLink) }) - it('logs the error thrown', () => { + it('logs the error "Contribution link has unknown cycle"', () => { expect(logger.error).toBeCalledWith('Contribution link has unknown cycle', 'INVALID') expect(logger.error).toBeCalledWith( 'Creation from contribution link was not successful', @@ -302,7 +302,7 @@ describe('TransactionLinkResolver', () => { await resetEntity(DbContributionLink) }) - it('logs the error thrown', () => { + it('logs the error "Contribution link is no longer valid"', () => { expect(logger.error).toBeCalledWith('Contribution link is no longer valid', validTo) expect(logger.error).toBeCalledWith( 'Creation from contribution link was not successful', @@ -394,7 +394,7 @@ describe('TransactionLinkResolver', () => { }) }) - it('logs the error thrown', () => { + it('logs the error "Creation from contribution link was not successful"', () => { expect(logger.error).toBeCalledWith( 'Creation from contribution link was not successful', new Error( @@ -451,7 +451,7 @@ describe('TransactionLinkResolver', () => { }) }) - it('logs the error thrown', () => { + it('logs the error "Creation from contribution link was not successful"', () => { expect(logger.error).toBeCalledWith( 'Creation from contribution link was not successful', new Error('Contribution link already redeemed today'), @@ -503,7 +503,7 @@ describe('TransactionLinkResolver', () => { }) }) - it('logs the error thrown', () => { + it('logs the error "Creation from contribution link was not successful"', () => { expect(logger.error).toBeCalledWith( 'Creation from contribution link was not successful', new Error('Contribution link already redeemed today'), @@ -620,7 +620,7 @@ describe('TransactionLinkResolver', () => { }) }) - it('logs the error thrown', () => { + it('logs the error "Could not find requested User"', () => { expect(logger.error).toBeCalledWith('Could not find requested User', -1) }) }) From b6f903374e3b588b815634041f7c1ec129f24917 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Fri, 10 Mar 2023 14:12:46 +0100 Subject: [PATCH 22/49] also match tsx files, fix semaphore lint ignore --- backend/.eslintrc.js | 3 ++- backend/src/graphql/resolver/semaphore.test.ts | 2 -- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/backend/.eslintrc.js b/backend/.eslintrc.js index 5eafeffa3..bc2f0a43d 100644 --- a/backend/.eslintrc.js +++ b/backend/.eslintrc.js @@ -2,6 +2,7 @@ module.exports = { root: true, env: { node: true, + // jest: true, }, parser: '@typescript-eslint/parser', plugins: ['prettier', '@typescript-eslint', 'type-graphql', 'jest'], @@ -26,7 +27,7 @@ module.exports = { overrides: [ // only for ts files { - files: ['*.ts'], + files: ['*.ts', '*.tsx'], extends: [ 'plugin:@typescript-eslint/recommended', 'plugin:@typescript-eslint/recommended-requiring-type-checking', diff --git a/backend/src/graphql/resolver/semaphore.test.ts b/backend/src/graphql/resolver/semaphore.test.ts index 70e3e5f96..1ce133fba 100644 --- a/backend/src/graphql/resolver/semaphore.test.ts +++ b/backend/src/graphql/resolver/semaphore.test.ts @@ -5,8 +5,6 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import Decimal from 'decimal.js-light' -// eslint-disable-next-line @typescript-eslint/no-unused-vars -import { logger } from '@test/testSetup' import { userFactory } from '@/seeds/factory/user' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { bobBaumeister } from '@/seeds/users/bob-baumeister' From 7345ebb386146269b3b206626cb725845f3d65ec Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Fri, 10 Mar 2023 14:28:04 +0100 Subject: [PATCH 23/49] jest env not needed --- backend/.eslintrc.js | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/.eslintrc.js b/backend/.eslintrc.js index bc2f0a43d..0085e695b 100644 --- a/backend/.eslintrc.js +++ b/backend/.eslintrc.js @@ -2,7 +2,6 @@ module.exports = { root: true, env: { node: true, - // jest: true, }, parser: '@typescript-eslint/parser', plugins: ['prettier', '@typescript-eslint', 'type-graphql', 'jest'], From 193da5fd0f4d085dbc11c5a8b624f0f2382ac75e Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Sun, 12 Mar 2023 02:11:54 +0100 Subject: [PATCH 24/49] update config --- backend/.eslintrc.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/.eslintrc.js b/backend/.eslintrc.js index 0085e695b..6ce43ef35 100644 --- a/backend/.eslintrc.js +++ b/backend/.eslintrc.js @@ -17,10 +17,10 @@ module.exports = { }, ], // jest - 'jest/no-disabled-tests': 'off', // TODO + 'jest/no-disabled-tests': 'error', 'jest/no-focused-tests': 'error', 'jest/no-identical-title': 'error', - 'jest/prefer-to-have-length': 'warn', + 'jest/prefer-to-have-length': 'error', 'jest/valid-expect': 'error', }, overrides: [ From 62411198852240bb2029d55ab83e57334e6c7380 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Sun, 12 Mar 2023 02:18:13 +0100 Subject: [PATCH 25/49] fix skip tests --- backend/src/emails/sendEmailTranslated.test.ts | 2 ++ backend/src/graphql/resolver/ContributionResolver.test.ts | 1 + backend/src/graphql/resolver/TransactionLinkResolver.test.ts | 1 + backend/src/graphql/resolver/UserResolver.test.ts | 1 + backend/src/util/decay.test.ts | 1 + 5 files changed, 6 insertions(+) diff --git a/backend/src/emails/sendEmailTranslated.test.ts b/backend/src/emails/sendEmailTranslated.test.ts index f3c75a7a6..73edb79f3 100644 --- a/backend/src/emails/sendEmailTranslated.test.ts +++ b/backend/src/emails/sendEmailTranslated.test.ts @@ -102,10 +102,12 @@ describe('sendEmailTranslated', () => { }) }) + // eslint-disable-next-line jest/no-disabled-tests it.skip('calls "i18n.setLocale" with "en"', () => { expect(i18n.setLocale).toBeCalledWith('en') }) + // eslint-disable-next-line jest/no-disabled-tests it.skip('calls "i18n.__" for translation', () => { expect(i18n.__).toBeCalled() }) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index cc7357e99..a15c64e85 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -2225,6 +2225,7 @@ describe('ContributionResolver', () => { }) }) + // eslint-disable-next-line jest/no-disabled-tests describe.skip('creation update is successful changing month', () => { // skipped as changing the month is currently disable it('returns update creation object', async () => { diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.test.ts b/backend/src/graphql/resolver/TransactionLinkResolver.test.ts index c6b733d0d..35d3f42f6 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.test.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.test.ts @@ -759,6 +759,7 @@ describe('TransactionLinkResolver', () => { }) // TODO: works not as expected, because 'redeemedAt' and 'redeemedBy' have to be added to the transaktion link factory + // eslint-disable-next-line jest/no-disabled-tests describe.skip('filter by redeemed', () => { it('finds 6 open transaction links, 1 deleted, and no redeemed', async () => { await expect( diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index a57346583..083badc30 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -789,6 +789,7 @@ describe('UserResolver', () => { }) }) + // eslint-disable-next-line jest/no-disabled-tests describe.skip('user is in database but password is not set', () => { beforeAll(async () => { jest.clearAllMocks() diff --git a/backend/src/util/decay.test.ts b/backend/src/util/decay.test.ts index cf00ec851..0e7b02f56 100644 --- a/backend/src/util/decay.test.ts +++ b/backend/src/util/decay.test.ts @@ -16,6 +16,7 @@ describe('utils/decay', () => { expect(decayFormula(amount, seconds).toString()).toBe('1.000000021964959992727444') }) // we get pretty close, but not exact here, skipping + // eslint-disable-next-line jest/no-disabled-tests it.skip('has correct forward calculation', () => { const amount = new Decimal(1.0).div( new Decimal('0.99999997803504048973201202316767079413460520837376'), From 90d9b2114ec02ccf4c8911e3f2ca87b6a0a9a988 Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 24 Mar 2023 00:38:19 +0100 Subject: [PATCH 26/49] refactor(backend): add klicktipp-api library --- backend/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/package.json b/backend/package.json index 22e75f4af..19427091b 100644 --- a/backend/package.json +++ b/backend/package.json @@ -68,6 +68,7 @@ "eslint-plugin-type-graphql": "^1.0.0", "faker": "^5.5.3", "jest": "^27.2.4", + "klicktipp-api": "^1.0.2", "nodemon": "^2.0.7", "prettier": "^2.3.1", "ts-jest": "^27.0.5", From 34f96eb284ab5c7401d6d139de82ffaf591e3093 Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 24 Mar 2023 00:39:48 +0100 Subject: [PATCH 27/49] remove translated library --- backend/src/apis/klicktippConnector.ts | 624 ------------------------- 1 file changed, 624 deletions(-) delete mode 100644 backend/src/apis/klicktippConnector.ts diff --git a/backend/src/apis/klicktippConnector.ts b/backend/src/apis/klicktippConnector.ts deleted file mode 100644 index 0ff741604..000000000 --- a/backend/src/apis/klicktippConnector.ts +++ /dev/null @@ -1,624 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unsafe-return */ -/* eslint-disable @typescript-eslint/no-unsafe-member-access */ -/* eslint-disable @typescript-eslint/no-unsafe-assignment */ -/* eslint-disable @typescript-eslint/restrict-template-expressions */ -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -import axios, { AxiosRequestConfig, Method } from 'axios' - -export class KlicktippConnector { - private baseURL: string - private sessionName: string - private sessionId: string - private error: string - - constructor(service?: string) { - this.baseURL = service !== undefined ? service : 'https://api.klicktipp.com' - this.sessionName = '' - this.sessionId = '' - } - - /** - * Get last error - * - * @return string an error description of the last error - */ - getLastError(): string { - const result = this.error - return result - } - - /** - * login - * - * @param username The login name of the user to login. - * @param password The password of the user. - * @return TRUE on success - */ - async login(username: string, password: string): Promise { - if (!(username.length > 0 && password.length > 0)) { - throw new Error('Klicktipp Login failed: Illegal Arguments') - } - - const res = await this.httpRequest('/account/login', 'POST', { username, password }, false) - - if (!res.isAxiosError) { - this.sessionId = res.data.sessid - this.sessionName = res.data.session_name - - return true - } - - throw new Error(`Klicktipp Login failed: ${res.response.statusText}`) - } - - /** - * Logs out the user currently logged in. - * - * @return TRUE on success - */ - async logout(): Promise { - const res = await this.httpRequest('/account/logout', 'POST') - - if (!res.isAxiosError) { - this.sessionId = '' - this.sessionName = '' - - return true - } - - throw new Error(`Klicktipp Logout failed: ${res.response.statusText}`) - } - - /** - * Get all subscription processes (lists) of the logged in user. Requires to be logged in. - * - * @return A associative obeject => - */ - async subscriptionProcessIndex(): Promise { - const res = await this.httpRequest('/list', 'GET', {}, true) - - if (!res.isAxiosError) { - return res.data - } - - throw new Error(`Klicktipp Subscription process index failed: ${res.response.statusText}`) - } - - /** - * Get subscription process (list) definition. Requires to be logged in. - * - * @param listid The id of the subscription process - * - * @return An object representing the Klicktipp subscription process. - */ - async subscriptionProcessGet(listid: string): Promise { - if (!listid || listid === '') { - throw new Error('Klicktipp Illegal Arguments') - } - - // retrieve - const res = await this.httpRequest(`/subscriber/${listid}`, 'GET', {}, true) - - if (!res.isAxiosError) { - return res.data - } - - throw new Error(`Klicktipp Subscription process get failed: ${res.response.statusText}`) - } - - /** - * Get subscription process (list) redirection url for given subscription. - * - * @param listid The id of the subscription process. - * @param email The email address of the subscriber. - * - * @return A redirection url as defined in the subscription process. - */ - async subscriptionProcessRedirect(listid: string, email: string): Promise { - if (!listid || listid === '' || !email || email === '') { - throw new Error('Klicktipp Illegal Arguments') - } - - // update - const data = { listid, email } - const res = await this.httpRequest('/list/redirect', 'POST', data) - - if (!res.isAxiosError) { - return res.data - } - - throw new Error( - `Klicktipp Subscription process get redirection url failed: ${res.response.statusText}`, - ) - } - - /** - * Get all manual tags of the logged in user. Requires to be logged in. - * - * @return A associative object => - */ - async tagIndex(): Promise { - const res = await this.httpRequest('/tag', 'GET', {}, true) - - if (!res.isAxiosError) { - return res.data - } - - throw new Error(`Klicktipp Tag index failed: ${res.response.statusText}`) - } - - /** - * Get a tag definition. Requires to be logged in. - * - * @param tagid The tag id. - * - * @return An object representing the Klicktipp tag object. - */ - async tagGet(tagid: string): Promise { - if (!tagid || tagid === '') { - throw new Error('Klicktipp Illegal Arguments') - } - const res = await this.httpRequest(`/tag/${tagid}`, 'GET', {}, true) - - if (!res.isAxiosError) { - return res.data - } - - throw new Error(`Klicktipp Tag get failed: ${res.response.statusText}`) - } - - /** - * Create a new manual tag. Requires to be logged in. - * - * @param name The name of the tag. - * @param text (optional) An additional description of the tag. - * - * @return The id of the newly created tag or false if failed. - */ - async tagCreate(name: string, text?: string): Promise { - if (!name || name === '') { - throw new Error('Klicktipp Illegal Arguments') - } - const data = { - name, - text: text !== undefined ? text : '', - } - const res = await this.httpRequest('/tag', 'POST', data, true) - - if (!res.isAxiosError) { - return res.data - } - - throw new Error(`Klicktipp Tag creation failed: ${res.response.statusText}`) - } - - /** - * Updates a tag. Requires to be logged in. - * - * @param tagid The tag id used to identify which tag to modify. - * @param name (optional) The new tag name. Set empty to leave it unchanged. - * @param text (optional) The new tag description. Set empty to leave it unchanged. - * - * @return TRUE on success - */ - async tagUpdate(tagid: string, name?: string, text?: string): Promise { - if (!tagid || tagid === '' || (name === '' && text === '')) { - throw new Error('Klicktipp Illegal Arguments') - } - const data = { - name: name !== undefined ? name : '', - text: text !== undefined ? text : '', - } - - const res = await this.httpRequest(`/tag/${tagid}`, 'PUT', data, true) - - if (!res.isAxiosError) { - return true - } - - throw new Error(`Klicktipp Tag update failed: ${res.response.statusText}`) - } - - /** - * Deletes a tag. Requires to be logged in. - * - * @param tagid The user id of the user to delete. - * - * @return TRUE on success - */ - async tagDelete(tagid: string): Promise { - if (!tagid || tagid === '') { - throw new Error('Klicktipp Illegal Arguments') - } - - const res = await this.httpRequest(`/tag/${tagid}`, 'DELETE') - - if (!res.isAxiosError) { - return true - } - - throw new Error(`Klicktipp Tag deletion failed: ${res.response.statusText}`) - } - - /** - * Get all contact fields of the logged in user. Requires to be logged in. - * - * @return A associative object => - */ - async fieldIndex(): Promise { - const res = await this.httpRequest('/field', 'GET', {}, true) - - if (!res.isAxiosError) { - return res.data - } - - throw new Error(`Klicktipp Field index failed: ${res.response.statusText}`) - } - - /** - * Subscribe an email. Requires to be logged in. - * - * @param email The email address of the subscriber. - * @param listid (optional) The id subscription process. - * @param tagid (optional) The id of the manual tag the subscriber will be tagged with. - * @param fields (optional) Additional fields of the subscriber. - * - * @return An object representing the Klicktipp subscriber object. - */ - async subscribe( - email: string, - listid?: number, - tagid?: number, - fields?: any, - smsnumber?: string, - ): Promise { - if ((!email || email === '') && smsnumber === '') { - throw new Error('Illegal Arguments') - } - // subscribe - const data = { - email, - fields: fields !== undefined ? fields : {}, - smsnumber: smsnumber !== undefined ? smsnumber : '', - listid: listid !== undefined ? listid : 0, - tagid: tagid !== undefined ? tagid : 0, - } - - const res = await this.httpRequest('/subscriber', 'POST', data, true) - - if (!res.isAxiosError) { - return res.data - } - throw new Error(`Klicktipp Subscription failed: ${res.response.statusText}`) - } - - /** - * Unsubscribe an email. Requires to be logged in. - * - * @param email The email address of the subscriber. - * - * @return TRUE on success - */ - async unsubscribe(email: string): Promise { - if (!email || email === '') { - throw new Error('Klicktipp Illegal Arguments') - } - - // unsubscribe - const data = { email } - - const res = await this.httpRequest('/subscriber/unsubscribe', 'POST', data, true) - - if (!res.isAxiosError) { - return true - } - throw new Error(`Klicktipp Unsubscription failed: ${res.response.statusText}`) - } - - /** - * Tag an email. Requires to be logged in. - * - * @param email The email address of the subscriber. - * @param tagids an array of the manual tag(s) the subscriber will be tagged with. - * - * @return TRUE on success - */ - async tag(email: string, tagids: string): Promise { - if (!email || email === '' || !tagids || tagids === '') { - throw new Error('Klicktipp Illegal Arguments') - } - - // tag - const data = { - email, - tagids, - } - - const res = await this.httpRequest('/subscriber/tag', 'POST', data, true) - - if (!res.isAxiosError) { - return res.data - } - throw new Error(`Klicktipp Tagging failed: ${res.response.statusText}`) - } - - /** - * Untag an email. Requires to be logged in. - * - * @param mixed $email The email address of the subscriber. - * @param mixed $tagid The id of the manual tag that will be removed from the subscriber. - * - * @return TRUE on success. - */ - async untag(email: string, tagid: string): Promise { - if (!email || email === '' || !tagid || tagid === '') { - throw new Error('Klicktipp Illegal Arguments') - } - - // subscribe - const data = { - email, - tagid, - } - - const res = await this.httpRequest('/subscriber/untag', 'POST', data, true) - - if (!res.isAxiosError) { - return true - } - throw new Error(`Klicktipp Untagging failed: ${res.response.statusText}`) - } - - /** - * Resend an autoresponder for an email address. Requires to be logged in. - * - * @param email A valid email address - * @param autoresponder An id of the autoresponder - * - * @return TRUE on success - */ - async resend(email: string, autoresponder: string): Promise { - if (!email || email === '' || !autoresponder || autoresponder === '') { - throw new Error('Klicktipp Illegal Arguments') - } - - // resend/reset autoresponder - const data = { email, autoresponder } - - const res = await this.httpRequest('/subscriber/resend', 'POST', data, true) - - if (!res.isAxiosError) { - return true - } - throw new Error(`Klicktipp Resend failed: ${res.response.statusText}`) - } - - /** - * Get all active subscribers. Requires to be logged in. - * - * @return An array of subscriber ids. - */ - async subscriberIndex(): Promise<[string]> { - const res = await this.httpRequest('/subscriber', 'GET', undefined, true) - - if (!res.isAxiosError) { - return res.data - } - throw new Error(`Klicktipp Subscriber index failed: ${res.response.statusText}`) - } - - /** - * Get subscriber information. Requires to be logged in. - * - * @param subscriberid The subscriber id. - * - * @return An object representing the Klicktipp subscriber. - */ - async subscriberGet(subscriberid: string): Promise { - if (!subscriberid || subscriberid === '') { - throw new Error('Klicktipp Illegal Arguments') - } - - // retrieve - const res = await this.httpRequest(`/subscriber/${subscriberid}`, 'GET', {}, true) - if (!res.isAxiosError) { - return res.data - } - throw new Error(`Klicktipp Subscriber get failed: ${res.response.statusText}`) - } - - /** - * Get a subscriber id by email. Requires to be logged in. - * - * @param email The email address of the subscriber. - * - * @return The id of the subscriber. Use subscriber_get to get subscriber details. - */ - async subscriberSearch(email: string): Promise { - if (!email || email === '') { - throw new Error('Klicktipp Illegal Arguments') - } - // search - const data = { email } - const res = await this.httpRequest('/subscriber/search', 'POST', data, true) - - if (!res.isAxiosError) { - return res.data - } - throw new Error(`Klicktipp Subscriber search failed: ${res.response.statusText}`) - } - - /** - * Get all active subscribers tagged with the given tag id. Requires to be logged in. - * - * @param tagid The id of the tag. - * - * @return An array with id -> subscription date of the tagged subscribers. Use subscriber_get to get subscriber details. - */ - async subscriberTagged(tagid: string): Promise { - if (!tagid || tagid === '') { - throw new Error('Klicktipp Illegal Arguments') - } - - // search - const data = { tagid } - const res = await this.httpRequest('/subscriber/tagged', 'POST', data, true) - - if (!res.isAxiosError) { - return res.data - } - throw new Error(`Klicktipp subscriber tagged failed: ${res.response.statusText}`) - } - - /** - * Updates a subscriber. Requires to be logged in. - * - * @param subscriberid The id of the subscriber to update. - * @param fields (optional) The fields of the subscriber to update - * @param newemail (optional) The new email of the subscriber to update - * - * @return TRUE on success - */ - async subscriberUpdate( - subscriberid: string, - fields?: any, - newemail?: string, - newsmsnumber?: string, - ): Promise { - if (!subscriberid || subscriberid === '') { - throw new Error('Klicktipp Illegal Arguments') - } - - // update - const data = { - fields: fields !== undefined ? fields : {}, - newemail: newemail !== undefined ? newemail : '', - newsmsnumber: newsmsnumber !== undefined ? newsmsnumber : '', - } - const res = await this.httpRequest(`/subscriber/${subscriberid}`, 'PUT', data, true) - if (!res.isAxiosError) { - return true - } - throw new Error(`Klicktipp Subscriber update failed: ${res.response.statusText}`) - } - - /** - * Delete a subscribe. Requires to be logged in. - * - * @param subscriberid The id of the subscriber to update. - * - * @return TRUE on success. - */ - async subscriberDelete(subscriberid: string): Promise { - if (!subscriberid || subscriberid === '') { - throw new Error('Klicktipp Illegal Arguments') - } - - // delete - const res = await this.httpRequest(`/subscriber/${subscriberid}`, 'DELETE', {}, true) - - if (!res.isAxiosError) { - return true - } - throw new Error(`Klicktipp Subscriber deletion failed: ${res.response.statusText}`) - } - - /** - * Subscribe an email. Requires an api key. - * - * @param apikey The api key (listbuildng configuration). - * @param email The email address of the subscriber. - * @param fields (optional) Additional fields of the subscriber. - * - * @return A redirection url as defined in the subscription process. - */ - async signin(apikey: string, email: string, fields?: any, smsnumber?: string): Promise { - if (!apikey || apikey === '' || ((!email || email === '') && smsnumber === '')) { - throw new Error('Klicktipp Illegal Arguments') - } - - // subscribe - const data = { - apikey, - email, - fields: fields !== undefined ? fields : {}, - smsnumber: smsnumber !== undefined ? smsnumber : '', - } - - const res = await this.httpRequest('/subscriber/signin', 'POST', data) - - if (!res.isAxiosError) { - return true - } - throw new Error(`Klicktipp Subscription failed: ${res.response.statusText}`) - } - - /** - * Untag an email. Requires an api key. - * - * @param apikey The api key (listbuildng configuration). - * @param email The email address of the subscriber. - * - * @return TRUE on success - */ - async signout(apikey: string, email: string): Promise { - if (!apikey || apikey === '' || !email || email === '') { - throw new Error('Klicktipp Illegal Arguments') - } - - // untag - const data = { apikey, email } - const res = await this.httpRequest('/subscriber/signout', 'POST', data) - - if (!res.isAxiosError) { - return true - } - throw new Error(`Klicktipp Untagging failed: ${res.response.statusText}`) - } - - /** - * Unsubscribe an email. Requires an api key. - * - * @param apikey The api key (listbuildng configuration). - * @param email The email address of the subscriber. - * - * @return TRUE on success - */ - async signoff(apikey: string, email: string): Promise { - if (!apikey || apikey === '' || !email || email === '') { - throw new Error('Klicktipp Illegal Arguments') - } - - // unsubscribe - const data = { apikey, email } - const res = await this.httpRequest('/subscriber/signoff', 'POST', data) - - if (!res.isAxiosError) { - return true - } - throw new Error(`Klicktipp Unsubscription failed: ${res.response.statusText}`) - } - - async httpRequest(path: string, method?: Method, data?: any, usesession?: boolean): Promise { - if (method === undefined) { - method = 'GET' - } - const options: AxiosRequestConfig = { - baseURL: this.baseURL, - method, - url: path, - data, - headers: { - 'Content-Type': 'application/json', - Content: 'application/json', - Cookie: - usesession && this.sessionName !== '' ? `${this.sessionName}=${this.sessionId}` : '', - }, - } - - return axios(options) - .then((res) => res) - .catch((error) => error) - } -} From 4faa36da391955e49f6b93f25a2aadea085c842d Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 24 Mar 2023 00:40:27 +0100 Subject: [PATCH 28/49] change import to library --- backend/src/apis/KlicktippController.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backend/src/apis/KlicktippController.ts b/backend/src/apis/KlicktippController.ts index fe9ad563a..a291bb945 100644 --- a/backend/src/apis/KlicktippController.ts +++ b/backend/src/apis/KlicktippController.ts @@ -1,8 +1,10 @@ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-return */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -import { KlicktippConnector } from './klicktippConnector' +import KlicktippConnector from 'klicktipp-api' import CONFIG from '@/config' const klicktippConnector = new KlicktippConnector() From a8a4d62847d12afc6ff31cb67525615b1f5cfc7b Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 24 Mar 2023 00:41:01 +0100 Subject: [PATCH 29/49] create typescript .d.ts file --- backend/@types/klicktipp-api/index.d.ts | 1 + 1 file changed, 1 insertion(+) create mode 100644 backend/@types/klicktipp-api/index.d.ts diff --git a/backend/@types/klicktipp-api/index.d.ts b/backend/@types/klicktipp-api/index.d.ts new file mode 100644 index 000000000..e34bfc6c6 --- /dev/null +++ b/backend/@types/klicktipp-api/index.d.ts @@ -0,0 +1 @@ +declare module 'klicktipp-api' From a78397caf53b5a2aee73b24eecf56b6903e92431 Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 24 Mar 2023 00:41:40 +0100 Subject: [PATCH 30/49] change definition of @types to root --- backend/tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/tsconfig.json b/backend/tsconfig.json index 52241a0a6..146cd41e3 100644 --- a/backend/tsconfig.json +++ b/backend/tsconfig.json @@ -59,7 +59,7 @@ "@entity/*": ["../database/entity/*", "../../database/build/entity/*"] }, // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ - "typeRoots": ["src/federation/@types", "node_modules/@types"], /* List of folders to include type definitions from. */ + "typeRoots": ["@types", "node_modules/@types"], /* List of folders to include type definitions from. */ // "types": [], /* Type declaration files to be included in compilation. */ // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ From c2ef4bca8e355026ed6584ea3139bb2a0f3241f3 Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 24 Mar 2023 00:42:07 +0100 Subject: [PATCH 31/49] add klicktipp to yarn lock --- backend/yarn.lock | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/backend/yarn.lock b/backend/yarn.lock index 3151557ab..e169a9ce7 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -4526,6 +4526,13 @@ kleur@^3.0.3: resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== +klicktipp-api@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/klicktipp-api/-/klicktipp-api-1.0.2.tgz#a7ba728887c4d9a1c257fa30b78cbe0be92a20ab" + integrity sha512-aQQpuznC0O2W7Oq2BxKDnuLAnGmKTMfudOQ0TAEf0TLv82KH2AsCXl0nbutJ2g1i3MH+sCyGE/r/nwnUhr4QeA== + dependencies: + axios "^0.21.1" + latest-version@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face" From 1d908b3a26fac313e678c91d654a4b5a3b87267e Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 24 Mar 2023 00:45:05 +0100 Subject: [PATCH 32/49] refactor(backend): upgrade coverage to 85% --- backend/jest.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/jest.config.js b/backend/jest.config.js index 66a883b51..f2e2a556d 100644 --- a/backend/jest.config.js +++ b/backend/jest.config.js @@ -6,7 +6,7 @@ module.exports = { collectCoverageFrom: ['src/**/*.ts', '!**/node_modules/**', '!src/seeds/**', '!build/**'], coverageThreshold: { global: { - lines: 81, + lines: 85, }, }, setupFiles: ['/test/testSetup.ts'], From 783831b3de59eddaff219226cbea45732c6e829d Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 24 Mar 2023 00:57:43 +0100 Subject: [PATCH 33/49] Remove unnecessary eslint-disable --- backend/src/apis/KlicktippController.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/backend/src/apis/KlicktippController.ts b/backend/src/apis/KlicktippController.ts index a291bb945..56dd067e9 100644 --- a/backend/src/apis/KlicktippController.ts +++ b/backend/src/apis/KlicktippController.ts @@ -2,8 +2,6 @@ /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-return */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import KlicktippConnector from 'klicktipp-api' import CONFIG from '@/config' From 43d01cfbf86392ff55751700286b6dfe90f2840c Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 24 Mar 2023 01:04:27 +0100 Subject: [PATCH 34/49] Revert "Remove unnecessary eslint-disable" This reverts commit 783831b3de59eddaff219226cbea45732c6e829d. --- backend/src/apis/KlicktippController.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backend/src/apis/KlicktippController.ts b/backend/src/apis/KlicktippController.ts index 56dd067e9..a291bb945 100644 --- a/backend/src/apis/KlicktippController.ts +++ b/backend/src/apis/KlicktippController.ts @@ -2,6 +2,8 @@ /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-return */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import KlicktippConnector from 'klicktipp-api' import CONFIG from '@/config' From eb38eaa6ced57b6126f2b2b794ac312beb4028b9 Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 24 Mar 2023 01:06:45 +0100 Subject: [PATCH 35/49] Revert "Remove unnecessary eslint-disable" This reverts commit 783831b3de59eddaff219226cbea45732c6e829d. --- backend/src/apis/KlicktippController.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backend/src/apis/KlicktippController.ts b/backend/src/apis/KlicktippController.ts index 56dd067e9..a291bb945 100644 --- a/backend/src/apis/KlicktippController.ts +++ b/backend/src/apis/KlicktippController.ts @@ -2,6 +2,8 @@ /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-return */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import KlicktippConnector from 'klicktipp-api' import CONFIG from '@/config' From 5610e327d3afbd30fac722a92ba589a6a9893508 Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 24 Mar 2023 08:11:47 +0100 Subject: [PATCH 36/49] fix(backend): subscription KlickTipp searches user --- frontend/src/components/UserSettings/UserNewsletter.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/components/UserSettings/UserNewsletter.vue b/frontend/src/components/UserSettings/UserNewsletter.vue index 39f3a14af..f17463354 100644 --- a/frontend/src/components/UserSettings/UserNewsletter.vue +++ b/frontend/src/components/UserSettings/UserNewsletter.vue @@ -42,7 +42,6 @@ export default { .mutate({ mutation: this.newsletterState ? subscribeNewsletter : unsubscribeNewsletter, variables: { - email: this.$store.state.email, language: this.newsletterState ? this.$store.state.language : undefined, }, }) From 7149de1b93bfbe0f834ca6650c4ecbc8590651f4 Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 24 Mar 2023 08:12:57 +0100 Subject: [PATCH 37/49] remove email from graphql mutation --- frontend/src/graphql/mutations.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/src/graphql/mutations.js b/frontend/src/graphql/mutations.js index 55858b09b..bd4d6c145 100644 --- a/frontend/src/graphql/mutations.js +++ b/frontend/src/graphql/mutations.js @@ -1,14 +1,14 @@ import gql from 'graphql-tag' export const subscribeNewsletter = gql` - mutation($email: String!, $language: String!) { - subscribeNewsletter(email: $email, language: $language) + mutation($language: String!) { + subscribeNewsletter(language: $language) } ` export const unsubscribeNewsletter = gql` - mutation($email: String!) { - unsubscribeNewsletter(email: $email) + mutation { + unsubscribeNewsletter } ` From 0997d81ca9f6a339fd6728d03b0f5a7abe3d3c6c Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 24 Mar 2023 08:13:25 +0100 Subject: [PATCH 38/49] Remove ununsed Args definition --- backend/src/graphql/arg/SubscribeNewsletterArgs.ts | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 backend/src/graphql/arg/SubscribeNewsletterArgs.ts diff --git a/backend/src/graphql/arg/SubscribeNewsletterArgs.ts b/backend/src/graphql/arg/SubscribeNewsletterArgs.ts deleted file mode 100644 index 98a3bb2d3..000000000 --- a/backend/src/graphql/arg/SubscribeNewsletterArgs.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { ArgsType, Field } from 'type-graphql' - -@ArgsType() -export default class SubscribeNewsletterArgs { - @Field(() => String) - email: string - - @Field(() => String) - language: string -} From d07d76298b1cba69366aaff0762c0402d350ea66 Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 24 Mar 2023 08:14:12 +0100 Subject: [PATCH 39/49] email is searched from user object --- .../src/graphql/resolver/KlicktippResolver.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/backend/src/graphql/resolver/KlicktippResolver.ts b/backend/src/graphql/resolver/KlicktippResolver.ts index dd137f07c..7d4444263 100644 --- a/backend/src/graphql/resolver/KlicktippResolver.ts +++ b/backend/src/graphql/resolver/KlicktippResolver.ts @@ -1,7 +1,5 @@ /* eslint-disable @typescript-eslint/no-unsafe-return */ -import { Resolver, Query, Authorized, Arg, Mutation, Args } from 'type-graphql' - -import SubscribeNewsletterArgs from '@arg/SubscribeNewsletterArgs' +import { Resolver, Query, Authorized, Arg, Mutation, Args, Ctx } from 'type-graphql' import { getKlickTippUser, @@ -10,6 +8,7 @@ import { klicktippSignIn, } from '@/apis/KlicktippController' import { RIGHTS } from '@/auth/RIGHTS' +import { Context, getUser } from '@/server/context' @Resolver() export class KlicktippResolver { @@ -27,15 +26,18 @@ export class KlicktippResolver { @Authorized([RIGHTS.UNSUBSCRIBE_NEWSLETTER]) @Mutation(() => Boolean) - async unsubscribeNewsletter(@Arg('email') email: string): Promise { - return await unsubscribe(email) + async unsubscribeNewsletter(@Ctx() context: Context): Promise { + const user = getUser(context) + return await unsubscribe(user.emailContact.email) } @Authorized([RIGHTS.SUBSCRIBE_NEWSLETTER]) @Mutation(() => Boolean) async subscribeNewsletter( - @Args() { email, language }: SubscribeNewsletterArgs, + @Arg('language') language: string, + @Ctx() context: Context, ): Promise { - return await klicktippSignIn(email, language) + const user = getUser(context) + return await klicktippSignIn(user.emailContact.email, language) } } From f7af88fcef21324621d9bd142e26e5f00cd18f69 Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 24 Mar 2023 08:34:15 +0100 Subject: [PATCH 40/49] unsubscribeNewslette variable language undefined --- frontend/src/components/UserSettings/UserNewsletter.spec.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/src/components/UserSettings/UserNewsletter.spec.js b/frontend/src/components/UserSettings/UserNewsletter.spec.js index bb2781586..c21c6b052 100644 --- a/frontend/src/components/UserSettings/UserNewsletter.spec.js +++ b/frontend/src/components/UserSettings/UserNewsletter.spec.js @@ -61,7 +61,7 @@ describe('UserCard_Newsletter', () => { expect(mockAPIcall).toBeCalledWith({ mutation: unsubscribeNewsletter, variables: { - email: 'peter@lustig.de', + language: undefined, }, }) }) @@ -90,7 +90,6 @@ describe('UserCard_Newsletter', () => { expect(mockAPIcall).toBeCalledWith({ mutation: subscribeNewsletter, variables: { - email: 'peter@lustig.de', language: 'de', }, }) From 4081a9eecf829d944d1edff32b7a9d202048507f Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 24 Mar 2023 08:34:33 +0100 Subject: [PATCH 41/49] remove Args import --- backend/src/graphql/resolver/KlicktippResolver.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/KlicktippResolver.ts b/backend/src/graphql/resolver/KlicktippResolver.ts index 7d4444263..661aeb4a6 100644 --- a/backend/src/graphql/resolver/KlicktippResolver.ts +++ b/backend/src/graphql/resolver/KlicktippResolver.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/no-unsafe-return */ -import { Resolver, Query, Authorized, Arg, Mutation, Args, Ctx } from 'type-graphql' +import { Resolver, Query, Authorized, Arg, Mutation, Ctx } from 'type-graphql' import { getKlickTippUser, From a3e135969d0f59d97e782a17c15f3e404ff03fa2 Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 24 Mar 2023 12:08:47 +0100 Subject: [PATCH 42/49] =?UTF-8?q?fix(frontend):=20FR=20change=20`````=20an?= =?UTF-8?q?d=20``=C2=B4``=20to=20``'``?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/locales/fr.json | 68 ++++++++++++++++++------------------ 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/frontend/src/locales/fr.json b/frontend/src/locales/fr.json index 102825acc..0ab1a62d4 100644 --- a/frontend/src/locales/fr.json +++ b/frontend/src/locales/fr.json @@ -23,7 +23,7 @@ "choose-another-community": "Choisissez une autre communauté", "community": "Communauté", "communityMember": "Vous etes un membre actif", - "continue-to-registration": "Continuez l´inscription", + "continue-to-registration": "Continuez l'inscription", "moderator": "Modérateur", "moderators": "Modérateurs", "myContributions": "Mes contributions", @@ -43,20 +43,20 @@ "deleted": "Supprimé", "denied": "supprimé", "in_progress": "Il y a une question du modérateur.", - "myContributionNoteList": "À tout moment vous pouvez éditer ou supprimer les données qui n´ont pas été confirmées.", + "myContributionNoteList": "À tout moment vous pouvez éditer ou supprimer les données qui n'ont pas été confirmées.", "pending": "Inscription en attente de validation" }, "date": "Contribution pour:", "delete": "Supprimer la contribution! Êtes-vous sûr?", "deleted": "La contribution a été supprimée! Mais elle restera visible.", "formText": { - "bringYourTalentsTo": "Apportez vos talents à la communauté! Votre participation bénévole sera récompensée de 20 GDD/heure jusqu´à un plafond de 1000 GDD/mois.", - "describeYourCommunity": "Décrivez votre activité/service à la communauté en mentionnant le nombre d´heures, et calculez le montant à raison de 20 GDD/heure! Après confirmation par l´un de nos collaborateurs, le montant sera crédité sur votre compte.", + "bringYourTalentsTo": "Apportez vos talents à la communauté! Votre participation bénévole sera récompensée de 20 GDD/heure jusqu'à un plafond de 1000 GDD/mois.", + "describeYourCommunity": "Décrivez votre activité/service à la communauté en mentionnant le nombre d'heures, et calculez le montant à raison de 20 GDD/heure! Après confirmation par l'un de nos collaborateurs, le montant sera crédité sur votre compte.", "maxGDDforMonth": "Vous pouvez seulement déclarer un montant maximum de (montant) GDD pour le mois sélectionné.", "openAmountForMonth": "Pour {monthAndYear}, vous pouvez encore déclarer {creation} GDD.", "yourContribution": "Votre contribution au bien commun" }, - "noDateSelected": "Choisissez n´importe quelle date du mois", + "noDateSelected": "Choisissez n'importe quelle date du mois", "selectDate": "Quand a été effectuée votre contribution?", "submit": "Soumettre", "submitted": "La contribution a été soumise.", @@ -70,7 +70,7 @@ "contributionText": "Texte de la contribution", "creation": "Création", "decay": { - "before_startblock_transaction": "Cette transaction n´est pas péremptoire.", + "before_startblock_transaction": "Cette transaction n'est pas péremptoire.", "calculation_decay": "Calcul de la décroissance", "calculation_total": "Calcul du montant total", "decay": "Décroissance", @@ -94,9 +94,9 @@ "email-already-sent": "Nous vous avons déjà envoyé un email il y a moins de 10 minutes.", "empty-transactionlist": "Il y a eu une erreur lors de la transmission du numéro de votre transaction.", "error": "Erreur!", - "no-account": "Malheureusement nous n´avons pas pu trouver de compte (actif) correspondant aux données transmises.", - "no-transactionlist": "Il y a malheureusement eu une erreur. Aucune transaction n´a été envoyée depuis l`serveur.", - "no-user": "Pas d`utilisateur pour cet identifiant.", + "no-account": "Malheureusement nous n'avons pas pu trouver de compte (actif) correspondant aux données transmises.", + "no-transactionlist": "Il y a malheureusement eu une erreur. Aucune transaction n'a été envoyée depuis l'serveur.", + "no-user": "Pas d'utilisateur pour cet identifiant.", "session-expired": "La session a expiré pour des raisons de sécurité.", "unknown-error": "Erreur inconnue: " }, @@ -131,7 +131,7 @@ "memo": "Note", "message": "Message", "new_balance": "Montant du solde après confirmation", - "no_gdd_available": "Vous n´avez pas de GDD à envoyer.", + "no_gdd_available": "Vous n'avez pas de GDD à envoyer.", "password": "Mot de passe", "passwordRepeat": "Répétez le mot de passe", "password_new": "Nouveau mot de passe", @@ -145,7 +145,7 @@ "sender": "Expéditeur", "send_check": "Confirmez la transaction. Veuillez revérifier toutes les données svp!", "send_now": "Envoyez maintenant", - "send_transaction_error": "Malheureusement, la transaction n´a pas pu être effectuée!", + "send_transaction_error": "Malheureusement, la transaction n'a pas pu être effectuée!", "send_transaction_success": "Votre transaction a été effectuée avec succès", "sorry": "Désolé", "thx": "Merci", @@ -155,8 +155,8 @@ "gddCreationTime": "Le champ {_field_} doit comprendre un nombre entre {min} et {max} avec un maximum de une décimale.", "gddSendAmount": "Le champ {_field_} doit comprendre un nombre entre {min} et {max} avec un maximum de deux chiffres après la virgule", "is-not": "Vous ne pouvez pas vous envoyer de Gradido à vous-même", - "usernmae-regex": "Le nom d´utilisateur doit commencer par une lettre, suivi d´au moins deux caractères alphanumériques.", - "usernmae-unique": "Ce nom d´utilisateur est déjà pris." + "usernmae-regex": "Le nom d'utilisateur doit commencer par une lettre, suivi d'au moins deux caractères alphanumériques.", + "usernmae-unique": "Ce nom d'utilisateur est déjà pris." }, "your_amount": "Votre montant" }, @@ -167,7 +167,7 @@ "copy-link": "Copier le lien", "copy-link-with-text": "Copier le lien et le texte", "created": "Le lien a été créé!", - "credit-your-gradido": "Pour l´accréditation du Gradido, cliquer sur le lien!", + "credit-your-gradido": "Pour l'accréditation du Gradido, cliquer sur le lien!", "delete-the-link": "Supprimer le lien?", "deleted": "Le lien a été supprimé!", "expiredOn": "A expiré le", @@ -177,13 +177,13 @@ "link-and-text-copied": "Le lien et votre message ont été copiés dans le presse-papier. Vous pouvez maintenant le joindre à un email ou à un message..", "link-copied": "Le lien a été copié dans le presse-papier. Vous pouvez désormais le coller dans votre email ou votre message.", "link-deleted": "Le lien a été supprimé le on {date}.", - "link-expired": "Le lien n´est plus valide. Sa validité a expiré le {date}.", + "link-expired": "Le lien n'est plus valide. Sa validité a expiré le {date}.", "link-hint": "Attention : tout le monde peut utiliser ce lien. Veuillez en prendre soin!", "link-overview": "Aperçu du lien", "links_count": "Liens actifs", "links_sum": "Ouvrir les liens et les QR codes", - "no-account": "Vous n´avez pas encore de compte Gradido?", - "no-redeem": "Vous n´êtes pas autorisé à percevoir votre propre lien!", + "no-account": "Vous n'avez pas encore de compte Gradido?", + "no-redeem": "Vous n'êtes pas autorisé à percevoir votre propre lien!", "not-copied": "Malheureusement votre appareil ne permet pas de copier! Veuillez copier le lien manuellement svp!", "redeem": "Encaisser", "redeemed": "Encaissé avec succès! Votre compte est crédité de {n} GDD.", @@ -191,8 +191,8 @@ "redeemed-title": "encaisser", "to-login": "Connexion", "to-register": "Enregistrer un nouveau compte.", - "validUntil": "Valide jusqu´au", - "validUntilDate": "Le lien est valide jusqu´au {date}." + "validUntil": "Valide jusqu'au", + "validUntilDate": "Le lien est valide jusqu'au {date}." }, "GDT": "GDT", "gdt": { @@ -208,7 +208,7 @@ "gdt-received": "Gradido Transform (GDT) perçu", "gdtKonto": "Compte GDT", "no-transactions": "Vous ne possédez pas encore Gradido Transform (GDT).", - "not-reachable": "Le Serveur GDT n´est pas accessible.", + "not-reachable": "Le Serveur GDT n'est pas accessible.", "publisher": "Un membre que vous avez référé a apporté un contribution", "raise": "Augmentation", "recruited-member": "Membre invité" @@ -226,15 +226,15 @@ "maxReached": "Max. atteint", "member": "Membre", "message": { - "activateEmail": "Votre compte n´a pas encore été activé. Veuillez vérifier vos emails et cliquer sur le lien d´activation ou faites la demande d´un nouveau lien en utilisant la page qui permet de générer un nouveau mot de passe.", + "activateEmail": "Votre compte n'a pas encore été activé. Veuillez vérifier vos emails et cliquer sur le lien d'activation ou faites la demande d'un nouveau lien en utilisant la page qui permet de générer un nouveau mot de passe.", "checkEmail": "Votre email a bien été vérifié. Vous pouvez vous enregistrer maintenant.", "email": "Nous vous avons envoyé un email.", "errorTitle": "Attention!", - "register": "Vous êtes enregistré maintenant, merci de vérifier votre boîte mail et cliquer sur le lien d´activation.", + "register": "Vous êtes enregistré maintenant, merci de vérifier votre boîte mail et cliquer sur le lien d'activation.", "reply": "Merci, ta réponse a été envoyée.", "reset": "Votre mot de passe a été modifié.", "title": "Merci!", - "unsetPassword": "Votre mot de passe n´a pas été accepté. Merci de le réinitialiser." + "unsetPassword": "Votre mot de passe n'a pas été accepté. Merci de le réinitialiser." }, "navigation": { "admin_area": "Partie administrative", @@ -262,7 +262,7 @@ "send_per_link": "Envoyer GDD via lien", "session": { "extend": "Rester connecter", - "lightText": "S´il n´apparaît aucune activité pendant plus de 10 minutes, la session expirera pour des raisons de sécurité.", + "lightText": "S'il n'apparaît aucune activité pendant plus de 10 minutes, la session expirera pour des raisons de sécurité.", "logoutIn": "Se déconnecter ", "warningText": "Êtes-vous toujours connecté?" }, @@ -285,12 +285,12 @@ "newsletter": { "newsletter": "Information par email", "newsletterFalse": "Vous ne recevrez aucune information par email.", - "newsletterTrue": "Vous recevrez de l´information par email." + "newsletterTrue": "Vous recevrez de l'information par email." }, "password": { "change-password": "Changer le mot de passe", "forgot_pwd": "Mot de passe oublié?", - "resend_subtitle": "Votre lien d´activation a expiré, vous pouvez en obtenir un nouveau ici.", + "resend_subtitle": "Votre lien d'activation a expiré, vous pouvez en obtenir un nouveau ici.", "reset": "Réinitialiser le mot de passe", "reset-password": { "text": "Entrez un nouveau mot de passe que vous utiliserez dans le futur pour vous connecter à votre compte Gradido.." @@ -305,21 +305,21 @@ "showAmountGDD": "Votre montant GDD est visible.", "showAmountGDT": "Votre montant GDT est visible." }, - "signin": "S´identifier", - "signup": "S´inscrire", + "signin": "S'identifier", + "signup": "S'inscrire", "site": { "forgotPassword": { - "heading": "Veuillez entrer l´adresse email sous laquelle vous êtes enregistré ici svp." + "heading": "Veuillez entrer l'adresse email sous laquelle vous êtes enregistré ici svp." }, "resetPassword": { - "heading": "Entrez votre mot de passe et répétez l´action svp." + "heading": "Entrez votre mot de passe et répétez l'action svp." }, "signup": { - "agree": "J´accepte le politique de confidentialité .", + "agree": "J'accepte le politique de confidentialité .", "dont_match": "Les mots de passe ne correspondent pas.", "lowercase": "Une lettre minuscule est requise.", "minimum": "8 caractères minimum.", - "no-whitespace": "Pas d´espace ni d´onglet", + "no-whitespace": "Pas d'espace ni d'onglet", "one_number": "Un chiffre requis.", "special-char": "Un caractère spécial requis (e.g. _ or ä)", "uppercase": "Une lettre majuscule requise." @@ -339,8 +339,8 @@ }, "transaction": { "lastTransactions": "Dernières transactions", - "nullTransactions": "Vous n´avez pas encore de transaction effectuée sur votre compte.", - "receiverDeleted": "Le compte du destinataire n´existe plus", + "nullTransactions": "Vous n'avez pas encore de transaction effectuée sur votre compte.", + "receiverDeleted": "Le compte du destinataire n'existe plus", "receiverNotFound": "Destinataire inconnu", "show_all": "Voir toutes les {count} transactions." }, From 1f136130492e136defc049c17ecdb0ebea6fd32a Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 24 Mar 2023 13:35:03 +0100 Subject: [PATCH 43/49] remove language from mutation --- backend/src/graphql/resolver/KlicktippResolver.ts | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/backend/src/graphql/resolver/KlicktippResolver.ts b/backend/src/graphql/resolver/KlicktippResolver.ts index 661aeb4a6..f3681ce29 100644 --- a/backend/src/graphql/resolver/KlicktippResolver.ts +++ b/backend/src/graphql/resolver/KlicktippResolver.ts @@ -33,11 +33,8 @@ export class KlicktippResolver { @Authorized([RIGHTS.SUBSCRIBE_NEWSLETTER]) @Mutation(() => Boolean) - async subscribeNewsletter( - @Arg('language') language: string, - @Ctx() context: Context, - ): Promise { + async subscribeNewsletter(@Ctx() context: Context): Promise { const user = getUser(context) - return await klicktippSignIn(user.emailContact.email, language) + return await klicktippSignIn(user.emailContact.email, user.language) } } From 68064a9797272ecc03aaff5b27b51951a2cc598e Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 24 Mar 2023 13:35:43 +0100 Subject: [PATCH 44/49] remove language from mutation definition --- frontend/src/graphql/mutations.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/graphql/mutations.js b/frontend/src/graphql/mutations.js index bd4d6c145..4b43cade4 100644 --- a/frontend/src/graphql/mutations.js +++ b/frontend/src/graphql/mutations.js @@ -1,8 +1,8 @@ import gql from 'graphql-tag' export const subscribeNewsletter = gql` - mutation($language: String!) { - subscribeNewsletter(language: $language) + mutation { + subscribeNewsletter } ` From 5a960a6e27d3cebcabbfe4c9cc04b1fae623cf02 Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 24 Mar 2023 13:36:18 +0100 Subject: [PATCH 45/49] Frontend mutation call remove language --- frontend/src/components/UserSettings/UserNewsletter.vue | 3 --- 1 file changed, 3 deletions(-) diff --git a/frontend/src/components/UserSettings/UserNewsletter.vue b/frontend/src/components/UserSettings/UserNewsletter.vue index f17463354..50e442a29 100644 --- a/frontend/src/components/UserSettings/UserNewsletter.vue +++ b/frontend/src/components/UserSettings/UserNewsletter.vue @@ -41,9 +41,6 @@ export default { this.$apollo .mutate({ mutation: this.newsletterState ? subscribeNewsletter : unsubscribeNewsletter, - variables: { - language: this.newsletterState ? this.$store.state.language : undefined, - }, }) .then(() => { this.$store.commit('newsletterState', this.newsletterState) From 06a5cd678bb27d4c8b260e4957ca8daa09320bb1 Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 24 Mar 2023 13:36:25 +0100 Subject: [PATCH 46/49] Fix test --- frontend/src/components/UserSettings/UserNewsletter.spec.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/frontend/src/components/UserSettings/UserNewsletter.spec.js b/frontend/src/components/UserSettings/UserNewsletter.spec.js index c21c6b052..b211ec169 100644 --- a/frontend/src/components/UserSettings/UserNewsletter.spec.js +++ b/frontend/src/components/UserSettings/UserNewsletter.spec.js @@ -60,9 +60,6 @@ describe('UserCard_Newsletter', () => { it('calls the unsubscribe mutation', () => { expect(mockAPIcall).toBeCalledWith({ mutation: unsubscribeNewsletter, - variables: { - language: undefined, - }, }) }) @@ -89,9 +86,6 @@ describe('UserCard_Newsletter', () => { it('calls the subscribe mutation', () => { expect(mockAPIcall).toBeCalledWith({ mutation: subscribeNewsletter, - variables: { - language: 'de', - }, }) }) From 4c4da6e929c0fd345767a099f21dcf950e82b3f3 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Mon, 27 Mar 2023 23:59:46 +0200 Subject: [PATCH 47/49] fixed linting --- backend/src/graphql/resolver/TransactionLinkResolver.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.test.ts b/backend/src/graphql/resolver/TransactionLinkResolver.test.ts index 2d2bb3b68..e1c73b98c 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.test.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.test.ts @@ -453,7 +453,7 @@ describe('TransactionLinkResolver', () => { { email: 'bibi@bloxberg.de' }, { relations: ['user'] }, ) - expect(DbEvent.find()).resolves.toContainEqual( + await expect(DbEvent.find()).resolves.toContainEqual( expect.objectContaining({ type: EventType.CONTRIBUTION_LINK_REDEEM, affectedUserId: userConatct.user.id, From d6536f275fcf4df34193df2b4884e444308ac9b2 Mon Sep 17 00:00:00 2001 From: Hannes Heine Date: Tue, 28 Mar 2023 01:49:08 +0200 Subject: [PATCH 48/49] Update backend/src/graphql/resolver/KlicktippResolver.ts Co-authored-by: Ulf Gebhardt --- backend/src/graphql/resolver/KlicktippResolver.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/KlicktippResolver.ts b/backend/src/graphql/resolver/KlicktippResolver.ts index f3681ce29..0b054ddcc 100644 --- a/backend/src/graphql/resolver/KlicktippResolver.ts +++ b/backend/src/graphql/resolver/KlicktippResolver.ts @@ -28,7 +28,7 @@ export class KlicktippResolver { @Mutation(() => Boolean) async unsubscribeNewsletter(@Ctx() context: Context): Promise { const user = getUser(context) - return await unsubscribe(user.emailContact.email) + return unsubscribe(user.emailContact.email) } @Authorized([RIGHTS.SUBSCRIBE_NEWSLETTER]) From 3c9dca5b46c297c655d384f9c5f9a80fe539543a Mon Sep 17 00:00:00 2001 From: Hannes Heine Date: Tue, 28 Mar 2023 01:49:27 +0200 Subject: [PATCH 49/49] Update backend/src/graphql/resolver/KlicktippResolver.ts Co-authored-by: Ulf Gebhardt --- backend/src/graphql/resolver/KlicktippResolver.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/KlicktippResolver.ts b/backend/src/graphql/resolver/KlicktippResolver.ts index 0b054ddcc..31bde0581 100644 --- a/backend/src/graphql/resolver/KlicktippResolver.ts +++ b/backend/src/graphql/resolver/KlicktippResolver.ts @@ -35,6 +35,6 @@ export class KlicktippResolver { @Mutation(() => Boolean) async subscribeNewsletter(@Ctx() context: Context): Promise { const user = getUser(context) - return await klicktippSignIn(user.emailContact.email, user.language) + return klicktippSignIn(user.emailContact.email, user.language) } }