From 0dd17da89b75b52a1c648475def452ba38ad4082 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Tue, 21 Jun 2022 04:30:31 +0200 Subject: [PATCH 001/114] create event protocol tables, entities and enums --- backend/src/graphql/enum/EventProtocolType.ts | 31 ++++++ .../EnumEventType.ts | 13 +++ .../EventProtocol.ts | 39 +++++++ database/entity/EnumEventType.ts | 1 + database/entity/EventProtocol.ts | 1 + database/entity/index.ts | 4 + .../0041-add_event_protocol_table.ts | 102 ++++++++++++++++++ database/src/config/index.ts | 2 +- 8 files changed, 192 insertions(+), 1 deletion(-) create mode 100644 backend/src/graphql/enum/EventProtocolType.ts create mode 100644 database/entity/0041-add_event_protocol_table/EnumEventType.ts create mode 100644 database/entity/0041-add_event_protocol_table/EventProtocol.ts create mode 100644 database/entity/EnumEventType.ts create mode 100644 database/entity/EventProtocol.ts create mode 100644 database/migrations/0041-add_event_protocol_table.ts diff --git a/backend/src/graphql/enum/EventProtocolType.ts b/backend/src/graphql/enum/EventProtocolType.ts new file mode 100644 index 000000000..a95ccb819 --- /dev/null +++ b/backend/src/graphql/enum/EventProtocolType.ts @@ -0,0 +1,31 @@ +import { registerEnumType } from 'type-graphql' + +export enum EventProtocolType { + BASIC = '0', + VISIT_GRADIDO = '10', + REGISTER = '20', + REDEEM_REGISTER = '21', + INACTIVE_ACCOUNT = '22', + SEND_CONFIRMATION_EMAIL = '23', + CONFIRM_EMAIL = '24', + REGISTER_EMAIL_KLICKTIPP = '25', + LOGIN = '30', + REDEEM_LOGIN = '31', + ACTIVATE_ACCOUNT = '32', + PASSWORD_CHANGE = '33', + TRANSACTION_SEND = '40', + TRANSACTION_SEND_REDEEM = '41', + TRANSACTION_REPEATE_REDEEM = '42', + TRANSACTION_CREATION = '50', + TRANSACTION_RECEIVE = '51', + TRANSACTION_RECEIVE_REDEEM = '52', + CONTRIBUTION_CREATE = '60', + CONTRIBUTION_CONFIRM = '61', + CONTRIBUTION_LINK_DEFINE = '70', + CONTRIBUTION_LINK_ACTIVATE_REDEEM = '71', +} + +registerEnumType(EventProtocolType, { + name: 'EventProtocolType', // this one is mandatory + description: 'Name of the Type of the EventProtocol', // this one is optional +}) diff --git a/database/entity/0041-add_event_protocol_table/EnumEventType.ts b/database/entity/0041-add_event_protocol_table/EnumEventType.ts new file mode 100644 index 000000000..814ac851b --- /dev/null +++ b/database/entity/0041-add_event_protocol_table/EnumEventType.ts @@ -0,0 +1,13 @@ +import { BaseEntity, Entity, Column, PrimaryColumn } from 'typeorm' + +@Entity('enum_event_type') +export class EnumEventType extends BaseEntity { + @PrimaryColumn({ name: 'key', length: 100, nullable: false, collation: 'utf8mb4_unicode_ci' }) + key: string + + @Column({ name: 'value', unsigned: true, nullable: false }) + value: number + + @Column({ length: 200, nullable: false, collation: 'utf8mb4_unicode_ci' }) + description: string +} diff --git a/database/entity/0041-add_event_protocol_table/EventProtocol.ts b/database/entity/0041-add_event_protocol_table/EventProtocol.ts new file mode 100644 index 000000000..cf7747b77 --- /dev/null +++ b/database/entity/0041-add_event_protocol_table/EventProtocol.ts @@ -0,0 +1,39 @@ +import Decimal from 'decimal.js-light' +import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, DeleteDateColumn } from 'typeorm' +import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer' + +@Entity('event_protocol') +export class EventProtocol extends BaseEntity { + @PrimaryGeneratedColumn('increment', { unsigned: true }) + id: number + + @Column({ length: 100, nullable: false, collation: 'utf8mb4_unicode_ci' }) + type: string + + @Column({ name: 'created_at', type: 'datetime', default: () => 'CURRENT_TIMESTAMP' }) + createdAt: Date + + @Column({ name: 'user_id', unsigned: true, nullable: false }) + userId: number + + @Column({ name: 'x_user_id', unsigned: true, nullable: true }) + xUserId: number + + @Column({ name: 'x_community_id', unsigned: true, nullable: true }) + xCommunityId: number + + @Column({ name: 'transaction_id', unsigned: true, nullable: true }) + transactionId: number + + @Column({ name: 'contribution_id', unsigned: true, nullable: true }) + contributionId: number + + @Column({ + type: 'decimal', + precision: 40, + scale: 20, + nullable: true, + transformer: DecimalTransformer, + }) + amount: Decimal +} diff --git a/database/entity/EnumEventType.ts b/database/entity/EnumEventType.ts new file mode 100644 index 000000000..5b581d25f --- /dev/null +++ b/database/entity/EnumEventType.ts @@ -0,0 +1 @@ +export { EnumEventType } from './0041-add_event_protocol_table/EnumEventType' diff --git a/database/entity/EventProtocol.ts b/database/entity/EventProtocol.ts new file mode 100644 index 000000000..d7cfd869e --- /dev/null +++ b/database/entity/EventProtocol.ts @@ -0,0 +1 @@ +export { EventProtocol } from './0041-add_event_protocol_table/EventProtocol' diff --git a/database/entity/index.ts b/database/entity/index.ts index 266c40740..0974fe900 100644 --- a/database/entity/index.ts +++ b/database/entity/index.ts @@ -6,6 +6,8 @@ import { Transaction } from './Transaction' import { TransactionLink } from './TransactionLink' import { User } from './User' import { Contribution } from './Contribution' +import { EventProtocol } from './EventProtocol' +import { EnumEventType } from './EnumEventType' export const entities = [ Contribution, @@ -16,4 +18,6 @@ export const entities = [ Transaction, TransactionLink, User, + EventProtocol, + EnumEventType, ] diff --git a/database/migrations/0041-add_event_protocol_table.ts b/database/migrations/0041-add_event_protocol_table.ts new file mode 100644 index 000000000..191ef7f41 --- /dev/null +++ b/database/migrations/0041-add_event_protocol_table.ts @@ -0,0 +1,102 @@ +/* MIGRATION TO ADD EVENT_PROTOCOL + * + * This migration adds the table `event_protocol` in order to store all sorts of business event data + */ + +/* 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(` + CREATE TABLE IF NOT EXISTS \`event_protocol\` ( + \`id\` int(10) unsigned NOT NULL AUTO_INCREMENT, + \`type\` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL, + \`created_at\` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, + \`user_id\` int(10) unsigned NOT NULL, + \`x_user_id\` int(10) unsigned NULL DEFAULT NULL, + \`x_community_id\` int(10) unsigned NULL DEFAULT NULL, + \`transaction_id\` int(10) unsigned NULL DEFAULT NULL, + \`contribution_id\` int(10) unsigned NULL DEFAULT NULL, + \`amount\` bigint(20) NULL DEFAULT NULL, + PRIMARY KEY (\`id\`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;`) + await queryFn(` + CREATE TABLE IF NOT EXISTS \`enum_event_type\` ( + \`key\` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL, + \`value\` int(10) unsigned NOT NULL, + \`description\` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL, + PRIMARY KEY (\`key\`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;`) + await queryFn( + `INSERT INTO \`enum_event_type\` (\`key\`, \`value\`, \`description\`) VALUES ('BASIC', 0, 'BasicEvent: the basic event is the root of all further extending event types');`, + ) + await queryFn( + `INSERT INTO \`enum_event_type\` (\`key\`, \`value\`, \`description\`) VALUES ('VISIT_GRADIDO', 10, 'VisitGradidoEvent: if a user visits a gradido page without login or register');`, + ) + await queryFn( + `INSERT INTO \`enum_event_type\` (\`key\`, \`value\`, \`description\`) VALUES ('REGISTER', 20, 'RegisterEvent: the user presses the register button');`, + ) + await queryFn( + `INSERT INTO \`enum_event_type\` (\`key\`, \`value\`, \`description\`) VALUES ('REDEEM_REGISTER', 21, 'RedeemRegisterEvent: the user presses the register button initiated by the redeem link');`, + ) + await queryFn( + `INSERT INTO \`enum_event_type\` (\`key\`, \`value\`, \`description\`) VALUES ('INACTIVE_ACCOUNT', 22, 'InActiveAccountEvent: the systems create an inactive account during the register process');`, + ) + await queryFn( + `INSERT INTO \`enum_event_type\` (\`key\`, \`value\`, \`description\`) VALUES ('SEND_CONFIRMATION_EMAIL', 23, 'SendConfirmEmailEvent: the system send a confirmation email to the user during the register process');`, + ) + await queryFn( + `INSERT INTO \`enum_event_type\` (\`key\`, \`value\`, \`description\`) VALUES ('CONFIRM_EMAIL', 24, 'ConfirmEmailEvent: the user confirms his email during the register process');`, + ) + await queryFn( + `INSERT INTO \`enum_event_type\` (\`key\`, \`value\`, \`description\`) VALUES ('REGISTER_EMAIL_KLICKTIPP', 25, 'RegisterEmailKlickTippEvent: the system registers the confirmed email at klicktipp');`, + ) + await queryFn( + `INSERT INTO \`enum_event_type\` (\`key\`, \`value\`, \`description\`) VALUES ('LOGIN', 30, 'LoginEvent: the user presses the login button');`, + ) + await queryFn( + `INSERT INTO \`enum_event_type\` (\`key\`, \`value\`, \`description\`) VALUES ('REDEEM_LOGIN', 31, 'RedeemLoginEvent: the user presses the login button initiated by the redeem link');`, + ) + await queryFn( + `INSERT INTO \`enum_event_type\` (\`key\`, \`value\`, \`description\`) VALUES ('ACTIVATE_ACCOUNT', 32, 'ActivateAccountEvent: the system activates the users account during the first login process');`, + ) + await queryFn( + `INSERT INTO \`enum_event_type\` (\`key\`, \`value\`, \`description\`) VALUES ('PASSWORD_CHANGE', 33, 'PasswordChangeEvent: the user changes his password');`, + ) + await queryFn( + `INSERT INTO \`enum_event_type\` (\`key\`, \`value\`, \`description\`) VALUES ('TRANSACTION_SEND', 40, 'TransactionSendEvent: the user creates a transaction and sends it online');`, + ) + await queryFn( + `INSERT INTO \`enum_event_type\` (\`key\`, \`value\`, \`description\`) VALUES ('TRANSACTION_SEND_REDEEM', 41, 'TransactionSendRedeemEvent: the user creates a transaction and sends it per redeem link');`, + ) + await queryFn( + `INSERT INTO \`enum_event_type\` (\`key\`, \`value\`, \`description\`) VALUES ('TRANSACTION_REPEATE_REDEEM', 42, 'TransactionRepeateRedeemEvent: the user recreates a redeem link of a still open transaction');`, + ) + await queryFn( + `INSERT INTO \`enum_event_type\` (\`key\`, \`value\`, \`description\`) VALUES ('TRANSACTION_CREATION', 50, 'TransactionCreationEvent: the user receives a creation transaction for his confirmed contribution');`, + ) + await queryFn( + `INSERT INTO \`enum_event_type\` (\`key\`, \`value\`, \`description\`) VALUES ('TRANSACTION_RECEIVE', 51, 'TransactionReceiveEvent: the user receives a transaction from an other user and posts the amount on his account');`, + ) + await queryFn( + `INSERT INTO \`enum_event_type\` (\`key\`, \`value\`, \`description\`) VALUES ('TRANSACTION_RECEIVE_REDEEM', 52, 'TransactionReceiveRedeemEvent: the user activates the redeem link and receives the transaction and posts the amount on his account');`, + ) + await queryFn( + `INSERT INTO \`enum_event_type\` (\`key\`, \`value\`, \`description\`) VALUES ('CONTRIBUTION_CREATE', 60, 'ContributionCreateEvent: the user enters his contribution and asks for confirmation');`, + ) + await queryFn( + `INSERT INTO \`enum_event_type\` (\`key\`, \`value\`, \`description\`) VALUES ('CONTRIBUTION_CONFIRM', 61, 'ContributionConfirmEvent: the user confirms a contribution of an other user (for future multi confirmation from several users)');`, + ) + await queryFn( + `INSERT INTO \`enum_event_type\` (\`key\`, \`value\`, \`description\`) VALUES ('CONTRIBUTION_LINK_DEFINE', 70, 'ContributionLinkDefineEvent: the admin user defines a contributionLink, which could be send per Link/QR-Code on an other medium');`, + ) + await queryFn( + `INSERT INTO \`enum_event_type\` (\`key\`, \`value\`, \`description\`) VALUES ('CONTRIBUTION_LINK_ACTIVATE_REDEEM', 71, 'ContributionLinkActivateRedeemEvent: the user activates a received contributionLink to create a contribution entry for the contributionLink');`, + ) +} + +export async function downgrade(queryFn: (query: string, values?: any[]) => Promise>) { + // write downgrade logic as parameter of queryFn + await queryFn(`DROP TABLE IF EXISTS \`event_protocol\`;`) + await queryFn(`DROP TABLE IF EXISTS \`enum_event_type\`;`) +} diff --git a/database/src/config/index.ts b/database/src/config/index.ts index ba41f11d4..d8cd78eae 100644 --- a/database/src/config/index.ts +++ b/database/src/config/index.ts @@ -6,7 +6,7 @@ dotenv.config() const constants = { CONFIG_VERSION: { DEFAULT: 'DEFAULT', - EXPECTED: 'v1.2022-03-18', + EXPECTED: 'v7.2022-06-15', CURRENT: '', }, } From 279a5975f1ae4873c825638d00954fd2ab724683 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Tue, 21 Jun 2022 04:31:12 +0200 Subject: [PATCH 002/114] add ContributionLink-Events --- .../BusinessEventProtocol.md | 94 ++++++++++--------- 1 file changed, 48 insertions(+), 46 deletions(-) diff --git a/docu/Concepts/TechnicalRequirements/BusinessEventProtocol.md b/docu/Concepts/TechnicalRequirements/BusinessEventProtocol.md index 5a436d057..f8cf2cd03 100644 --- a/docu/Concepts/TechnicalRequirements/BusinessEventProtocol.md +++ b/docu/Concepts/TechnicalRequirements/BusinessEventProtocol.md @@ -6,29 +6,30 @@ With the business event protocol the gradido application will capture and persis The different event types will be defined as Enum. The following list is a first draft and will grow with further event types in the future. -| EventType | Value | Description | -| --------------------------- | ----- | ---------------------------------------------------------------------------------------------------- | -| BasicEvent | 0 | the basic event is the root of all further extending event types | -| VisitGradidoEvent | 10 | if a user visits a gradido page without login or register | -| RegisterEvent | 20 | the user presses the register button | -| RedeemRegisterEvent | 21 | the user presses the register button initiated by the redeem link | -| InActiveAccountEvent | 22 | the systems create an inactive account during the register process | -| SendConfirmEmailEvent | 23 | the system send a confirmation email to the user during the register process | -| ConfirmEmailEvent | 24 | the user confirms his email during the register process | -| RegisterEmailKlickTippEvent | 25 | the system registers the confirmed email at klicktipp | -| LoginEvent | 30 | the user presses the login button | -| RedeemLoginEvent | 31 | the user presses the login button initiated by the redeem link | -| ActivateAccountEvent | 32 | the system activates the users account during the first login process | -| PasswordChangeEvent | 33 | the user changes his password | -| TxSendEvent | 40 | the user creates a transaction and sends it online | -| TxSendRedeemEvent | 41 | the user creates a transaction and sends it per redeem link | -| TxRepeateRedeemEvent | 42 | the user recreates a redeem link of a still open transaction | -| TxCreationEvent | 50 | the user receives a creation transaction for his confirmed contribution | -| TxReceiveEvent | 51 | the user receives a transaction from an other user and posts the amount on his account | -| TxReceiveRedeemEvent | 52 | the user activates the redeem link and receives the transaction and posts the amount on his account | -| ContribCreateEvent | 60 | the user enters his contribution and asks for confirmation | -| ContribConfirmEvent | 61 | the user confirms a contribution of an other user (for future multi confirmation from several users) | -| | | | +| EventType | Value | Description | +| ----------------------------------- | ----- | ------------------------------------------------------------------------------------------------------ | +| BasicEvent | 0 | the basic event is the root of all further extending event types | +| VisitGradidoEvent | 10 | if a user visits a gradido page without login or register | +| RegisterEvent | 20 | the user presses the register button | +| RedeemRegisterEvent | 21 | the user presses the register button initiated by the redeem link | +| InActiveAccountEvent | 22 | the systems create an inactive account during the register process | +| SendConfirmEmailEvent | 23 | the system send a confirmation email to the user during the register process | +| ConfirmEmailEvent | 24 | the user confirms his email during the register process | +| RegisterEmailKlickTippEvent | 25 | the system registers the confirmed email at klicktipp | +| LoginEvent | 30 | the user presses the login button | +| RedeemLoginEvent | 31 | the user presses the login button initiated by the redeem link | +| ActivateAccountEvent | 32 | the system activates the users account during the first login process | +| PasswordChangeEvent | 33 | the user changes his password | +| TransactionSendEvent | 40 | the user creates a transaction and sends it online | +| TransactionSendRedeemEvent | 41 | the user creates a transaction and sends it per redeem link | +| TransactionRepeateRedeemEvent | 42 | the user recreates a redeem link of a still open transaction | +| TransactionCreationEvent | 50 | the user receives a creation transaction for his confirmed contribution | +| TransactionReceiveEvent | 51 | the user receives a transaction from an other user and posts the amount on his account | +| TransactionReceiveRedeemEvent | 52 | the user activates the redeem link and receives the transaction and posts the amount on his account | +| ContributionCreateEvent | 60 | the user enters his contribution and asks for confirmation | +| ContributionConfirmEvent | 61 | the user confirms a contribution of an other user (for future multi confirmation from several users) | +| ContributionLinkDefineEvent | 70 | the admin user defines a contributionLink, which could be send per Link/QR-Code on an other medium | +| ContributionLinkActivateRedeemEvent | 71 | the user activates a received contributionLink to create a contribution entry for the contributionLink | ## EventProtocol - Entity @@ -50,29 +51,30 @@ The business events will be stored in database in the new table `EventProtocol`. The following table lists for each event type the mandatory attributes, which have to be initialized at event occurence and to be written in the database event protocol table: -| EventType | id | type | createdAt | userID | XuserID | XCommunityID | transactionID | contribID | amount | -| :-------------------------- | :-: | :--: | :-------: | :----: | :-----: | :----------: | :-----------: | :-------: | :----: | -| BasicEvent | x | x | x | | | | | | | -| VisitGradidoEvent | x | x | x | | | | | | | -| RegisterEvent | x | x | x | x | | | | | | -| RedeemRegisterEvent | x | x | x | x | | | | | | -| InActiveAccountEvent | x | x | x | x | | | | | | -| SendConfirmEmailEvent | x | x | x | x | | | | | | -| ConfirmEmailEvent | x | x | x | x | | | | | | -| RegisterEmailKlickTippEvent | x | x | x | x | | | | | | -| LoginEvent | x | x | x | x | | | | | | -| RedeemLoginEvent | x | x | x | x | | | | | | -| ActivateAccountEvent | x | x | x | x | | | | | | -| PasswordChangeEvent | x | x | x | x | | | | | | -| TxSendEvent | x | x | x | x | x | x | x | | x | -| TxSendRedeemEvent | x | x | x | x | x | x | x | | x | -| TxRepeateRedeemEvent | x | x | x | x | x | x | x | | x | -| TxCreationEvent | x | x | x | x | | | x | | x | -| TxReceiveEvent | x | x | x | x | x | x | x | | x | -| TxReceiveRedeemEvent | x | x | x | x | x | x | x | | x | -| ContribCreateEvent | x | x | x | x | | | | x | | -| ContribConfirmEvent | x | x | x | x | x | x | | x | | -| | | | | | | | | | | +| EventType | id | type | createdAt | userID | XuserID | XCommunityID | transactionID | contribID | amount | +| :---------------------------------- | :-: | :--: | :-------: | :----: | :-----: | :----------: | :-----------: | :-------: | :----: | +| BasicEvent | x | x | x | | | | | | | +| VisitGradidoEvent | x | x | x | | | | | | | +| RegisterEvent | x | x | x | x | | | | | | +| RedeemRegisterEvent | x | x | x | x | | | (x) | (x) | | +| InActiveAccountEvent | x | x | x | x | | | | | | +| SendConfirmEmailEvent | x | x | x | x | | | | | | +| ConfirmEmailEvent | x | x | x | x | | | | | | +| RegisterEmailKlickTippEvent | x | x | x | x | | | | | | +| LoginEvent | x | x | x | x | | | | | | +| RedeemLoginEvent | x | x | x | x | | | (x) | (x) | | +| ActivateAccountEvent | x | x | x | x | | | | | | +| PasswordChangeEvent | x | x | x | x | | | | | | +| TransactionSendEvent | x | x | x | x | x | x | x | | x | +| TransactionSendRedeemEvent | x | x | x | x | x | x | x | | x | +| TransactionRepeateRedeemEvent | x | x | x | x | x | x | x | | x | +| TransactionCreationEvent | x | x | x | x | | | x | | x | +| TransactionReceiveEvent | x | x | x | x | x | x | x | | x | +| TransactionReceiveRedeemEvent | x | x | x | x | x | x | x | | x | +| ContributionCreateEvent | x | x | x | x | | | | x | x | +| ContributionConfirmEvent | x | x | x | x | x | x | | x | x | +| ContributionLinkDefineEvent | x | x | x | x | | | | | x | +| ContributionLinkActivateRedeemEvent | x | x | x | x | | | | x | x | ## Event creation From 7ecd96d28b6adf7ec6c1e87b03de5e1965cbe364 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Wed, 22 Jun 2022 15:09:22 +0200 Subject: [PATCH 003/114] undo changes of DB config --- database/src/config/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database/src/config/index.ts b/database/src/config/index.ts index d8cd78eae..ba41f11d4 100644 --- a/database/src/config/index.ts +++ b/database/src/config/index.ts @@ -6,7 +6,7 @@ dotenv.config() const constants = { CONFIG_VERSION: { DEFAULT: 'DEFAULT', - EXPECTED: 'v7.2022-06-15', + EXPECTED: 'v1.2022-03-18', CURRENT: '', }, } From bab867a1bd01660ac89e9d190d79f4036a818bc2 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Wed, 22 Jun 2022 16:02:28 +0200 Subject: [PATCH 004/114] add global event handler middleware --- backend/src/config/index.ts | 2 +- backend/src/graphql/schema.ts | 2 ++ backend/src/middleware/EventHandler.ts | 15 +++++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 backend/src/middleware/EventHandler.ts diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index 4e6dd8099..eae01a51f 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -10,7 +10,7 @@ Decimal.set({ }) const constants = { - DB_VERSION: '0040-add_contribution_link_id_to_user', + DB_VERSION: '0041-add_event_protocol_table', DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0 LOG4JS_CONFIG: 'log4js-config.json', // default log level on production should be info diff --git a/backend/src/graphql/schema.ts b/backend/src/graphql/schema.ts index f14f45efa..6b1579ea4 100644 --- a/backend/src/graphql/schema.ts +++ b/backend/src/graphql/schema.ts @@ -1,6 +1,7 @@ import { GraphQLSchema } from 'graphql' import { buildSchema } from 'type-graphql' import path from 'path' +import { EventHandler } from '@/middleware/EventHandler' import isAuthorized from './directive/isAuthorized' import DecimalScalar from './scalar/Decimal' @@ -11,6 +12,7 @@ const schema = async (): Promise => { resolvers: [path.join(__dirname, 'resolver', `!(*.test).{js,ts}`)], authChecker: isAuthorized, scalarsMap: [{ type: Decimal, scalar: DecimalScalar }], + globalMiddlewares: [EventHandler], }) } diff --git a/backend/src/middleware/EventHandler.ts b/backend/src/middleware/EventHandler.ts new file mode 100644 index 000000000..35b9d0b7b --- /dev/null +++ b/backend/src/middleware/EventHandler.ts @@ -0,0 +1,15 @@ +import { MiddlewareFn } from 'type-graphql' +import { EventProtocol } from '@entity/EventProtocol' + +export const EventHandler: MiddlewareFn = async ( + /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ + { root, args, context, info }, + next, +) => { + const event = new EventProtocol() + // set values before calling the resolver here + const result = await next() + // set event values here when having the result ... + await event.save() + return result +} From f5ced262d2a9bfd8317ae3b32bb3c8025459432d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Wed, 22 Jun 2022 21:13:16 +0200 Subject: [PATCH 005/114] linting --- database/entity/0041-add_event_protocol_table/EventProtocol.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/database/entity/0041-add_event_protocol_table/EventProtocol.ts b/database/entity/0041-add_event_protocol_table/EventProtocol.ts index cf7747b77..72470d2ed 100644 --- a/database/entity/0041-add_event_protocol_table/EventProtocol.ts +++ b/database/entity/0041-add_event_protocol_table/EventProtocol.ts @@ -1,5 +1,5 @@ import Decimal from 'decimal.js-light' -import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, DeleteDateColumn } from 'typeorm' +import { BaseEntity, Entity, PrimaryGeneratedColumn, Column } from 'typeorm' import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer' @Entity('event_protocol') From ecd38bd184e216313652edcbb94798c6a93f0347 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Thu, 23 Jun 2022 00:26:43 +0200 Subject: [PATCH 006/114] mutation createEventProtocol --- backend/src/seeds/graphql/mutations.ts | 31 ++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/backend/src/seeds/graphql/mutations.ts b/backend/src/seeds/graphql/mutations.ts index 7becae274..f2550aafd 100644 --- a/backend/src/seeds/graphql/mutations.ts +++ b/backend/src/seeds/graphql/mutations.ts @@ -224,3 +224,34 @@ export const deleteContributionLink = gql` deleteContributionLink(id: $id) } ` +export const createEventProtocol = gql` + mutation ( + $type: String! + $userId: Int! + $xUserId: Int + $xCommunityId: Int + $transactionId: Int + $contributionId: Int + $amount: Decimal + ) { + createEventProtocol( + type: $type + userId: $userId + xUserId: $xUserId + xCommunityId: $xCommunityId + transactionId: $transactionId + contributionId: $contributionId + amount: $amount + ) { + id + type + createdAt + userId + xUserId + xCommunityId + transactionId + contributionId + amount + } + } +` From 522233913ea15f3931ce919926a19272b0ad76cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Tue, 28 Jun 2022 04:08:25 +0200 Subject: [PATCH 007/114] define EventEmitter with an EventHandler for each EventProtocolType --- backend/src/event/EventProtocolEmitter.ts | 322 ++++++++++++++++++++++ 1 file changed, 322 insertions(+) create mode 100644 backend/src/event/EventProtocolEmitter.ts diff --git a/backend/src/event/EventProtocolEmitter.ts b/backend/src/event/EventProtocolEmitter.ts new file mode 100644 index 000000000..5b8520882 --- /dev/null +++ b/backend/src/event/EventProtocolEmitter.ts @@ -0,0 +1,322 @@ +import { EventEmitter } from 'events' +import { backendLogger as logger } from '@/server/logger' +import { EventProtocolType } from '@/graphql/enum/EventProtocolType' +import { EventProtocol } from '@entity/EventProtocol' +import Decimal from 'decimal.js-light' + +export class EventProtocolEmitter extends EventEmitter {} +const eventProtocol = new EventProtocolEmitter() + +eventProtocol.on( + EventProtocolType.ACTIVATE_ACCOUNT, + (_event: Event, createdAt: Date, userId: number) => { + logger.info( + `EventProtocol - ACTIVATE_ACCOUNT: _event=${_event}, createdAt=${createdAt}, userId=${userId}`, + ) + writeEvent(EventProtocolType.ACTIVATE_ACCOUNT, createdAt, userId, null, null, null, null, null) + }, +) + +eventProtocol.on(EventProtocolType.BASIC, (_event: Event, createdAt: Date, userId: number) => { + logger.info(`EventProtocol - BASIC: _event=${_event}, createdAt=${createdAt}, userId=${userId}`) + writeEvent(EventProtocolType.BASIC, createdAt, userId, null, null, null, null, null) +}) + +eventProtocol.on( + EventProtocolType.CONFIRM_EMAIL, + (_event: Event, createdAt: Date, userId: number) => { + logger.info( + `EventProtocol - CONFIRM_EMAIL: _event=${_event}, createdAt=${createdAt}, userId=${userId}`, + ) + writeEvent(EventProtocolType.CONFIRM_EMAIL, createdAt, userId, null, null, null, null, null) + }, +) + +eventProtocol.on( + EventProtocolType.CONTRIBUTION_CONFIRM, + ( + _event: Event, + createdAt: Date, + userId: number, + xUserId: number, + xCommunityId: number, + contributionId: number, + ) => { + logger.info( + `EventProtocol - CONTRIBUTION_CONFIRM: _event=${_event}, createdAt=${createdAt}, userId=${userId}, xUserId=${xUserId}, xCommunityId=${xCommunityId}, contributionId=${contributionId}`, + ) + writeEvent( + EventProtocolType.CONTRIBUTION_CONFIRM, + createdAt, + userId, + xUserId, + xCommunityId, + null, + contributionId, + null, + ) + }, +) + +eventProtocol.on( + EventProtocolType.CONTRIBUTION_CREATE, + (_event, createdAt, userId, contributionId) => { + logger.info( + `EventProtocol - CONTRIBUTION_CREATE: _event=${_event}, createdAt=${createdAt}, userId=${userId}, contributionId=${contributionId}`, + ) + writeEvent( + EventProtocolType.CONTRIBUTION_CREATE, + createdAt, + userId, + null, + null, + null, + contributionId, + null, + ) + }, +) + +eventProtocol.on( + EventProtocolType.CONTRIBUTION_LINK_ACTIVATE_REDEEM, + (_event, createdAt, userId) => { + logger.info( + `EventProtocol - CONTRIBUTION_LINK_ACTIVATE_REDEEM: _event=${_event}, createdAt=${createdAt}, userId=${userId}`, + ) + writeEvent( + EventProtocolType.CONTRIBUTION_LINK_ACTIVATE_REDEEM, + createdAt, + userId, + null, + null, + null, + null, + null, + ) + }, +) + +eventProtocol.on(EventProtocolType.CONTRIBUTION_LINK_DEFINE, (_event, createdAt, userId) => { + logger.info( + `EventProtocol - CONTRIBUTION_LINK_DEFINE: _event=${_event}, createdAt=${createdAt}, userId=${userId}`, + ) + writeEvent( + EventProtocolType.CONTRIBUTION_LINK_DEFINE, + createdAt, + userId, + null, + null, + null, + null, + null, + ) +}) + +eventProtocol.on(EventProtocolType.INACTIVE_ACCOUNT, (_event, createdAt, userId) => { + logger.info( + `EventProtocol - INACTIVE_ACCOUNT: _event=${_event}, createdAt=${createdAt}, userId=${userId}`, + ) + writeEvent(EventProtocolType.INACTIVE_ACCOUNT, createdAt, userId, null, null, null, null, null) +}) + +eventProtocol.on(EventProtocolType.LOGIN, (_event, createdAt, userId) => { + logger.info(`EventProtocol - LOGIN: _event=${_event}, createdAt=${createdAt}, userId=${userId}`) + writeEvent(EventProtocolType.LOGIN, createdAt, userId, null, null, null, null, null) +}) + +eventProtocol.on(EventProtocolType.PASSWORD_CHANGE, (_event, createdAt, userId) => { + logger.info( + `EventProtocol - PASSWORD_CHANGE: _event=${_event}, createdAt=${createdAt}, userId=${userId}`, + ) + writeEvent(EventProtocolType.PASSWORD_CHANGE, createdAt, userId, null, null, null, null, null) +}) + +eventProtocol.on( + EventProtocolType.REDEEM_LOGIN, + (_event, createdAt, userId, transactionId, contributionId) => { + logger.info( + `EventProtocol - REDEEM_LOGIN: _event=${_event}, createdAt=${createdAt}, userId=${userId}, transactionId=${transactionId}, contributionId=${contributionId}`, + ) + writeEvent( + EventProtocolType.REDEEM_LOGIN, + createdAt, + userId, + null, + null, + transactionId, + contributionId, + null, + ) + }, +) + +eventProtocol.on( + EventProtocolType.REDEEM_REGISTER, + (_event, createdAt, userId, transactionId, contributionId) => { + logger.info( + `EventProtocol - REDEEM_REGISTER: _event=${_event}, createdAt=${createdAt}, userId=${userId}, transactionId=${transactionId}, contributionId=${contributionId}`, + ) + writeEvent( + EventProtocolType.REDEEM_REGISTER, + createdAt, + userId, + null, + null, + transactionId, + contributionId, + null, + ) + }, +) + +eventProtocol.on(EventProtocolType.REGISTER, (_event, createdAt, userId) => { + logger.info( + `EventProtocol - REGISTER: _event=${_event}, createdAt=${createdAt}, userId=${userId}`, + ) + writeEvent(EventProtocolType.REGISTER, createdAt, userId, null, null, null, null, null) +}) + +eventProtocol.on(EventProtocolType.REGISTER_EMAIL_KLICKTIPP, (_event, createdAt, userId) => { + logger.info( + `EventProtocol - REGISTER_EMAIL_KLICKTIPP: _event=${_event}, createdAt=${createdAt}, userId=${userId}`, + ) + writeEvent( + EventProtocolType.REGISTER_EMAIL_KLICKTIPP, + createdAt, + userId, + null, + null, + null, + null, + null, + ) +}) + +eventProtocol.on(EventProtocolType.SEND_CONFIRMATION_EMAIL, (_event, createdAt, userId) => { + logger.info( + `EventProtocol - SEND_CONFIRMATION_EMAIL: _event=${_event}, createdAt=${createdAt}, userId=${userId}`, + ) + writeEvent( + EventProtocolType.SEND_CONFIRMATION_EMAIL, + createdAt, + userId, + null, + null, + null, + null, + null, + ) +}) + +eventProtocol.on(EventProtocolType.TRANSACTION_CREATION, (_event, createdAt, userId) => { + logger.info( + `EventProtocol - TRANSACTION_CREATION: _event=${_event}, createdAt=${createdAt}, userId=${userId}`, + ) + writeEvent( + EventProtocolType.TRANSACTION_CREATION, + createdAt, + userId, + null, + null, + null, + null, + null, + ) +}) + +eventProtocol.on(EventProtocolType.TRANSACTION_RECEIVE, (_event, createdAt, userId) => { + logger.info( + `EventProtocol - TRANSACTION_RECEIVE: _event=${_event}, createdAt=${createdAt}, userId=${userId}`, + ) + writeEvent(EventProtocolType.TRANSACTION_RECEIVE, createdAt, userId, null, null, null, null, null) +}) + +eventProtocol.on(EventProtocolType.TRANSACTION_RECEIVE_REDEEM, (_event, createdAt, userId) => { + logger.info( + `EventProtocol - TRANSACTION_RECEIVE_REDEEM: _event=${_event}, createdAt=${createdAt}, userId=${userId}`, + ) + writeEvent( + EventProtocolType.TRANSACTION_RECEIVE_REDEEM, + createdAt, + userId, + null, + null, + null, + null, + null, + ) +}) + +eventProtocol.on(EventProtocolType.TRANSACTION_REPEATE_REDEEM, (_event, createdAt, userId) => { + logger.info( + `EventProtocol - TRANSACTION_REPEATE_REDEEM: _event=${_event}, createdAt=${createdAt}, userId=${userId}`, + ) + writeEvent( + EventProtocolType.TRANSACTION_REPEATE_REDEEM, + createdAt, + userId, + null, + null, + null, + null, + null, + ) +}) + +eventProtocol.on(EventProtocolType.TRANSACTION_SEND, (_event, createdAt, userId) => { + logger.info( + `EventProtocol - TRANSACTION_SEND: _event=${_event}, createdAt=${createdAt}, userId=${userId}`, + ) + writeEvent(EventProtocolType.TRANSACTION_SEND, createdAt, userId, null, null, null, null, null) +}) + +eventProtocol.on(EventProtocolType.TRANSACTION_SEND_REDEEM, (_event, createdAt, userId) => { + logger.info( + `EventProtocol - TRANSACTION_SEND_REDEEM: _event=${_event}, createdAt=${createdAt}, userId=${userId}`, + ) + writeEvent( + EventProtocolType.TRANSACTION_SEND_REDEEM, + createdAt, + userId, + null, + null, + null, + null, + null, + ) +}) + +eventProtocol.on(EventProtocolType.VISIT_GRADIDO, (_event, createdAt, userId) => { + logger.info( + `EventProtocol - VISIT_GRADIDO: _event=${_event}, createdAt=${createdAt}, userId=${userId}`, + ) + writeEvent(EventProtocolType.VISIT_GRADIDO, createdAt, userId, null, null, null, null, null) +}) + +async function writeEvent( + type: string, + createdAt: Date, + userId: number, + xUserId: number | null, + xCommunityId: number | null, + transactionId: number | null, + contributionId: number | null, + amount: Decimal | null, +) { + const event = new EventProtocol() + // eslint-disable-next-line no-unused-expressions + amount ? (event.amount = amount) : null + // eslint-disable-next-line no-unused-expressions + contributionId ? (event.contributionId = contributionId) : null + event.createdAt = createdAt + // eslint-disable-next-line no-unused-expressions + transactionId ? (event.transactionId = transactionId) : null + event.type = type + event.userId = userId + // eslint-disable-next-line no-unused-expressions + xCommunityId ? (event.xCommunityId = xCommunityId) : null + // eslint-disable-next-line no-unused-expressions + xUserId ? (event.xUserId = xUserId) : null + // set event values here when having the result ... + await event.save() +} From 0dbce63910264e98cf1baf266a540a095bd60929 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Tue, 28 Jun 2022 04:13:26 +0200 Subject: [PATCH 008/114] emit some first events --- backend/src/graphql/resolver/UserResolver.ts | 21 ++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 0bde22ae6..f3c4bcd3f 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -23,6 +23,11 @@ import { sendAccountMultiRegistrationEmail } from '@/mailer/sendAccountMultiRegi import { klicktippSignIn } from '@/apis/KlicktippController' import { RIGHTS } from '@/auth/RIGHTS' import { hasElopageBuys } from '@/util/hasElopageBuys' +import { EventProtocolEmitter } from '@/event/EventProtocolEmitter' +import { EventProtocolType } from '@/graphql/enum/EventProtocolType' + + +const eventProtocol = new EventProtocolEmitter() // eslint-disable-next-line @typescript-eslint/no-var-requires const sodium = require('sodium-native') @@ -290,6 +295,7 @@ export class UserResolver { key: 'token', value: encode(dbUser.pubKey), }) + eventProtocol.emit(EventProtocolType.LOGIN, new Date(Date.now()), user.id) logger.info('successful Login:' + user) return user } @@ -384,12 +390,26 @@ export class UserResolver { logger.info('redeemCode found contributionLink=' + contributionLink) if (contributionLink) { dbUser.contributionLinkId = contributionLink.id + eventProtocol.emit( + EventProtocolType.REDEEM_REGISTER, + new Date(Date.now()), + dbUser.id, + null, + contributionLink.id, + ) } } else { const transactionLink = await dbTransactionLink.findOne({ code: redeemCode }) logger.info('redeemCode found transactionLink=' + transactionLink) if (transactionLink) { dbUser.referrerId = transactionLink.userId + eventProtocol.emit( + EventProtocolType.REDEEM_REGISTER, + new Date(Date.now()), + dbUser.id, + transactionLink.id, + null, + ) } } } @@ -444,6 +464,7 @@ export class UserResolver { await queryRunner.release() } logger.info('createUser() successful...') + eventProtocol.emit(EventProtocolType.REGISTER, new Date(Date.now()), dbUser.id) return new User(dbUser) } From 55f491694a4b6690e3241487a9fc2b60c15a7c43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Tue, 28 Jun 2022 04:23:43 +0200 Subject: [PATCH 009/114] lintting --- backend/src/graphql/resolver/UserResolver.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index f3c4bcd3f..879cf7eaf 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -26,7 +26,6 @@ import { hasElopageBuys } from '@/util/hasElopageBuys' import { EventProtocolEmitter } from '@/event/EventProtocolEmitter' import { EventProtocolType } from '@/graphql/enum/EventProtocolType' - const eventProtocol = new EventProtocolEmitter() // eslint-disable-next-line @typescript-eslint/no-var-requires From 1edea38fbb386704a2ad83eb89d0c7cb0ec6ec74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Wed, 29 Jun 2022 02:06:16 +0200 Subject: [PATCH 010/114] move EventProtocolType in event package --- backend/src/{graphql/enum => event}/EventProtocolType.ts | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename backend/src/{graphql/enum => event}/EventProtocolType.ts (100%) diff --git a/backend/src/graphql/enum/EventProtocolType.ts b/backend/src/event/EventProtocolType.ts similarity index 100% rename from backend/src/graphql/enum/EventProtocolType.ts rename to backend/src/event/EventProtocolType.ts From 1d02795562a4f7189436acd46ad621c438425588 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Wed, 29 Jun 2022 02:06:44 +0200 Subject: [PATCH 011/114] rework EventProtocol --- backend/src/event/EventProtocolEmitter.ts | 489 +++++++++++----------- backend/src/event/EventProtocolType.ts | 51 +-- 2 files changed, 270 insertions(+), 270 deletions(-) diff --git a/backend/src/event/EventProtocolEmitter.ts b/backend/src/event/EventProtocolEmitter.ts index 5b8520882..64e13cf18 100644 --- a/backend/src/event/EventProtocolEmitter.ts +++ b/backend/src/event/EventProtocolEmitter.ts @@ -1,68 +1,231 @@ import { EventEmitter } from 'events' import { backendLogger as logger } from '@/server/logger' -import { EventProtocolType } from '@/graphql/enum/EventProtocolType' +import { EventProtocolType } from './EventProtocolType' import { EventProtocol } from '@entity/EventProtocol' import Decimal from 'decimal.js-light' -export class EventProtocolEmitter extends EventEmitter {} -const eventProtocol = new EventProtocolEmitter() +class EventProtocolEmitter extends EventEmitter {} +export const eventProtocol = new EventProtocolEmitter() -eventProtocol.on( - EventProtocolType.ACTIVATE_ACCOUNT, - (_event: Event, createdAt: Date, userId: number) => { - logger.info( - `EventProtocol - ACTIVATE_ACCOUNT: _event=${_event}, createdAt=${createdAt}, userId=${userId}`, - ) - writeEvent(EventProtocolType.ACTIVATE_ACCOUNT, createdAt, userId, null, null, null, null, null) - }, -) +eventProtocol.on('error', (err) => { + logger.error(`ERROR in EventProtocol: ${err}`) +}) -eventProtocol.on(EventProtocolType.BASIC, (_event: Event, createdAt: Date, userId: number) => { - logger.info(`EventProtocol - BASIC: _event=${_event}, createdAt=${createdAt}, userId=${userId}`) +eventProtocol.on(EventProtocolType.BASIC, (createdAt: Date, userId: number) => { + logger.info( + `EventProtocol - ${EventProtocolType.BASIC}: createdAt=${createdAt}, userId=${userId}`, + ) writeEvent(EventProtocolType.BASIC, createdAt, userId, null, null, null, null, null) }) +eventProtocol.on(EventProtocolType.VISIT_GRADIDO, (createdAt: Date, userId: number) => { + logger.info( + `EventProtocol - ${EventProtocolType.VISIT_GRADIDO}: createdAt=${createdAt}, userId=${userId}`, + ) + writeEvent(EventProtocolType.VISIT_GRADIDO, createdAt, userId, null, null, null, null, null) +}) + +eventProtocol.on(EventProtocolType.REGISTER, (createdAt: Date, userId: number) => { + logger.info( + `EventProtocol - ${EventProtocolType.REGISTER}: createdAt=${createdAt}, userId=${userId}`, + ) + writeEvent(EventProtocolType.REGISTER, createdAt, userId, null, null, null, null, null) +}) + eventProtocol.on( - EventProtocolType.CONFIRM_EMAIL, - (_event: Event, createdAt: Date, userId: number) => { + EventProtocolType.REDEEM_REGISTER, + (createdAt: Date, userId: number, transactionId: number, contributionId: number) => { logger.info( - `EventProtocol - CONFIRM_EMAIL: _event=${_event}, createdAt=${createdAt}, userId=${userId}`, + `EventProtocol - ${EventProtocolType.REDEEM_REGISTER}: createdAt=${createdAt}, userId=${userId}, transactionId=${transactionId}, contributionId=${contributionId}`, + ) + writeEvent( + EventProtocolType.REDEEM_REGISTER, + createdAt, + userId, + null, + null, + transactionId, + contributionId, + null, ) - writeEvent(EventProtocolType.CONFIRM_EMAIL, createdAt, userId, null, null, null, null, null) }, ) +eventProtocol.on(EventProtocolType.INACTIVE_ACCOUNT, (createdAt: Date, userId: number) => { + logger.info( + `EventProtocol - ${EventProtocolType.INACTIVE_ACCOUNT}: createdAt=${createdAt}, userId=${userId}`, + ) + writeEvent(EventProtocolType.INACTIVE_ACCOUNT, createdAt, userId, null, null, null, null, null) +}) + +eventProtocol.on(EventProtocolType.SEND_CONFIRMATION_EMAIL, (createdAt: Date, userId: number) => { + logger.info( + `EventProtocol - ${EventProtocolType.SEND_CONFIRMATION_EMAIL}: createdAt=${createdAt}, userId=${userId}`, + ) + writeEvent( + EventProtocolType.SEND_CONFIRMATION_EMAIL, + createdAt, + userId, + null, + null, + null, + null, + null, + ) +}) + +eventProtocol.on(EventProtocolType.CONFIRM_EMAIL, (createdAt: Date, userId: number) => { + logger.info( + `EventProtocol - ${EventProtocolType.CONFIRM_EMAIL}: createdAt=${createdAt}, userId=${userId}`, + ) + writeEvent(EventProtocolType.CONFIRM_EMAIL, createdAt, userId, null, null, null, null, null) +}) + +eventProtocol.on(EventProtocolType.REGISTER_EMAIL_KLICKTIPP, (createdAt: Date, userId: number) => { + logger.info( + `EventProtocol - ${EventProtocolType.REGISTER_EMAIL_KLICKTIPP}: createdAt=${createdAt}, userId=${userId}`, + ) + writeEvent( + EventProtocolType.REGISTER_EMAIL_KLICKTIPP, + createdAt, + userId, + null, + null, + null, + null, + null, + ) +}) + +eventProtocol.on(EventProtocolType.LOGIN, (createdAt: Date, userId: number) => { + logger.info( + `EventProtocol - ${EventProtocolType.LOGIN}: createdAt=${createdAt}, userId=${userId}`, + ) + writeEvent(EventProtocolType.LOGIN, createdAt, userId, null, null, null, null, null) +}) + eventProtocol.on( - EventProtocolType.CONTRIBUTION_CONFIRM, - ( - _event: Event, - createdAt: Date, - userId: number, - xUserId: number, - xCommunityId: number, - contributionId: number, - ) => { + EventProtocolType.REDEEM_LOGIN, + (createdAt: Date, userId: number, transactionId: number, contributionId: number) => { logger.info( - `EventProtocol - CONTRIBUTION_CONFIRM: _event=${_event}, createdAt=${createdAt}, userId=${userId}, xUserId=${xUserId}, xCommunityId=${xCommunityId}, contributionId=${contributionId}`, + `EventProtocol - ${EventProtocolType.REDEEM_LOGIN}: createdAt=${createdAt}, userId=${userId}, transactionId=${transactionId}, contributionId=${contributionId}`, ) writeEvent( - EventProtocolType.CONTRIBUTION_CONFIRM, + EventProtocolType.REDEEM_LOGIN, createdAt, userId, - xUserId, - xCommunityId, null, + null, + transactionId, contributionId, null, ) }, ) +eventProtocol.on(EventProtocolType.ACTIVATE_ACCOUNT, (createdAt: Date, userId: number) => { + logger.info( + `EventProtocol - ${EventProtocolType.ACTIVATE_ACCOUNT}: createdAt=${createdAt}, userId=${userId}`, + ) + writeEvent(EventProtocolType.ACTIVATE_ACCOUNT, createdAt, userId, null, null, null, null, null) +}) + +eventProtocol.on(EventProtocolType.PASSWORD_CHANGE, (createdAt: Date, userId: number) => { + logger.info( + `EventProtocol - ${EventProtocolType.PASSWORD_CHANGE}: createdAt=${createdAt}, userId=${userId}`, + ) + writeEvent(EventProtocolType.PASSWORD_CHANGE, createdAt, userId, null, null, null, null, null) +}) + +eventProtocol.on(EventProtocolType.TRANSACTION_SEND, (createdAt: Date, userId: number) => { + logger.info( + `EventProtocol - ${EventProtocolType.TRANSACTION_SEND}: createdAt=${createdAt}, userId=${userId}`, + ) + writeEvent(EventProtocolType.TRANSACTION_SEND, createdAt, userId, null, null, null, null, null) +}) + +eventProtocol.on(EventProtocolType.TRANSACTION_SEND_REDEEM, (createdAt: Date, userId: number) => { + logger.info( + `EventProtocol - ${EventProtocolType.TRANSACTION_SEND_REDEEM}: createdAt=${createdAt}, userId=${userId}`, + ) + writeEvent( + EventProtocolType.TRANSACTION_SEND_REDEEM, + createdAt, + userId, + null, + null, + null, + null, + null, + ) +}) + +eventProtocol.on( + EventProtocolType.TRANSACTION_REPEATE_REDEEM, + (createdAt: Date, userId: number) => { + logger.info( + `EventProtocol - ${EventProtocolType.TRANSACTION_REPEATE_REDEEM}: createdAt=${createdAt}, userId=${userId}`, + ) + writeEvent( + EventProtocolType.TRANSACTION_REPEATE_REDEEM, + createdAt, + userId, + null, + null, + null, + null, + null, + ) + }, +) + +eventProtocol.on(EventProtocolType.TRANSACTION_CREATION, (createdAt: Date, userId: number) => { + logger.info( + `EventProtocol - ${EventProtocolType.TRANSACTION_CREATION}: createdAt=${createdAt}, userId=${userId}`, + ) + writeEvent( + EventProtocolType.TRANSACTION_CREATION, + createdAt, + userId, + null, + null, + null, + null, + null, + ) +}) + +eventProtocol.on(EventProtocolType.TRANSACTION_RECEIVE, (createdAt: Date, userId: number) => { + logger.info( + `EventProtocol - ${EventProtocolType.TRANSACTION_RECEIVE}: createdAt=${createdAt}, userId=${userId}`, + ) + writeEvent(EventProtocolType.TRANSACTION_RECEIVE, createdAt, userId, null, null, null, null, null) +}) + +eventProtocol.on( + EventProtocolType.TRANSACTION_RECEIVE_REDEEM, + (createdAt: Date, userId: number) => { + logger.info( + `EventProtocol - ${EventProtocolType.TRANSACTION_RECEIVE_REDEEM}: createdAt=${createdAt}, userId=${userId}`, + ) + writeEvent( + EventProtocolType.TRANSACTION_RECEIVE_REDEEM, + createdAt, + userId, + null, + null, + null, + null, + null, + ) + }, +) + eventProtocol.on( EventProtocolType.CONTRIBUTION_CREATE, - (_event, createdAt, userId, contributionId) => { + (createdAt: Date, userId: number, contributionId: number) => { logger.info( - `EventProtocol - CONTRIBUTION_CREATE: _event=${_event}, createdAt=${createdAt}, userId=${userId}, contributionId=${contributionId}`, + `EventProtocol - ${EventProtocolType.CONTRIBUTION_CREATE}: createdAt=${createdAt}, userId=${userId}, contributionId=${contributionId}`, ) writeEvent( EventProtocolType.CONTRIBUTION_CREATE, @@ -78,10 +241,51 @@ eventProtocol.on( ) eventProtocol.on( - EventProtocolType.CONTRIBUTION_LINK_ACTIVATE_REDEEM, - (_event, createdAt, userId) => { + EventProtocolType.CONTRIBUTION_CONFIRM, + ( + createdAt: Date, + userId: number, + xUserId: number, + xCommunityId: number, + contributionId: number, + ) => { logger.info( - `EventProtocol - CONTRIBUTION_LINK_ACTIVATE_REDEEM: _event=${_event}, createdAt=${createdAt}, userId=${userId}`, + `EventProtocol - ${EventProtocolType.CONTRIBUTION_CONFIRM}: createdAt=${createdAt}, userId=${userId}, xUserId=${xUserId}, xCommunityId=${xCommunityId}, contributionId=${contributionId}`, + ) + writeEvent( + EventProtocolType.CONTRIBUTION_CONFIRM, + createdAt, + userId, + xUserId, + xCommunityId, + null, + contributionId, + null, + ) + }, +) + +eventProtocol.on(EventProtocolType.CONTRIBUTION_LINK_DEFINE, (createdAt: Date, userId: number) => { + logger.info( + `EventProtocol - ${EventProtocolType.CONTRIBUTION_LINK_DEFINE}: createdAt=${createdAt}, userId=${userId}`, + ) + writeEvent( + EventProtocolType.CONTRIBUTION_LINK_DEFINE, + createdAt, + userId, + null, + null, + null, + null, + null, + ) +}) + +eventProtocol.on( + EventProtocolType.CONTRIBUTION_LINK_ACTIVATE_REDEEM, + (createdAt: Date, userId: number) => { + logger.info( + `EventProtocol - ${EventProtocolType.CONTRIBUTION_LINK_ACTIVATE_REDEEM}: createdAt=${createdAt}, userId=${userId}`, ) writeEvent( EventProtocolType.CONTRIBUTION_LINK_ACTIVATE_REDEEM, @@ -96,203 +300,6 @@ eventProtocol.on( }, ) -eventProtocol.on(EventProtocolType.CONTRIBUTION_LINK_DEFINE, (_event, createdAt, userId) => { - logger.info( - `EventProtocol - CONTRIBUTION_LINK_DEFINE: _event=${_event}, createdAt=${createdAt}, userId=${userId}`, - ) - writeEvent( - EventProtocolType.CONTRIBUTION_LINK_DEFINE, - createdAt, - userId, - null, - null, - null, - null, - null, - ) -}) - -eventProtocol.on(EventProtocolType.INACTIVE_ACCOUNT, (_event, createdAt, userId) => { - logger.info( - `EventProtocol - INACTIVE_ACCOUNT: _event=${_event}, createdAt=${createdAt}, userId=${userId}`, - ) - writeEvent(EventProtocolType.INACTIVE_ACCOUNT, createdAt, userId, null, null, null, null, null) -}) - -eventProtocol.on(EventProtocolType.LOGIN, (_event, createdAt, userId) => { - logger.info(`EventProtocol - LOGIN: _event=${_event}, createdAt=${createdAt}, userId=${userId}`) - writeEvent(EventProtocolType.LOGIN, createdAt, userId, null, null, null, null, null) -}) - -eventProtocol.on(EventProtocolType.PASSWORD_CHANGE, (_event, createdAt, userId) => { - logger.info( - `EventProtocol - PASSWORD_CHANGE: _event=${_event}, createdAt=${createdAt}, userId=${userId}`, - ) - writeEvent(EventProtocolType.PASSWORD_CHANGE, createdAt, userId, null, null, null, null, null) -}) - -eventProtocol.on( - EventProtocolType.REDEEM_LOGIN, - (_event, createdAt, userId, transactionId, contributionId) => { - logger.info( - `EventProtocol - REDEEM_LOGIN: _event=${_event}, createdAt=${createdAt}, userId=${userId}, transactionId=${transactionId}, contributionId=${contributionId}`, - ) - writeEvent( - EventProtocolType.REDEEM_LOGIN, - createdAt, - userId, - null, - null, - transactionId, - contributionId, - null, - ) - }, -) - -eventProtocol.on( - EventProtocolType.REDEEM_REGISTER, - (_event, createdAt, userId, transactionId, contributionId) => { - logger.info( - `EventProtocol - REDEEM_REGISTER: _event=${_event}, createdAt=${createdAt}, userId=${userId}, transactionId=${transactionId}, contributionId=${contributionId}`, - ) - writeEvent( - EventProtocolType.REDEEM_REGISTER, - createdAt, - userId, - null, - null, - transactionId, - contributionId, - null, - ) - }, -) - -eventProtocol.on(EventProtocolType.REGISTER, (_event, createdAt, userId) => { - logger.info( - `EventProtocol - REGISTER: _event=${_event}, createdAt=${createdAt}, userId=${userId}`, - ) - writeEvent(EventProtocolType.REGISTER, createdAt, userId, null, null, null, null, null) -}) - -eventProtocol.on(EventProtocolType.REGISTER_EMAIL_KLICKTIPP, (_event, createdAt, userId) => { - logger.info( - `EventProtocol - REGISTER_EMAIL_KLICKTIPP: _event=${_event}, createdAt=${createdAt}, userId=${userId}`, - ) - writeEvent( - EventProtocolType.REGISTER_EMAIL_KLICKTIPP, - createdAt, - userId, - null, - null, - null, - null, - null, - ) -}) - -eventProtocol.on(EventProtocolType.SEND_CONFIRMATION_EMAIL, (_event, createdAt, userId) => { - logger.info( - `EventProtocol - SEND_CONFIRMATION_EMAIL: _event=${_event}, createdAt=${createdAt}, userId=${userId}`, - ) - writeEvent( - EventProtocolType.SEND_CONFIRMATION_EMAIL, - createdAt, - userId, - null, - null, - null, - null, - null, - ) -}) - -eventProtocol.on(EventProtocolType.TRANSACTION_CREATION, (_event, createdAt, userId) => { - logger.info( - `EventProtocol - TRANSACTION_CREATION: _event=${_event}, createdAt=${createdAt}, userId=${userId}`, - ) - writeEvent( - EventProtocolType.TRANSACTION_CREATION, - createdAt, - userId, - null, - null, - null, - null, - null, - ) -}) - -eventProtocol.on(EventProtocolType.TRANSACTION_RECEIVE, (_event, createdAt, userId) => { - logger.info( - `EventProtocol - TRANSACTION_RECEIVE: _event=${_event}, createdAt=${createdAt}, userId=${userId}`, - ) - writeEvent(EventProtocolType.TRANSACTION_RECEIVE, createdAt, userId, null, null, null, null, null) -}) - -eventProtocol.on(EventProtocolType.TRANSACTION_RECEIVE_REDEEM, (_event, createdAt, userId) => { - logger.info( - `EventProtocol - TRANSACTION_RECEIVE_REDEEM: _event=${_event}, createdAt=${createdAt}, userId=${userId}`, - ) - writeEvent( - EventProtocolType.TRANSACTION_RECEIVE_REDEEM, - createdAt, - userId, - null, - null, - null, - null, - null, - ) -}) - -eventProtocol.on(EventProtocolType.TRANSACTION_REPEATE_REDEEM, (_event, createdAt, userId) => { - logger.info( - `EventProtocol - TRANSACTION_REPEATE_REDEEM: _event=${_event}, createdAt=${createdAt}, userId=${userId}`, - ) - writeEvent( - EventProtocolType.TRANSACTION_REPEATE_REDEEM, - createdAt, - userId, - null, - null, - null, - null, - null, - ) -}) - -eventProtocol.on(EventProtocolType.TRANSACTION_SEND, (_event, createdAt, userId) => { - logger.info( - `EventProtocol - TRANSACTION_SEND: _event=${_event}, createdAt=${createdAt}, userId=${userId}`, - ) - writeEvent(EventProtocolType.TRANSACTION_SEND, createdAt, userId, null, null, null, null, null) -}) - -eventProtocol.on(EventProtocolType.TRANSACTION_SEND_REDEEM, (_event, createdAt, userId) => { - logger.info( - `EventProtocol - TRANSACTION_SEND_REDEEM: _event=${_event}, createdAt=${createdAt}, userId=${userId}`, - ) - writeEvent( - EventProtocolType.TRANSACTION_SEND_REDEEM, - createdAt, - userId, - null, - null, - null, - null, - null, - ) -}) - -eventProtocol.on(EventProtocolType.VISIT_GRADIDO, (_event, createdAt, userId) => { - logger.info( - `EventProtocol - VISIT_GRADIDO: _event=${_event}, createdAt=${createdAt}, userId=${userId}`, - ) - writeEvent(EventProtocolType.VISIT_GRADIDO, createdAt, userId, null, null, null, null, null) -}) - async function writeEvent( type: string, createdAt: Date, @@ -304,19 +311,19 @@ async function writeEvent( amount: Decimal | null, ) { const event = new EventProtocol() - // eslint-disable-next-line no-unused-expressions - amount ? (event.amount = amount) : null - // eslint-disable-next-line no-unused-expressions - contributionId ? (event.contributionId = contributionId) : null - event.createdAt = createdAt - // eslint-disable-next-line no-unused-expressions - transactionId ? (event.transactionId = transactionId) : null event.type = type + event.createdAt = createdAt event.userId = userId // eslint-disable-next-line no-unused-expressions + xUserId ? (event.xUserId = xUserId) : null + // eslint-disable-next-line no-unused-expressions xCommunityId ? (event.xCommunityId = xCommunityId) : null // eslint-disable-next-line no-unused-expressions - xUserId ? (event.xUserId = xUserId) : null + contributionId ? (event.contributionId = contributionId) : null + // eslint-disable-next-line no-unused-expressions + transactionId ? (event.transactionId = transactionId) : null + // eslint-disable-next-line no-unused-expressions + amount ? (event.amount = amount) : null // set event values here when having the result ... await event.save() } diff --git a/backend/src/event/EventProtocolType.ts b/backend/src/event/EventProtocolType.ts index a95ccb819..0f61f787a 100644 --- a/backend/src/event/EventProtocolType.ts +++ b/backend/src/event/EventProtocolType.ts @@ -1,31 +1,24 @@ -import { registerEnumType } from 'type-graphql' - export enum EventProtocolType { - BASIC = '0', - VISIT_GRADIDO = '10', - REGISTER = '20', - REDEEM_REGISTER = '21', - INACTIVE_ACCOUNT = '22', - SEND_CONFIRMATION_EMAIL = '23', - CONFIRM_EMAIL = '24', - REGISTER_EMAIL_KLICKTIPP = '25', - LOGIN = '30', - REDEEM_LOGIN = '31', - ACTIVATE_ACCOUNT = '32', - PASSWORD_CHANGE = '33', - TRANSACTION_SEND = '40', - TRANSACTION_SEND_REDEEM = '41', - TRANSACTION_REPEATE_REDEEM = '42', - TRANSACTION_CREATION = '50', - TRANSACTION_RECEIVE = '51', - TRANSACTION_RECEIVE_REDEEM = '52', - CONTRIBUTION_CREATE = '60', - CONTRIBUTION_CONFIRM = '61', - CONTRIBUTION_LINK_DEFINE = '70', - CONTRIBUTION_LINK_ACTIVATE_REDEEM = '71', + BASIC = 'BASIC', + VISIT_GRADIDO = 'VISIT_GRADIDO', + REGISTER = 'REGISTER', + REDEEM_REGISTER = 'REDEEM_REGISTER', + INACTIVE_ACCOUNT = 'INACTIVE_ACCOUNT', + SEND_CONFIRMATION_EMAIL = 'SEND_CONFIRMATION_EMAIL', + CONFIRM_EMAIL = 'CONFIRM_EMAIL', + REGISTER_EMAIL_KLICKTIPP = 'REGISTER_EMAIL_KLICKTIPP', + LOGIN = 'LOGIN', + REDEEM_LOGIN = 'REDEEM_LOGIN', + ACTIVATE_ACCOUNT = 'ACTIVATE_ACCOUNT', + PASSWORD_CHANGE = 'PASSWORD_CHANGE', + TRANSACTION_SEND = 'TRANSACTION_SEND', + TRANSACTION_SEND_REDEEM = 'TRANSACTION_SEND_REDEEM', + TRANSACTION_REPEATE_REDEEM = 'TRANSACTION_REPEATE_REDEEM', + TRANSACTION_CREATION = 'TRANSACTION_CREATION', + TRANSACTION_RECEIVE = 'TRANSACTION_RECEIVE', + TRANSACTION_RECEIVE_REDEEM = 'TRANSACTION_RECEIVE_REDEEM', + CONTRIBUTION_CREATE = 'CONTRIBUTION_CREATE', + CONTRIBUTION_CONFIRM = 'CONTRIBUTION_CONFIRM', + CONTRIBUTION_LINK_DEFINE = 'CONTRIBUTION_LINK_DEFINE', + CONTRIBUTION_LINK_ACTIVATE_REDEEM = 'CONTRIBUTION_LINK_ACTIVATE_REDEEM', } - -registerEnumType(EventProtocolType, { - name: 'EventProtocolType', // this one is mandatory - description: 'Name of the Type of the EventProtocol', // this one is optional -}) From 60fde3f6886dc3a398ac3f38e9d70356f977eac1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Wed, 29 Jun 2022 02:07:58 +0200 Subject: [PATCH 012/114] rework EventProtocol --- backend/src/graphql/resolver/UserResolver.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 879cf7eaf..fed5530f8 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -23,10 +23,8 @@ import { sendAccountMultiRegistrationEmail } from '@/mailer/sendAccountMultiRegi import { klicktippSignIn } from '@/apis/KlicktippController' import { RIGHTS } from '@/auth/RIGHTS' import { hasElopageBuys } from '@/util/hasElopageBuys' -import { EventProtocolEmitter } from '@/event/EventProtocolEmitter' -import { EventProtocolType } from '@/graphql/enum/EventProtocolType' - -const eventProtocol = new EventProtocolEmitter() +import { eventProtocol } from '@/event/EventProtocolEmitter' +import { EventProtocolType } from '@/event/EventProtocolType' // eslint-disable-next-line @typescript-eslint/no-var-requires const sodium = require('sodium-native') From 38fcb0e9cf54abf72955e8cb56008a31cfc5c976 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Thu, 30 Jun 2022 01:28:27 +0200 Subject: [PATCH 013/114] next try writing event_protocol --- backend/src/event/EventProtocolEmitter.ts | 44 +++++++++++++++++------ 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/backend/src/event/EventProtocolEmitter.ts b/backend/src/event/EventProtocolEmitter.ts index 64e13cf18..1e70880a4 100644 --- a/backend/src/event/EventProtocolEmitter.ts +++ b/backend/src/event/EventProtocolEmitter.ts @@ -2,9 +2,10 @@ import { EventEmitter } from 'events' import { backendLogger as logger } from '@/server/logger' import { EventProtocolType } from './EventProtocolType' import { EventProtocol } from '@entity/EventProtocol' +import { getConnection } from '@dbTools/typeorm' import Decimal from 'decimal.js-light' -class EventProtocolEmitter extends EventEmitter {} +class EventProtocolEmitter extends EventEmitter { } export const eventProtocol = new EventProtocolEmitter() eventProtocol.on('error', (err) => { @@ -310,20 +311,41 @@ async function writeEvent( contributionId: number | null, amount: Decimal | null, ) { - const event = new EventProtocol() - event.type = type - event.createdAt = createdAt - event.userId = userId + logger.info( + `writeEvent(type=${type}, createdAt=${createdAt}, userId=${userId}, xUserId=${xUserId}, xCommunityId=${xCommunityId}, contributionId=${contributionId}, transactionId=${transactionId}, amount=${amount})`, + ) + const dbEvent = new EventProtocol() + dbEvent.type = type + dbEvent.createdAt = createdAt + dbEvent.userId = userId // eslint-disable-next-line no-unused-expressions - xUserId ? (event.xUserId = xUserId) : null + xUserId ? (dbEvent.xUserId = xUserId) : null // eslint-disable-next-line no-unused-expressions - xCommunityId ? (event.xCommunityId = xCommunityId) : null + xCommunityId ? (dbEvent.xCommunityId = xCommunityId) : null // eslint-disable-next-line no-unused-expressions - contributionId ? (event.contributionId = contributionId) : null + contributionId ? (dbEvent.contributionId = contributionId) : null // eslint-disable-next-line no-unused-expressions - transactionId ? (event.transactionId = transactionId) : null + transactionId ? (dbEvent.transactionId = transactionId) : null // eslint-disable-next-line no-unused-expressions - amount ? (event.amount = amount) : null + amount ? (dbEvent.amount = amount) : null // set event values here when having the result ... - await event.save() + // await dbEvent.save() + + const queryRunner = getConnection().createQueryRunner('master') + await queryRunner.connect() + await queryRunner.startTransaction('READ UNCOMMITTED') + try { + await queryRunner.manager.save(dbEvent).catch((error) => { + logger.error('Error while saving dbEvent', error) + throw new Error('error saving eventProtocol entry') + }) + await queryRunner.commitTransaction() + } catch (e) { + logger.error(`error during write event with ${e}`) + await queryRunner.rollbackTransaction() + throw e + } finally { + await queryRunner.release() + } } + From 7e31b5957edbea824894734d4b1471635f379735 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 30 Jun 2022 16:43:07 +0200 Subject: [PATCH 014/114] explain how .env files are working --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index 289a39109..b98d0f741 100644 --- a/README.md +++ b/README.md @@ -121,6 +121,19 @@ After generating a new version you should commit the changes. This will be the C Note: The Changelog will be regenerated with all tags on release on the external builder tool, but will not be checked in there. The Changelog on the github release will therefore always be correct, on the repo it might be incorrect due to missing tags when executing the `yarn release` command. +## How the different .env work on deploy + +Each component (frontend, admin, backend and database) has its own `.env` file. When running in development you usually do not have to care about the `.env`. The defaults are set by the respetive config file, found in the `src/config/` folder of each component. But if you have a local `.env`, the defaults set in the config are overwritten by the `.env`. + +Each component has a `.env.dist` file. This file contains all environment variables used by the component. If you want to use a local `.env`, copy the `.env.dist` and adjust the variables accordingly. + +Each component has a `.env.template` file. These files are very important on deploy. + +There is one `.env.dist` in the `deployment/bare_metal/` folder. This `.env` contains all variables used by the components. On deploy, we set all variables in this file. The deploy script loads this variables and provides them by the `.env.templates` of each component, creating a `.env` for each component. + +To avoid forgetting to update the global `.env` when deploying, we have a environment version variable inside the codebase of each component. You should update this version, when environment variables must be changed or added on deploy. The code checks, that the environement version provided by the `.env` is the one expected by the codebase. + + ## Troubleshooting | Problem | Issue | Solution | Description | From 7f5995d2fac9ae152a8ead3134a0d3400dce09ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Fri, 1 Jul 2022 00:40:10 +0200 Subject: [PATCH 015/114] add enable-check to EventProtocol configurable as CONFIG-Property --- backend/.env.dist | 3 ++ backend/src/config/index.ts | 6 ++++ backend/src/event/EventProtocolEmitter.ts | 13 ++++--- backend/src/graphql/resolver/UserResolver.ts | 36 ++++++++++++-------- 4 files changed, 39 insertions(+), 19 deletions(-) diff --git a/backend/.env.dist b/backend/.env.dist index db01cf4cc..aa44057e7 100644 --- a/backend/.env.dist +++ b/backend/.env.dist @@ -52,6 +52,9 @@ EMAIL_CODE_REQUEST_TIME=10 # Webhook WEBHOOK_ELOPAGE_SECRET=secret +# EventProtocol +EVENT_PROTOCOL_ENABLED=true + # SET LOG LEVEL AS NEEDED IN YOUR .ENV # POSSIBLE VALUES: all | trace | debug | info | warn | error | fatal # LOG_LEVEL=info diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index 641770d4e..a92d20c57 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -94,6 +94,11 @@ const webhook = { WEBHOOK_ELOPAGE_SECRET: process.env.WEBHOOK_ELOPAGE_SECRET || 'secret', } +const eventProtocol = { + // global switch to enable writing of EventProtocol-Entries + EVENT_PROTOCOL_ENABLED: process.env.EVENT_PROTOCOL_ENABLED === 'true' || false, +} + // This is needed by graphql-directive-auth process.env.APP_SECRET = server.JWT_SECRET @@ -118,6 +123,7 @@ const CONFIG = { ...email, ...loginServer, ...webhook, + ...eventProtocol, } export default CONFIG diff --git a/backend/src/event/EventProtocolEmitter.ts b/backend/src/event/EventProtocolEmitter.ts index 1e70880a4..4910bcdfa 100644 --- a/backend/src/event/EventProtocolEmitter.ts +++ b/backend/src/event/EventProtocolEmitter.ts @@ -4,8 +4,14 @@ import { EventProtocolType } from './EventProtocolType' import { EventProtocol } from '@entity/EventProtocol' import { getConnection } from '@dbTools/typeorm' import Decimal from 'decimal.js-light' +import CONFIG from '@/config' -class EventProtocolEmitter extends EventEmitter { } +class EventProtocolEmitter extends EventEmitter { + public isEnabled() { + logger.info(`EventProtocol - isEnabled=${CONFIG.EVENT_PROTOCOL_ENABLED}`) + return CONFIG.EVENT_PROTOCOL_ENABLED + } +} export const eventProtocol = new EventProtocolEmitter() eventProtocol.on('error', (err) => { @@ -329,11 +335,11 @@ async function writeEvent( // eslint-disable-next-line no-unused-expressions amount ? (dbEvent.amount = amount) : null // set event values here when having the result ... - // await dbEvent.save() + // dbEvent.save() const queryRunner = getConnection().createQueryRunner('master') await queryRunner.connect() - await queryRunner.startTransaction('READ UNCOMMITTED') + await queryRunner.startTransaction('REPEATABLE READ') try { await queryRunner.manager.save(dbEvent).catch((error) => { logger.error('Error while saving dbEvent', error) @@ -348,4 +354,3 @@ async function writeEvent( await queryRunner.release() } } - diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index fed5530f8..0bf37e82e 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -387,26 +387,30 @@ export class UserResolver { logger.info('redeemCode found contributionLink=' + contributionLink) if (contributionLink) { dbUser.contributionLinkId = contributionLink.id - eventProtocol.emit( - EventProtocolType.REDEEM_REGISTER, - new Date(Date.now()), - dbUser.id, - null, - contributionLink.id, - ) + if (eventProtocol.isEnabled()) { + eventProtocol.emit( + EventProtocolType.REDEEM_REGISTER, + new Date(Date.now()), + dbUser.id, + null, + contributionLink.id, + ) + } } } else { const transactionLink = await dbTransactionLink.findOne({ code: redeemCode }) logger.info('redeemCode found transactionLink=' + transactionLink) if (transactionLink) { dbUser.referrerId = transactionLink.userId - eventProtocol.emit( - EventProtocolType.REDEEM_REGISTER, - new Date(Date.now()), - dbUser.id, - transactionLink.id, - null, - ) + if (eventProtocol.isEnabled()) { + eventProtocol.emit( + EventProtocolType.REDEEM_REGISTER, + new Date(Date.now()), + dbUser.id, + transactionLink.id, + null, + ) + } } } } @@ -461,8 +465,10 @@ export class UserResolver { await queryRunner.release() } logger.info('createUser() successful...') - eventProtocol.emit(EventProtocolType.REGISTER, new Date(Date.now()), dbUser.id) + if (eventProtocol.isEnabled()) { + eventProtocol.emit(EventProtocolType.REGISTER, new Date(Date.now()), dbUser.id) + } return new User(dbUser) } From d9034b1bdb9e5f8ee56124599feb66d8fa54488b Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Fri, 1 Jul 2022 17:20:26 +0200 Subject: [PATCH 016/114] changes after session with claus peter --- backend/src/event/EventProtocolEmitter.ts | 330 +++++++++++-------- backend/src/graphql/resolver/UserResolver.ts | 47 +-- backend/src/graphql/schema.ts | 4 +- backend/src/seeds/graphql/mutations.ts | 3 + 4 files changed, 220 insertions(+), 164 deletions(-) diff --git a/backend/src/event/EventProtocolEmitter.ts b/backend/src/event/EventProtocolEmitter.ts index 4910bcdfa..404d1090b 100644 --- a/backend/src/event/EventProtocolEmitter.ts +++ b/backend/src/event/EventProtocolEmitter.ts @@ -1,8 +1,8 @@ import { EventEmitter } from 'events' import { backendLogger as logger } from '@/server/logger' -import { EventProtocolType } from './EventProtocolType' +// import { EventProtocolType } from './EventProtocolType' import { EventProtocol } from '@entity/EventProtocol' -import { getConnection } from '@dbTools/typeorm' +// import { getConnection } from '@dbTools/typeorm' import Decimal from 'decimal.js-light' import CONFIG from '@/config' @@ -18,34 +18,35 @@ eventProtocol.on('error', (err) => { logger.error(`ERROR in EventProtocol: ${err}`) }) -eventProtocol.on(EventProtocolType.BASIC, (createdAt: Date, userId: number) => { +/* +eventProtocol.on(EventProtocolType.BASIC, async (createdAt: Date, userId: number) => { logger.info( `EventProtocol - ${EventProtocolType.BASIC}: createdAt=${createdAt}, userId=${userId}`, ) - writeEvent(EventProtocolType.BASIC, createdAt, userId, null, null, null, null, null) + await writeEvent(EventProtocolType.BASIC, createdAt, userId, null, null, null, null, null) }) -eventProtocol.on(EventProtocolType.VISIT_GRADIDO, (createdAt: Date, userId: number) => { +eventProtocol.on(EventProtocolType.VISIT_GRADIDO, async (createdAt: Date, userId: number) => { logger.info( `EventProtocol - ${EventProtocolType.VISIT_GRADIDO}: createdAt=${createdAt}, userId=${userId}`, ) - writeEvent(EventProtocolType.VISIT_GRADIDO, createdAt, userId, null, null, null, null, null) + await writeEvent(EventProtocolType.VISIT_GRADIDO, createdAt, userId, null, null, null, null, null) }) -eventProtocol.on(EventProtocolType.REGISTER, (createdAt: Date, userId: number) => { +eventProtocol.on(EventProtocolType.REGISTER, async (createdAt: Date, userId: number) => { logger.info( `EventProtocol - ${EventProtocolType.REGISTER}: createdAt=${createdAt}, userId=${userId}`, ) - writeEvent(EventProtocolType.REGISTER, createdAt, userId, null, null, null, null, null) + await writeEvent(EventProtocolType.REGISTER, createdAt, userId, null, null, null, null, null) }) eventProtocol.on( EventProtocolType.REDEEM_REGISTER, - (createdAt: Date, userId: number, transactionId: number, contributionId: number) => { + async (createdAt: Date, userId: number, transactionId: number, contributionId: number) => { logger.info( `EventProtocol - ${EventProtocolType.REDEEM_REGISTER}: createdAt=${createdAt}, userId=${userId}, transactionId=${transactionId}, contributionId=${contributionId}`, ) - writeEvent( + await writeEvent( EventProtocolType.REDEEM_REGISTER, createdAt, userId, @@ -58,19 +59,12 @@ eventProtocol.on( }, ) -eventProtocol.on(EventProtocolType.INACTIVE_ACCOUNT, (createdAt: Date, userId: number) => { +eventProtocol.on(EventProtocolType.INACTIVE_ACCOUNT, async (createdAt: Date, userId: number) => { logger.info( `EventProtocol - ${EventProtocolType.INACTIVE_ACCOUNT}: createdAt=${createdAt}, userId=${userId}`, ) - writeEvent(EventProtocolType.INACTIVE_ACCOUNT, createdAt, userId, null, null, null, null, null) -}) - -eventProtocol.on(EventProtocolType.SEND_CONFIRMATION_EMAIL, (createdAt: Date, userId: number) => { - logger.info( - `EventProtocol - ${EventProtocolType.SEND_CONFIRMATION_EMAIL}: createdAt=${createdAt}, userId=${userId}`, - ) - writeEvent( - EventProtocolType.SEND_CONFIRMATION_EMAIL, + await writeEvent( + EventProtocolType.INACTIVE_ACCOUNT, createdAt, userId, null, @@ -81,43 +75,65 @@ eventProtocol.on(EventProtocolType.SEND_CONFIRMATION_EMAIL, (createdAt: Date, us ) }) -eventProtocol.on(EventProtocolType.CONFIRM_EMAIL, (createdAt: Date, userId: number) => { +eventProtocol.on( + EventProtocolType.SEND_CONFIRMATION_EMAIL, + async (createdAt: Date, userId: number) => { + logger.info( + `EventProtocol - ${EventProtocolType.SEND_CONFIRMATION_EMAIL}: createdAt=${createdAt}, userId=${userId}`, + ) + await writeEvent( + EventProtocolType.SEND_CONFIRMATION_EMAIL, + createdAt, + userId, + null, + null, + null, + null, + null, + ) + }, +) + +eventProtocol.on(EventProtocolType.CONFIRM_EMAIL, async (createdAt: Date, userId: number) => { logger.info( `EventProtocol - ${EventProtocolType.CONFIRM_EMAIL}: createdAt=${createdAt}, userId=${userId}`, ) - writeEvent(EventProtocolType.CONFIRM_EMAIL, createdAt, userId, null, null, null, null, null) + await writeEvent(EventProtocolType.CONFIRM_EMAIL, createdAt, userId, null, null, null, null, null) }) -eventProtocol.on(EventProtocolType.REGISTER_EMAIL_KLICKTIPP, (createdAt: Date, userId: number) => { - logger.info( - `EventProtocol - ${EventProtocolType.REGISTER_EMAIL_KLICKTIPP}: createdAt=${createdAt}, userId=${userId}`, - ) - writeEvent( - EventProtocolType.REGISTER_EMAIL_KLICKTIPP, - createdAt, - userId, - null, - null, - null, - null, - null, - ) -}) +eventProtocol.on( + EventProtocolType.REGISTER_EMAIL_KLICKTIPP, + async (createdAt: Date, userId: number) => { + logger.info( + `EventProtocol - ${EventProtocolType.REGISTER_EMAIL_KLICKTIPP}: createdAt=${createdAt}, userId=${userId}`, + ) + await writeEvent( + EventProtocolType.REGISTER_EMAIL_KLICKTIPP, + createdAt, + userId, + null, + null, + null, + null, + null, + ) + }, +) -eventProtocol.on(EventProtocolType.LOGIN, (createdAt: Date, userId: number) => { +eventProtocol.on(EventProtocolType.LOGIN, async (createdAt: Date, userId: number) => { logger.info( `EventProtocol - ${EventProtocolType.LOGIN}: createdAt=${createdAt}, userId=${userId}`, ) - writeEvent(EventProtocolType.LOGIN, createdAt, userId, null, null, null, null, null) + await writeEvent(EventProtocolType.LOGIN, createdAt, userId, null, null, null, null, null) }) eventProtocol.on( EventProtocolType.REDEEM_LOGIN, - (createdAt: Date, userId: number, transactionId: number, contributionId: number) => { + async (createdAt: Date, userId: number, transactionId: number, contributionId: number) => { logger.info( `EventProtocol - ${EventProtocolType.REDEEM_LOGIN}: createdAt=${createdAt}, userId=${userId}, transactionId=${transactionId}, contributionId=${contributionId}`, ) - writeEvent( + await writeEvent( EventProtocolType.REDEEM_LOGIN, createdAt, userId, @@ -130,33 +146,44 @@ eventProtocol.on( }, ) -eventProtocol.on(EventProtocolType.ACTIVATE_ACCOUNT, (createdAt: Date, userId: number) => { +eventProtocol.on(EventProtocolType.ACTIVATE_ACCOUNT, async (createdAt: Date, userId: number) => { logger.info( `EventProtocol - ${EventProtocolType.ACTIVATE_ACCOUNT}: createdAt=${createdAt}, userId=${userId}`, ) - writeEvent(EventProtocolType.ACTIVATE_ACCOUNT, createdAt, userId, null, null, null, null, null) + await writeEvent( + EventProtocolType.ACTIVATE_ACCOUNT, + createdAt, + userId, + null, + null, + null, + null, + null, + ) }) -eventProtocol.on(EventProtocolType.PASSWORD_CHANGE, (createdAt: Date, userId: number) => { +eventProtocol.on(EventProtocolType.PASSWORD_CHANGE, async (createdAt: Date, userId: number) => { logger.info( `EventProtocol - ${EventProtocolType.PASSWORD_CHANGE}: createdAt=${createdAt}, userId=${userId}`, ) - writeEvent(EventProtocolType.PASSWORD_CHANGE, createdAt, userId, null, null, null, null, null) + await writeEvent( + EventProtocolType.PASSWORD_CHANGE, + createdAt, + userId, + null, + null, + null, + null, + null, + ) }) -eventProtocol.on(EventProtocolType.TRANSACTION_SEND, (createdAt: Date, userId: number) => { +eventProtocol.on(EventProtocolType.TRANSACTION_SEND, async (createdAt: Date, userId: number) => { logger.info( `EventProtocol - ${EventProtocolType.TRANSACTION_SEND}: createdAt=${createdAt}, userId=${userId}`, ) - writeEvent(EventProtocolType.TRANSACTION_SEND, createdAt, userId, null, null, null, null, null) -}) - -eventProtocol.on(EventProtocolType.TRANSACTION_SEND_REDEEM, (createdAt: Date, userId: number) => { - logger.info( - `EventProtocol - ${EventProtocolType.TRANSACTION_SEND_REDEEM}: createdAt=${createdAt}, userId=${userId}`, - ) - writeEvent( - EventProtocolType.TRANSACTION_SEND_REDEEM, + await writeEvent( + EventProtocolType.TRANSACTION_SEND, createdAt, userId, null, @@ -167,13 +194,32 @@ eventProtocol.on(EventProtocolType.TRANSACTION_SEND_REDEEM, (createdAt: Date, us ) }) +eventProtocol.on( + EventProtocolType.TRANSACTION_SEND_REDEEM, + async (createdAt: Date, userId: number) => { + logger.info( + `EventProtocol - ${EventProtocolType.TRANSACTION_SEND_REDEEM}: createdAt=${createdAt}, userId=${userId}`, + ) + await writeEvent( + EventProtocolType.TRANSACTION_SEND_REDEEM, + createdAt, + userId, + null, + null, + null, + null, + null, + ) + }, +) + eventProtocol.on( EventProtocolType.TRANSACTION_REPEATE_REDEEM, - (createdAt: Date, userId: number) => { + async (createdAt: Date, userId: number) => { logger.info( `EventProtocol - ${EventProtocolType.TRANSACTION_REPEATE_REDEEM}: createdAt=${createdAt}, userId=${userId}`, ) - writeEvent( + await writeEvent( EventProtocolType.TRANSACTION_REPEATE_REDEEM, createdAt, userId, @@ -186,12 +232,31 @@ eventProtocol.on( }, ) -eventProtocol.on(EventProtocolType.TRANSACTION_CREATION, (createdAt: Date, userId: number) => { +eventProtocol.on( + EventProtocolType.TRANSACTION_CREATION, + async (createdAt: Date, userId: number) => { + logger.info( + `EventProtocol - ${EventProtocolType.TRANSACTION_CREATION}: createdAt=${createdAt}, userId=${userId}`, + ) + await writeEvent( + EventProtocolType.TRANSACTION_CREATION, + createdAt, + userId, + null, + null, + null, + null, + null, + ) + }, +) + +eventProtocol.on(EventProtocolType.TRANSACTION_RECEIVE, async (createdAt: Date, userId: number) => { logger.info( - `EventProtocol - ${EventProtocolType.TRANSACTION_CREATION}: createdAt=${createdAt}, userId=${userId}`, + `EventProtocol - ${EventProtocolType.TRANSACTION_RECEIVE}: createdAt=${createdAt}, userId=${userId}`, ) - writeEvent( - EventProtocolType.TRANSACTION_CREATION, + await writeEvent( + EventProtocolType.TRANSACTION_RECEIVE, createdAt, userId, null, @@ -202,20 +267,13 @@ eventProtocol.on(EventProtocolType.TRANSACTION_CREATION, (createdAt: Date, userI ) }) -eventProtocol.on(EventProtocolType.TRANSACTION_RECEIVE, (createdAt: Date, userId: number) => { - logger.info( - `EventProtocol - ${EventProtocolType.TRANSACTION_RECEIVE}: createdAt=${createdAt}, userId=${userId}`, - ) - writeEvent(EventProtocolType.TRANSACTION_RECEIVE, createdAt, userId, null, null, null, null, null) -}) - eventProtocol.on( EventProtocolType.TRANSACTION_RECEIVE_REDEEM, - (createdAt: Date, userId: number) => { + async (createdAt: Date, userId: number) => { logger.info( `EventProtocol - ${EventProtocolType.TRANSACTION_RECEIVE_REDEEM}: createdAt=${createdAt}, userId=${userId}`, ) - writeEvent( + await writeEvent( EventProtocolType.TRANSACTION_RECEIVE_REDEEM, createdAt, userId, @@ -230,11 +288,11 @@ eventProtocol.on( eventProtocol.on( EventProtocolType.CONTRIBUTION_CREATE, - (createdAt: Date, userId: number, contributionId: number) => { + async (createdAt: Date, userId: number, contributionId: number) => { logger.info( `EventProtocol - ${EventProtocolType.CONTRIBUTION_CREATE}: createdAt=${createdAt}, userId=${userId}, contributionId=${contributionId}`, ) - writeEvent( + await writeEvent( EventProtocolType.CONTRIBUTION_CREATE, createdAt, userId, @@ -249,7 +307,7 @@ eventProtocol.on( eventProtocol.on( EventProtocolType.CONTRIBUTION_CONFIRM, - ( + async ( createdAt: Date, userId: number, xUserId: number, @@ -259,7 +317,7 @@ eventProtocol.on( logger.info( `EventProtocol - ${EventProtocolType.CONTRIBUTION_CONFIRM}: createdAt=${createdAt}, userId=${userId}, xUserId=${xUserId}, xCommunityId=${xCommunityId}, contributionId=${contributionId}`, ) - writeEvent( + await writeEvent( EventProtocolType.CONTRIBUTION_CONFIRM, createdAt, userId, @@ -272,30 +330,14 @@ eventProtocol.on( }, ) -eventProtocol.on(EventProtocolType.CONTRIBUTION_LINK_DEFINE, (createdAt: Date, userId: number) => { - logger.info( - `EventProtocol - ${EventProtocolType.CONTRIBUTION_LINK_DEFINE}: createdAt=${createdAt}, userId=${userId}`, - ) - writeEvent( - EventProtocolType.CONTRIBUTION_LINK_DEFINE, - createdAt, - userId, - null, - null, - null, - null, - null, - ) -}) - eventProtocol.on( - EventProtocolType.CONTRIBUTION_LINK_ACTIVATE_REDEEM, - (createdAt: Date, userId: number) => { + EventProtocolType.CONTRIBUTION_LINK_DEFINE, + async (createdAt: Date, userId: number) => { logger.info( - `EventProtocol - ${EventProtocolType.CONTRIBUTION_LINK_ACTIVATE_REDEEM}: createdAt=${createdAt}, userId=${userId}`, + `EventProtocol - ${EventProtocolType.CONTRIBUTION_LINK_DEFINE}: createdAt=${createdAt}, userId=${userId}`, ) - writeEvent( - EventProtocolType.CONTRIBUTION_LINK_ACTIVATE_REDEEM, + await writeEvent( + EventProtocolType.CONTRIBUTION_LINK_DEFINE, createdAt, userId, null, @@ -307,50 +349,58 @@ eventProtocol.on( }, ) -async function writeEvent( - type: string, - createdAt: Date, - userId: number, - xUserId: number | null, - xCommunityId: number | null, - transactionId: number | null, - contributionId: number | null, - amount: Decimal | null, -) { - logger.info( - `writeEvent(type=${type}, createdAt=${createdAt}, userId=${userId}, xUserId=${xUserId}, xCommunityId=${xCommunityId}, contributionId=${contributionId}, transactionId=${transactionId}, amount=${amount})`, - ) - const dbEvent = new EventProtocol() - dbEvent.type = type - dbEvent.createdAt = createdAt - dbEvent.userId = userId - // eslint-disable-next-line no-unused-expressions - xUserId ? (dbEvent.xUserId = xUserId) : null - // eslint-disable-next-line no-unused-expressions - xCommunityId ? (dbEvent.xCommunityId = xCommunityId) : null - // eslint-disable-next-line no-unused-expressions - contributionId ? (dbEvent.contributionId = contributionId) : null - // eslint-disable-next-line no-unused-expressions - transactionId ? (dbEvent.transactionId = transactionId) : null - // eslint-disable-next-line no-unused-expressions - amount ? (dbEvent.amount = amount) : null - // set event values here when having the result ... - // dbEvent.save() +eventProtocol.on( + EventProtocolType.CONTRIBUTION_LINK_ACTIVATE_REDEEM, + async (createdAt: Date, userId: number) => { + logger.info( + `EventProtocol - ${EventProtocolType.CONTRIBUTION_LINK_ACTIVATE_REDEEM}: createdAt=${createdAt}, userId=${userId}`, + ) + await writeEvent( + EventProtocolType.CONTRIBUTION_LINK_ACTIVATE_REDEEM, + createdAt, + userId, + null, + null, + null, + null, + null, + ) + }, +) +*/ - const queryRunner = getConnection().createQueryRunner('master') - await queryRunner.connect() - await queryRunner.startTransaction('REPEATABLE READ') - try { - await queryRunner.manager.save(dbEvent).catch((error) => { - logger.error('Error while saving dbEvent', error) - throw new Error('error saving eventProtocol entry') - }) - await queryRunner.commitTransaction() - } catch (e) { - logger.error(`error during write event with ${e}`) - await queryRunner.rollbackTransaction() - throw e - } finally { - await queryRunner.release() - } +export interface EventInterface { + type: string + createdAt: Date + userId: number + xUserId?: number + xCommunityId?: number + transactionId?: number + contributionId?: number + amount?: Decimal +} + +eventProtocol.on('writeEvents', async (events: EventInterface[]) => { + for (let i = 0; i < events.length; i++) { + await writeEvent(events[i]) + } +}) + +eventProtocol.on('writeEvent', async (event: EventInterface) => { + await writeEvent(event) +}) + +const writeEvent = async (event: EventInterface): Promise => { + // if (!eventProtocol.isEnabled()) return + logger.info(`writeEvent(${JSON.stringify(event)})`) + const dbEvent = new EventProtocol() + dbEvent.type = event.type + dbEvent.createdAt = event.createdAt + dbEvent.userId = event.userId + if (event.xUserId) dbEvent.xUserId = event.xUserId + if (event.xCommunityId) dbEvent.xCommunityId = event.xCommunityId + if (event.contributionId) dbEvent.contributionId = event.contributionId + if (event.transactionId) dbEvent.transactionId = event.transactionId + if (event.amount) dbEvent.amount = event.amount + await dbEvent.save() } diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 0bf37e82e..f7ccb170b 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -292,7 +292,11 @@ export class UserResolver { key: 'token', value: encode(dbUser.pubKey), }) - eventProtocol.emit(EventProtocolType.LOGIN, new Date(Date.now()), user.id) + eventProtocol.emit('writeEvent', { + type: EventProtocolType.LOGIN, + createdAt: new Date(), + userId: user.id, + }) logger.info('successful Login:' + user) return user } @@ -387,30 +391,26 @@ export class UserResolver { logger.info('redeemCode found contributionLink=' + contributionLink) if (contributionLink) { dbUser.contributionLinkId = contributionLink.id - if (eventProtocol.isEnabled()) { - eventProtocol.emit( - EventProtocolType.REDEEM_REGISTER, - new Date(Date.now()), - dbUser.id, - null, - contributionLink.id, - ) - } + /* eventProtocol.emit( + EventProtocolType.REDEEM_REGISTER, + new Date(Date.now()), + dbUser.id, + null, + contributionLink.id, + ) */ } } else { const transactionLink = await dbTransactionLink.findOne({ code: redeemCode }) logger.info('redeemCode found transactionLink=' + transactionLink) if (transactionLink) { dbUser.referrerId = transactionLink.userId - if (eventProtocol.isEnabled()) { - eventProtocol.emit( - EventProtocolType.REDEEM_REGISTER, - new Date(Date.now()), - dbUser.id, - transactionLink.id, - null, - ) - } + /* eventProtocol.emit( + EventProtocolType.REDEEM_REGISTER, + new Date(Date.now()), + dbUser.id, + transactionLink.id, + null, + ) */ } } } @@ -466,9 +466,12 @@ export class UserResolver { } logger.info('createUser() successful...') - if (eventProtocol.isEnabled()) { - eventProtocol.emit(EventProtocolType.REGISTER, new Date(Date.now()), dbUser.id) - } + eventProtocol.emit('writeEvent', { + type: EventProtocolType.REGISTER, + createdAt: new Date(), + userId: dbUser.id, + }) + return new User(dbUser) } diff --git a/backend/src/graphql/schema.ts b/backend/src/graphql/schema.ts index 6b1579ea4..5e7dfcf0a 100644 --- a/backend/src/graphql/schema.ts +++ b/backend/src/graphql/schema.ts @@ -1,7 +1,7 @@ import { GraphQLSchema } from 'graphql' import { buildSchema } from 'type-graphql' import path from 'path' -import { EventHandler } from '@/middleware/EventHandler' +// import { EventHandler } from '@/middleware/EventHandler' import isAuthorized from './directive/isAuthorized' import DecimalScalar from './scalar/Decimal' @@ -12,7 +12,7 @@ const schema = async (): Promise => { resolvers: [path.join(__dirname, 'resolver', `!(*.test).{js,ts}`)], authChecker: isAuthorized, scalarsMap: [{ type: Decimal, scalar: DecimalScalar }], - globalMiddlewares: [EventHandler], + // globalMiddlewares: [EventHandler], }) } diff --git a/backend/src/seeds/graphql/mutations.ts b/backend/src/seeds/graphql/mutations.ts index 3895a98b8..e316a37c1 100644 --- a/backend/src/seeds/graphql/mutations.ts +++ b/backend/src/seeds/graphql/mutations.ts @@ -230,6 +230,8 @@ export const deleteContributionLink = gql` deleteContributionLink(id: $id) } ` + +/* export const createEventProtocol = gql` mutation ( $type: String! @@ -261,3 +263,4 @@ export const createEventProtocol = gql` } } ` +*/ From 9816adc745323d3b0922113d913449ba1bef5a3e Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Fri, 1 Jul 2022 17:24:51 +0200 Subject: [PATCH 017/114] remove unused global middleware --- backend/src/graphql/schema.ts | 2 -- backend/src/middleware/EventHandler.ts | 15 --------------- 2 files changed, 17 deletions(-) delete mode 100644 backend/src/middleware/EventHandler.ts diff --git a/backend/src/graphql/schema.ts b/backend/src/graphql/schema.ts index 5e7dfcf0a..f14f45efa 100644 --- a/backend/src/graphql/schema.ts +++ b/backend/src/graphql/schema.ts @@ -1,7 +1,6 @@ import { GraphQLSchema } from 'graphql' import { buildSchema } from 'type-graphql' import path from 'path' -// import { EventHandler } from '@/middleware/EventHandler' import isAuthorized from './directive/isAuthorized' import DecimalScalar from './scalar/Decimal' @@ -12,7 +11,6 @@ const schema = async (): Promise => { resolvers: [path.join(__dirname, 'resolver', `!(*.test).{js,ts}`)], authChecker: isAuthorized, scalarsMap: [{ type: Decimal, scalar: DecimalScalar }], - // globalMiddlewares: [EventHandler], }) } diff --git a/backend/src/middleware/EventHandler.ts b/backend/src/middleware/EventHandler.ts deleted file mode 100644 index 35b9d0b7b..000000000 --- a/backend/src/middleware/EventHandler.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { MiddlewareFn } from 'type-graphql' -import { EventProtocol } from '@entity/EventProtocol' - -export const EventHandler: MiddlewareFn = async ( - /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ - { root, args, context, info }, - next, -) => { - const event = new EventProtocol() - // set values before calling the resolver here - const result = await next() - // set event values here when having the result ... - await event.save() - return result -} From 2e2a84f5356f3ab1e619e669522cd0aa7e5de525 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Fri, 1 Jul 2022 17:26:20 +0200 Subject: [PATCH 018/114] remove unused mutation --- backend/src/seeds/graphql/mutations.ts | 34 -------------------------- 1 file changed, 34 deletions(-) diff --git a/backend/src/seeds/graphql/mutations.ts b/backend/src/seeds/graphql/mutations.ts index e316a37c1..f2edf0821 100644 --- a/backend/src/seeds/graphql/mutations.ts +++ b/backend/src/seeds/graphql/mutations.ts @@ -230,37 +230,3 @@ export const deleteContributionLink = gql` deleteContributionLink(id: $id) } ` - -/* -export const createEventProtocol = gql` - mutation ( - $type: String! - $userId: Int! - $xUserId: Int - $xCommunityId: Int - $transactionId: Int - $contributionId: Int - $amount: Decimal - ) { - createEventProtocol( - type: $type - userId: $userId - xUserId: $xUserId - xCommunityId: $xCommunityId - transactionId: $transactionId - contributionId: $contributionId - amount: $amount - ) { - id - type - createdAt - userId - xUserId - xCommunityId - transactionId - contributionId - amount - } - } -` -*/ From 78195612c2c4abbf83151f7faed47ad4f4d1767f Mon Sep 17 00:00:00 2001 From: elweyn Date: Mon, 4 Jul 2022 07:39:11 +0200 Subject: [PATCH 019/114] Add ROLES and RIGHTS to updateContribution. --- backend/src/auth/RIGHTS.ts | 1 + backend/src/auth/ROLES.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/backend/src/auth/RIGHTS.ts b/backend/src/auth/RIGHTS.ts index 6a6f8b7c0..1d0fd2856 100644 --- a/backend/src/auth/RIGHTS.ts +++ b/backend/src/auth/RIGHTS.ts @@ -27,6 +27,7 @@ export enum RIGHTS { GDT_BALANCE = 'GDT_BALANCE', CREATE_CONTRIBUTION = 'CREATE_CONTRIBUTION', LIST_CONTRIBUTIONS = 'LIST_CONTRIBUTIONS', + UPDATE_CONTRIBUTION = 'UPDATE_CONTRIBUTION', // Admin SEARCH_USERS = 'SEARCH_USERS', SET_USER_ROLE = 'SET_USER_ROLE', diff --git a/backend/src/auth/ROLES.ts b/backend/src/auth/ROLES.ts index f56106664..75e552e79 100644 --- a/backend/src/auth/ROLES.ts +++ b/backend/src/auth/ROLES.ts @@ -25,6 +25,7 @@ export const ROLE_USER = new Role('user', [ RIGHTS.GDT_BALANCE, RIGHTS.CREATE_CONTRIBUTION, RIGHTS.LIST_CONTRIBUTIONS, + RIGHTS.UPDATE_CONTRIBUTION, ]) export const ROLE_ADMIN = new Role('admin', Object.values(RIGHTS)) // all rights From b580f8755da0a0034f58eb6b8871bab68c366d3e Mon Sep 17 00:00:00 2001 From: elweyn Date: Mon, 4 Jul 2022 07:40:10 +0200 Subject: [PATCH 020/114] Refactor updateCreations. --- backend/src/graphql/resolver/AdminResolver.ts | 11 +---------- .../src/graphql/resolver/util/isContributionValid.ts | 11 +++++++++++ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index 5476fd8a1..962c13e9b 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -52,6 +52,7 @@ import { getUserCreations, isContributionValid, isStartEndDateValid, + updateCreations, } from './util/isContributionValid' import { CONTRIBUTIONLINK_MEMO_MAX_CHARS, @@ -688,13 +689,3 @@ export class AdminResolver { return new ContributionLink(dbContributionLink) } } - -function updateCreations(creations: Decimal[], contribution: Contribution): Decimal[] { - const index = getCreationIndex(contribution.contributionDate.getMonth()) - - if (index < 0) { - throw new Error('You cannot create GDD for a month older than the last three months.') - } - creations[index] = creations[index].plus(contribution.amount.toString()) - return creations -} diff --git a/backend/src/graphql/resolver/util/isContributionValid.ts b/backend/src/graphql/resolver/util/isContributionValid.ts index 0a9b57170..552370f4c 100644 --- a/backend/src/graphql/resolver/util/isContributionValid.ts +++ b/backend/src/graphql/resolver/util/isContributionValid.ts @@ -1,6 +1,7 @@ import { TransactionTypeId } from '@/graphql/enum/TransactionTypeId' import { backendLogger as logger } from '@/server/logger' import { getConnection } from '@dbTools/typeorm' +import { Contribution } from '@entity/Contribution' import Decimal from 'decimal.js-light' import { FULL_CREATION_AVAILABLE, MAX_CREATION_AMOUNT } from '../const/const' @@ -117,3 +118,13 @@ export const isStartEndDateValid = ( throw new Error(`The value of validFrom must before or equals the validTo!`) } } + +export const updateCreations = (creations: Decimal[], contribution: Contribution): Decimal[] => { + const index = getCreationIndex(contribution.contributionDate.getMonth()) + + if (index < 0) { + throw new Error('You cannot create GDD for a month older than the last three months.') + } + creations[index] = creations[index].plus(contribution.amount.toString()) + return creations +} From 03db4ed125cd2bcd7d7288f081bc25fa08b071af Mon Sep 17 00:00:00 2001 From: elweyn Date: Mon, 4 Jul 2022 07:41:21 +0200 Subject: [PATCH 021/114] Add mutation to updateContribution. --- .../resolver/ContributionResolver.test.ts | 24 ++++++++++++++++++- backend/src/seeds/graphql/mutations.ts | 14 +++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index 2308cd4e7..c9302cf64 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -2,7 +2,7 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' -import { createContribution } from '@/seeds/graphql/mutations' +import { createContribution, updateContribution } from '@/seeds/graphql/mutations' import { listContributions, login } from '@/seeds/graphql/queries' import { cleanDB, resetToken, testEnvironment } from '@test/helpers' import { GraphQLError } from 'graphql' @@ -212,4 +212,26 @@ describe('ContributionResolver', () => { }) }) }) + + describe('updateContribution', () => { + describe('unauthenticated', () => { + it('returns an error', async () => { + await expect( + mutate({ + mutation: updateContribution, + variables: { + contributionId: 1, + amount: 100.0, + memo: 'Test Contribution', + creationDate: 'not-valid', + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('401 Unauthorized')], + }), + ) + }) + }) + }) }) diff --git a/backend/src/seeds/graphql/mutations.ts b/backend/src/seeds/graphql/mutations.ts index 4926f706f..45adeacc8 100644 --- a/backend/src/seeds/graphql/mutations.ts +++ b/backend/src/seeds/graphql/mutations.ts @@ -239,3 +239,17 @@ export const createContribution = gql` } } ` + +export const updateContribution = gql` + mutation ($contributionId: Int!, $amount: Decimal!, $memo: String!, $creationDate: String!) { + updateContribution( + contributionId: $contributionId + amount: $amount + memo: $memo + creationDate: $creationDate + ) { + amount + memo + } + } +` From 7b38fe7f931ad45697d67d1d3ce4d06cb0e535ec Mon Sep 17 00:00:00 2001 From: elweyn Date: Mon, 4 Jul 2022 07:41:41 +0200 Subject: [PATCH 022/114] Function for updateContribution. --- .../graphql/resolver/ContributionResolver.ts | 41 ++++++++++++++++++- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 6669ef20d..2399593c2 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -2,7 +2,7 @@ import { RIGHTS } from '@/auth/RIGHTS' import { Context, getUser } from '@/server/context' import { backendLogger as logger } from '@/server/logger' import { Contribution as dbContribution } from '@entity/Contribution' -import { Arg, Args, Authorized, Ctx, Mutation, Query, Resolver } from 'type-graphql' +import { Arg, Args, Authorized, Ctx, Int, Mutation, Query, Resolver } from 'type-graphql' import { IsNull } from '../../../../database/node_modules/typeorm' import ContributionArgs from '../arg/ContributionArgs' import Paginated from '../arg/Paginated' @@ -10,7 +10,7 @@ import { Order } from '../enum/Order' import { Contribution } from '../model/Contribution' import { UnconfirmedContribution } from '../model/UnconfirmedContribution' import { User } from '../model/User' -import { isContributionValid, getUserCreation } from './util/isContributionValid' +import { isContributionValid, getUserCreation, updateCreations } from './util/isContributionValid' @Resolver() export class ContributionResolver { @@ -75,4 +75,41 @@ export class ContributionResolver { } return contribution.map((contr) => new Contribution(contr, new User(user))) } + + @Authorized([RIGHTS.UPDATE_CONTRIBUTION]) + @Mutation(() => UnconfirmedContribution) + async updateContribution( + @Arg('contributionId', () => Int) + contributionId: number, + @Args() { amount, memo, creationDate }: ContributionArgs, + @Ctx() context: Context, + ): Promise { + const user = getUser(context) + + const contributionToUpdate = await dbContribution.findOne({ + where: { id: contributionId, confirmedAt: IsNull() }, + }) + if (!contributionToUpdate) { + throw new Error('No contribution found to given id.') + } + if (contributionToUpdate.userId !== user.id) { + throw new Error('user of the pending contribution and send user does not correspond') + } + + const creationDateObj = new Date(creationDate) + let creations = await getUserCreation(user.id) + if (contributionToUpdate.contributionDate.getMonth() === creationDateObj.getMonth()) { + creations = updateCreations(creations, contributionToUpdate) + } + + // all possible cases not to be true are thrown in this function + isContributionValid(creations, amount, creationDateObj) + contributionToUpdate.amount = amount + contributionToUpdate.memo = memo + contributionToUpdate.contributionDate = new Date(creationDate) + dbContribution.save(contributionToUpdate) + + const result = new UnconfirmedContribution(contributionToUpdate, user, creations) + return result + } } From a99a568f391b9ea16ed5ee354c03260364d392fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Tue, 5 Jul 2022 04:20:54 +0200 Subject: [PATCH 023/114] emit Redeem-Events --- backend/src/graphql/model/Event.ts | 57 ++++++++++++++++++++ backend/src/graphql/resolver/UserResolver.ts | 15 +++++- 2 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 backend/src/graphql/model/Event.ts diff --git a/backend/src/graphql/model/Event.ts b/backend/src/graphql/model/Event.ts new file mode 100644 index 000000000..a8c0ef885 --- /dev/null +++ b/backend/src/graphql/model/Event.ts @@ -0,0 +1,57 @@ +import { ObjectType, Field } from 'type-graphql' +import { EventProtocol } from '@entity/EventProtocol' +import { EventProtocolType } from '@/event/EventProtocolType' +import Decimal from 'decimal.js-light' + +export interface EventInterface { + type: string + createdAt: Date + userId: number + xUserId?: number + xCommunityId?: number + transactionId?: number + contributionId?: number + amount?: Decimal +} + +@ObjectType() +export class Event { + constructor(event: EventProtocol) { + this.id = event.id + this.type = event.type + this.createdAt = event.createdAt + this.userId = event.userId + this.xUserId = event.xUserId + this.xCommunityId = event.xCommunityId + this.transactionId = event.transactionId + this.contributionId = event.contributionId + this.amount = event.amount + } + + @Field(() => Number) + id: number + + @Field(() => EventProtocolType) + type: string + + @Field(() => Date) + createdAt: Date + + @Field(() => Number) + userId: number + + @Field(() => Number, { nullable: true }) + xUserId: number | null + + @Field(() => Number, { nullable: true }) + xCommunityId: number | null + + @Field(() => Number, { nullable: true }) + transactionId: number | null + + @Field(() => Number, { nullable: true }) + contributionId: number | null + + @Field(() => Decimal) + amount: Decimal | null +} diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index f7ccb170b..ea4006779 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -23,7 +23,7 @@ import { sendAccountMultiRegistrationEmail } from '@/mailer/sendAccountMultiRegi import { klicktippSignIn } from '@/apis/KlicktippController' import { RIGHTS } from '@/auth/RIGHTS' import { hasElopageBuys } from '@/util/hasElopageBuys' -import { eventProtocol } from '@/event/EventProtocolEmitter' +import { EventInterface, eventProtocol } from '@/event/EventProtocolEmitter' import { EventProtocolType } from '@/event/EventProtocolType' // eslint-disable-next-line @typescript-eslint/no-var-requires @@ -374,6 +374,9 @@ export class UserResolver { // const encryptedPrivkey = SecretKeyCryptographyEncrypt(keyPair[1], passwordHash[1]) const emailHash = getEmailHash(email) + let eventType = EventProtocolType.REGISTER + let eventContributionId = null + let eventTransactionId = null const dbUser = new DbUser() dbUser.email = email dbUser.firstName = firstName @@ -391,6 +394,8 @@ export class UserResolver { logger.info('redeemCode found contributionLink=' + contributionLink) if (contributionLink) { dbUser.contributionLinkId = contributionLink.id + eventType = EventProtocolType.REDEEM_REGISTER + eventContributionId = contributionLink.id /* eventProtocol.emit( EventProtocolType.REDEEM_REGISTER, new Date(Date.now()), @@ -404,6 +409,8 @@ export class UserResolver { logger.info('redeemCode found transactionLink=' + transactionLink) if (transactionLink) { dbUser.referrerId = transactionLink.userId + eventType = EventProtocolType.REDEEM_REGISTER + eventTransactionId = transactionLink.id /* eventProtocol.emit( EventProtocolType.REDEEM_REGISTER, new Date(Date.now()), @@ -467,9 +474,13 @@ export class UserResolver { logger.info('createUser() successful...') eventProtocol.emit('writeEvent', { - type: EventProtocolType.REGISTER, + type: eventType, createdAt: new Date(), userId: dbUser.id, + xUserId: null, + xCommunityId: null, + transactionId: eventTransactionId, + contributionId: eventContributionId, }) return new User(dbUser) From 8e7476ecb07d0ede3ff6270f1077f18d93ec17a8 Mon Sep 17 00:00:00 2001 From: elweyn Date: Tue, 5 Jul 2022 09:07:29 +0200 Subject: [PATCH 024/114] Refactor return value so that their is only one return value. --- backend/src/graphql/resolver/ContributionResolver.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 2399593c2..f14aa4f36 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -109,7 +109,6 @@ export class ContributionResolver { contributionToUpdate.contributionDate = new Date(creationDate) dbContribution.save(contributionToUpdate) - const result = new UnconfirmedContribution(contributionToUpdate, user, creations) - return result + return new UnconfirmedContribution(contributionToUpdate, user, creations) } } From 61d4c138e1d196bd02f2c360555ec19866c80187 Mon Sep 17 00:00:00 2001 From: elweyn Date: Tue, 5 Jul 2022 09:17:48 +0200 Subject: [PATCH 025/114] Remove unused import. --- backend/src/graphql/resolver/AdminResolver.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index 962c13e9b..291ee6ed8 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -47,7 +47,6 @@ import { sendAccountActivationEmail } from '@/mailer/sendAccountActivationEmail' import { transactionLinkCode as contributionLinkCode } from './TransactionLinkResolver' import CONFIG from '@/config' import { - getCreationIndex, getUserCreation, getUserCreations, isContributionValid, From 9867bb6a6f7397d6fc8ce9ec78176076d18d5cf0 Mon Sep 17 00:00:00 2001 From: elweyn Date: Tue, 5 Jul 2022 09:21:29 +0200 Subject: [PATCH 026/114] Add RIGHT for DELETE_CONTRIBUTION. --- backend/src/auth/RIGHTS.ts | 1 + backend/src/auth/ROLES.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/backend/src/auth/RIGHTS.ts b/backend/src/auth/RIGHTS.ts index c10fc96de..abe600c99 100644 --- a/backend/src/auth/RIGHTS.ts +++ b/backend/src/auth/RIGHTS.ts @@ -26,6 +26,7 @@ export enum RIGHTS { LIST_TRANSACTION_LINKS = 'LIST_TRANSACTION_LINKS', GDT_BALANCE = 'GDT_BALANCE', CREATE_CONTRIBUTION = 'CREATE_CONTRIBUTION', + DELETE_CONTRIBUTION = 'DELETE_CONTRIBUTION', // Admin SEARCH_USERS = 'SEARCH_USERS', SET_USER_ROLE = 'SET_USER_ROLE', diff --git a/backend/src/auth/ROLES.ts b/backend/src/auth/ROLES.ts index 2d9ac2deb..539158986 100644 --- a/backend/src/auth/ROLES.ts +++ b/backend/src/auth/ROLES.ts @@ -24,6 +24,7 @@ export const ROLE_USER = new Role('user', [ RIGHTS.LIST_TRANSACTION_LINKS, RIGHTS.GDT_BALANCE, RIGHTS.CREATE_CONTRIBUTION, + RIGHTS.DELETE_CONTRIBUTION, ]) export const ROLE_ADMIN = new Role('admin', Object.values(RIGHTS)) // all rights From 62e7abe76efd5974f7840fbf8f881e28f0fa73ea Mon Sep 17 00:00:00 2001 From: elweyn Date: Tue, 5 Jul 2022 09:22:32 +0200 Subject: [PATCH 027/114] Add mutation to soft delete a contribution. --- .../src/graphql/resolver/ContributionResolver.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 924108f87..e75471c08 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -2,7 +2,7 @@ import { RIGHTS } from '@/auth/RIGHTS' import { Context, getUser } from '@/server/context' import { backendLogger as logger } from '@/server/logger' import { Contribution } from '@entity/Contribution' -import { Args, Authorized, Ctx, Mutation, Resolver } from 'type-graphql' +import { Arg, Args, Authorized, Ctx, Int, Mutation, Resolver } from 'type-graphql' import ContributionArgs from '../arg/ContributionArgs' import { UnconfirmedContribution } from '../model/UnconfirmedContribution' import { isContributionValid, getUserCreation } from './util/isContributionValid' @@ -32,4 +32,15 @@ export class ContributionResolver { await Contribution.save(contribution) return new UnconfirmedContribution(contribution, user, creations) } + + @Authorized([RIGHTS.DELETE_CONTRIBUTION]) + @Mutation(() => Boolean) + async adminDeleteContribution(@Arg('id', () => Int) id: number): Promise { + const contribution = await Contribution.findOne(id) + if (!contribution) { + throw new Error('Contribution not found for given id.') + } + const res = await contribution.softRemove() + return !!res + } } From 9bd57109333274928ed6056316fbe2cd0d9588ff Mon Sep 17 00:00:00 2001 From: elweyn Date: Tue, 5 Jul 2022 09:37:41 +0200 Subject: [PATCH 028/114] Add check if user is owner of the contribution before deleting. --- backend/src/graphql/resolver/ContributionResolver.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index e75471c08..bdd8e74a4 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -35,11 +35,18 @@ export class ContributionResolver { @Authorized([RIGHTS.DELETE_CONTRIBUTION]) @Mutation(() => Boolean) - async adminDeleteContribution(@Arg('id', () => Int) id: number): Promise { + async adminDeleteContribution( + @Arg('id', () => Int) id: number, + @Ctx() context: Context, + ): Promise { + const user = getUser(context) const contribution = await Contribution.findOne(id) if (!contribution) { throw new Error('Contribution not found for given id.') } + if (contribution.userId !== user.id) { + throw new Error('Can not delete contribution of another user') + } const res = await contribution.softRemove() return !!res } From be7a40be18fe497d7bdf02b6265930ab87c00dc3 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 5 Jul 2022 11:57:08 +0200 Subject: [PATCH 029/114] fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b98d0f741..75a9e7e55 100644 --- a/README.md +++ b/README.md @@ -123,7 +123,7 @@ Note: The Changelog will be regenerated with all tags on release on the external ## How the different .env work on deploy -Each component (frontend, admin, backend and database) has its own `.env` file. When running in development you usually do not have to care about the `.env`. The defaults are set by the respetive config file, found in the `src/config/` folder of each component. But if you have a local `.env`, the defaults set in the config are overwritten by the `.env`. +Each component (frontend, admin, backend and database) has its own `.env` file. When running in development you usually do not have to care about the `.env`. The defaults are set by the respective config file, found in the `src/config/` folder of each component. But if you have a local `.env`, the defaults set in the config are overwritten by the `.env`. Each component has a `.env.dist` file. This file contains all environment variables used by the component. If you want to use a local `.env`, copy the `.env.dist` and adjust the variables accordingly. From 3f706dc5f09deb3ff35513268dd215cf39349e1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Wed, 6 Jul 2022 02:30:04 +0200 Subject: [PATCH 030/114] add EventType specific handling --- backend/src/event/Event.ts | 314 +++++++++++++++++++++++++++++ backend/src/graphql/model/Event.ts | 57 ------ 2 files changed, 314 insertions(+), 57 deletions(-) create mode 100644 backend/src/event/Event.ts delete mode 100644 backend/src/graphql/model/Event.ts diff --git a/backend/src/event/Event.ts b/backend/src/event/Event.ts new file mode 100644 index 000000000..acfb43519 --- /dev/null +++ b/backend/src/event/Event.ts @@ -0,0 +1,314 @@ +import { EventProtocol } from '@entity/EventProtocol' +import decimal from 'decimal.js-light' +import { EventProtocolType } from './EventProtocolType' + +/* +export interface EventInterface { + type: string + createdAt: Date + userId: number + xUserId?: number + xCommunityId?: number + transactionId?: number + contributionId?: number + amount?: Decimal +} +*/ + +export class EventBasic { + type: string + createdAt: Date +} +export class EventBasicUserId extends EventBasic { + userId: number +} + +export class EventBasicTx extends EventBasicUserId { + xUserId: number + xCommunityId: number + transactionId: number + amount: decimal +} + +export class EventBasicCt extends EventBasicUserId { + contributionId: number + amount: decimal +} + +export class EventBasicRedeem extends EventBasicUserId { + transactionId?: number + contributionId?: number +} + +export class EventVisitGradido extends EventBasic { } +export class EventRegister extends EventBasicUserId { } +export class EventRedeemRegister extends EventBasicRedeem { } +export class EventInactiveAccount extends EventBasicUserId { } +export class EventSendConfirmationEmail extends EventBasicUserId { } +export class EventConfirmationEmail extends EventBasicUserId { } +export class EventRegisterEmailKlicktipp extends EventBasicUserId { } +export class EventLogin extends EventBasicUserId { } +export class EventRedeemLogin extends EventBasicRedeem { } +export class EventActivateAccount extends EventBasicUserId { } +export class EventPasswordChange extends EventBasicUserId { } +export class EventTransactionSend extends EventBasicTx { } +export class EventTransactionSendRedeem extends EventBasicTx { } +export class EventTransactionRepeateRedeem extends EventBasicTx { } +export class EventTransactionCreation extends EventBasicUserId { + transactionId: number + amount: decimal +} +export class EventTransactionReceive extends EventBasicTx { } +export class EventTransactionReceiveRedeem extends EventBasicTx { } +export class EventContributionCreate extends EventBasicCt { } +export class EventContributionConfirm extends EventBasicCt { + xUserId: number + xCommunityId: number +} +export class EventContributionLinkDefine extends EventBasicCt { } +export class EventContributionLinkActivateRedeem extends EventBasicCt { } + +export class Event { + constructor() + constructor(event?: EventProtocol) { + if (event) { + this.id = event.id + this.type = event.type + this.createdAt = event.createdAt + this.userId = event.userId + this.xUserId = event.xUserId + this.xCommunityId = event.xCommunityId + this.transactionId = event.transactionId + this.contributionId = event.contributionId + this.amount = event.amount + } + } + + public setEventBasic(ev?: EventBasic): Event { + this.type = EventProtocolType.BASIC + this.createdAt = new Date() + + return this + } + + public setEventVisitGradido(ev?: EventVisitGradido): Event { + this.setEventBasic(ev) + this.type = EventProtocolType.VISIT_GRADIDO + + return this + } + + public setEventRegister(ev: EventRegister): Event { + this.setByBasicUser(ev.userId) + this.type = EventProtocolType.REGISTER + + return this + } + + public setEventRedeemRegister(ev: EventRedeemRegister): Event { + this.setByBasicRedeem(ev.userId, ev.transactionId, ev.contributionId) + this.type = EventProtocolType.REDEEM_REGISTER + + return this + } + + public setEventInactiveAccount(ev: EventInactiveAccount): Event { + this.setByBasicUser(ev.userId) + this.type = EventProtocolType.INACTIVE_ACCOUNT + + return this + } + + public setEventSendConfirmationEmail(ev: EventSendConfirmationEmail): Event { + this.setByBasicUser(ev.userId) + this.type = EventProtocolType.SEND_CONFIRMATION_EMAIL + + return this + } + + public setEventConfirmationEmail(ev: EventConfirmationEmail): Event { + this.setByBasicUser(ev.userId) + this.type = EventProtocolType.CONFIRM_EMAIL + + return this + } + + public setEventRegisterEmailKlicktipp(ev: EventRegisterEmailKlicktipp): Event { + this.setByBasicUser(ev.userId) + this.type = EventProtocolType.REGISTER_EMAIL_KLICKTIPP + + return this + } + + public setEventLogin(ev: EventLogin): Event { + this.setByBasicUser(ev.userId) + this.type = EventProtocolType.LOGIN + + return this + } + + public setEventRedeemLogin(ev: EventRedeemLogin): Event { + this.setByBasicRedeem(ev.userId, ev.transactionId, ev.contributionId) + this.type = EventProtocolType.REDEEM_LOGIN + + return this + } + + public setEventActivateAccount(ev: EventActivateAccount): Event { + this.setByBasicUser(ev.userId) + this.type = EventProtocolType.ACTIVATE_ACCOUNT + + return this + } + + public setEventPasswordChange(ev: EventPasswordChange): Event { + this.setByBasicUser(ev.userId) + this.type = EventProtocolType.PASSWORD_CHANGE + + return this + } + + public setEventTransactionSend(ev: EventTransactionSend): Event { + this.setByBasicTx(ev.userId, ev.xUserId, ev.xCommunityId, ev.transactionId, ev.amount) + this.type = EventProtocolType.TRANSACTION_SEND + + return this + } + + public setEventTransactionSendRedeem(ev: EventTransactionSendRedeem): Event { + this.setByBasicTx(ev.userId, ev.xUserId, ev.xCommunityId, ev.transactionId, ev.amount) + this.type = EventProtocolType.TRANSACTION_SEND_REDEEM + + return this + } + + public setEventTransactionRepeateRedeem(ev: EventTransactionRepeateRedeem): Event { + this.setByBasicTx(ev.userId, ev.xUserId, ev.xCommunityId, ev.transactionId, ev.amount) + this.type = EventProtocolType.TRANSACTION_REPEATE_REDEEM + + return this + } + + public setEventTransactionCreation(ev: EventTransactionCreation): Event { + this.setByBasicUser(ev.userId) + if (ev.transactionId) this.transactionId = ev.transactionId + if (ev.amount) this.amount = ev.amount + this.type = EventProtocolType.TRANSACTION_CREATION + + return this + } + + public setEventTransactionReceive(ev: EventTransactionReceive): Event { + this.setByBasicTx(ev.userId, ev.xUserId, ev.xCommunityId, ev.transactionId, ev.amount) + this.type = EventProtocolType.TRANSACTION_RECEIVE + + return this + } + + public setEventTransactionReceiveRedeem(ev: EventTransactionReceiveRedeem): Event { + this.setByBasicTx(ev.userId, ev.xUserId, ev.xCommunityId, ev.transactionId, ev.amount) + this.type = EventProtocolType.TRANSACTION_RECEIVE_REDEEM + + return this + } + + public setEventContributionCreate(ev: EventContributionCreate): Event { + this.setByBasicCt(ev.userId, ev.contributionId, ev.amount) + this.type = EventProtocolType.CONTRIBUTION_CREATE + + return this + } + + public setEventContributionConfirm(ev: EventContributionConfirm): Event { + this.setByBasicCt(ev.userId, ev.contributionId, ev.amount) + if (ev.xUserId) this.xUserId = ev.xUserId + if (ev.xCommunityId) this.xCommunityId = ev.xCommunityId + this.type = EventProtocolType.CONTRIBUTION_CONFIRM + + return this + } + + public setEventContributionLinkDefine(ev: EventContributionLinkDefine): Event { + this.setByBasicCt(ev.userId, ev.contributionId, ev.amount) + this.type = EventProtocolType.CONTRIBUTION_LINK_DEFINE + + return this + } + + public setEventContributionLinkActivateRedeem(ev: EventContributionLinkActivateRedeem): Event { + this.setByBasicCt(ev.userId, ev.contributionId, ev.amount) + this.type = EventProtocolType.CONTRIBUTION_LINK_ACTIVATE_REDEEM + + return this + } + + setByBasicUser(userId: number): Event { + this.setEventBasic() + this.userId = userId + + return this + } + + setByBasicTx( + userId: number, + xUserId?: number, + xCommunityId?: number, + transactionId?: number, + amount?: decimal, + ): Event { + this.setByBasicUser(userId) + if (xUserId) this.xUserId = xUserId + if (xCommunityId) this.xCommunityId = xCommunityId + if (transactionId) this.transactionId = transactionId + if (amount) this.amount = amount + + return this + } + + setByBasicCt(userId: number, contributionId: number, amount?: decimal): Event { + this.setByBasicUser(userId) + if (contributionId) this.contributionId = contributionId + if (amount) this.amount = amount + + return this + } + + setByBasicRedeem(userId: number, transactionId?: number, contributionId?: number): Event { + this.setByBasicUser(userId) + if (transactionId) this.transactionId = transactionId + if (contributionId) this.contributionId = contributionId + + return this + } + + setByEventTransactionCreation(event: EventTransactionCreation): Event { + this.type = event.type + this.createdAt = event.createdAt + this.userId = event.userId + this.transactionId = event.transactionId + this.amount = event.amount + + return this + } + + setByEventContributionConfirm(event: EventContributionConfirm): Event { + this.type = event.type + this.createdAt = event.createdAt + this.userId = event.userId + this.xUserId = event.xUserId + this.xCommunityId = event.xCommunityId + this.amount = event.amount + + return this + } + + id: number + type: string + createdAt: Date + userId: number + xUserId?: number + xCommunityId?: number + transactionId?: number + contributionId?: number + amount?: decimal +} diff --git a/backend/src/graphql/model/Event.ts b/backend/src/graphql/model/Event.ts deleted file mode 100644 index a8c0ef885..000000000 --- a/backend/src/graphql/model/Event.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { ObjectType, Field } from 'type-graphql' -import { EventProtocol } from '@entity/EventProtocol' -import { EventProtocolType } from '@/event/EventProtocolType' -import Decimal from 'decimal.js-light' - -export interface EventInterface { - type: string - createdAt: Date - userId: number - xUserId?: number - xCommunityId?: number - transactionId?: number - contributionId?: number - amount?: Decimal -} - -@ObjectType() -export class Event { - constructor(event: EventProtocol) { - this.id = event.id - this.type = event.type - this.createdAt = event.createdAt - this.userId = event.userId - this.xUserId = event.xUserId - this.xCommunityId = event.xCommunityId - this.transactionId = event.transactionId - this.contributionId = event.contributionId - this.amount = event.amount - } - - @Field(() => Number) - id: number - - @Field(() => EventProtocolType) - type: string - - @Field(() => Date) - createdAt: Date - - @Field(() => Number) - userId: number - - @Field(() => Number, { nullable: true }) - xUserId: number | null - - @Field(() => Number, { nullable: true }) - xCommunityId: number | null - - @Field(() => Number, { nullable: true }) - transactionId: number | null - - @Field(() => Number, { nullable: true }) - contributionId: number | null - - @Field(() => Decimal) - amount: Decimal | null -} From 314e211a4f6f3602bfe42bc521b985bf4dbf873c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Wed, 6 Jul 2022 02:30:52 +0200 Subject: [PATCH 031/114] modify EventEmitter to new Eventtype specific handling --- backend/src/event/EventProtocolEmitter.ts | 380 +--------------------- 1 file changed, 14 insertions(+), 366 deletions(-) diff --git a/backend/src/event/EventProtocolEmitter.ts b/backend/src/event/EventProtocolEmitter.ts index 404d1090b..d4ecea27a 100644 --- a/backend/src/event/EventProtocolEmitter.ts +++ b/backend/src/event/EventProtocolEmitter.ts @@ -1,12 +1,22 @@ import { EventEmitter } from 'events' +import { Event } from '@/event/Event' import { backendLogger as logger } from '@/server/logger' // import { EventProtocolType } from './EventProtocolType' import { EventProtocol } from '@entity/EventProtocol' // import { getConnection } from '@dbTools/typeorm' -import Decimal from 'decimal.js-light' import CONFIG from '@/config' class EventProtocolEmitter extends EventEmitter { + private events: Event[] + + public addEvent(event: Event) { + this.events.push(event) + } + + public getEvents(): Event[] { + return this.events + } + public isEnabled() { logger.info(`EventProtocol - isEnabled=${CONFIG.EVENT_PROTOCOL_ENABLED}`) return CONFIG.EVENT_PROTOCOL_ENABLED @@ -18,379 +28,17 @@ eventProtocol.on('error', (err) => { logger.error(`ERROR in EventProtocol: ${err}`) }) -/* -eventProtocol.on(EventProtocolType.BASIC, async (createdAt: Date, userId: number) => { - logger.info( - `EventProtocol - ${EventProtocolType.BASIC}: createdAt=${createdAt}, userId=${userId}`, - ) - await writeEvent(EventProtocolType.BASIC, createdAt, userId, null, null, null, null, null) -}) - -eventProtocol.on(EventProtocolType.VISIT_GRADIDO, async (createdAt: Date, userId: number) => { - logger.info( - `EventProtocol - ${EventProtocolType.VISIT_GRADIDO}: createdAt=${createdAt}, userId=${userId}`, - ) - await writeEvent(EventProtocolType.VISIT_GRADIDO, createdAt, userId, null, null, null, null, null) -}) - -eventProtocol.on(EventProtocolType.REGISTER, async (createdAt: Date, userId: number) => { - logger.info( - `EventProtocol - ${EventProtocolType.REGISTER}: createdAt=${createdAt}, userId=${userId}`, - ) - await writeEvent(EventProtocolType.REGISTER, createdAt, userId, null, null, null, null, null) -}) - -eventProtocol.on( - EventProtocolType.REDEEM_REGISTER, - async (createdAt: Date, userId: number, transactionId: number, contributionId: number) => { - logger.info( - `EventProtocol - ${EventProtocolType.REDEEM_REGISTER}: createdAt=${createdAt}, userId=${userId}, transactionId=${transactionId}, contributionId=${contributionId}`, - ) - await writeEvent( - EventProtocolType.REDEEM_REGISTER, - createdAt, - userId, - null, - null, - transactionId, - contributionId, - null, - ) - }, -) - -eventProtocol.on(EventProtocolType.INACTIVE_ACCOUNT, async (createdAt: Date, userId: number) => { - logger.info( - `EventProtocol - ${EventProtocolType.INACTIVE_ACCOUNT}: createdAt=${createdAt}, userId=${userId}`, - ) - await writeEvent( - EventProtocolType.INACTIVE_ACCOUNT, - createdAt, - userId, - null, - null, - null, - null, - null, - ) -}) - -eventProtocol.on( - EventProtocolType.SEND_CONFIRMATION_EMAIL, - async (createdAt: Date, userId: number) => { - logger.info( - `EventProtocol - ${EventProtocolType.SEND_CONFIRMATION_EMAIL}: createdAt=${createdAt}, userId=${userId}`, - ) - await writeEvent( - EventProtocolType.SEND_CONFIRMATION_EMAIL, - createdAt, - userId, - null, - null, - null, - null, - null, - ) - }, -) - -eventProtocol.on(EventProtocolType.CONFIRM_EMAIL, async (createdAt: Date, userId: number) => { - logger.info( - `EventProtocol - ${EventProtocolType.CONFIRM_EMAIL}: createdAt=${createdAt}, userId=${userId}`, - ) - await writeEvent(EventProtocolType.CONFIRM_EMAIL, createdAt, userId, null, null, null, null, null) -}) - -eventProtocol.on( - EventProtocolType.REGISTER_EMAIL_KLICKTIPP, - async (createdAt: Date, userId: number) => { - logger.info( - `EventProtocol - ${EventProtocolType.REGISTER_EMAIL_KLICKTIPP}: createdAt=${createdAt}, userId=${userId}`, - ) - await writeEvent( - EventProtocolType.REGISTER_EMAIL_KLICKTIPP, - createdAt, - userId, - null, - null, - null, - null, - null, - ) - }, -) - -eventProtocol.on(EventProtocolType.LOGIN, async (createdAt: Date, userId: number) => { - logger.info( - `EventProtocol - ${EventProtocolType.LOGIN}: createdAt=${createdAt}, userId=${userId}`, - ) - await writeEvent(EventProtocolType.LOGIN, createdAt, userId, null, null, null, null, null) -}) - -eventProtocol.on( - EventProtocolType.REDEEM_LOGIN, - async (createdAt: Date, userId: number, transactionId: number, contributionId: number) => { - logger.info( - `EventProtocol - ${EventProtocolType.REDEEM_LOGIN}: createdAt=${createdAt}, userId=${userId}, transactionId=${transactionId}, contributionId=${contributionId}`, - ) - await writeEvent( - EventProtocolType.REDEEM_LOGIN, - createdAt, - userId, - null, - null, - transactionId, - contributionId, - null, - ) - }, -) - -eventProtocol.on(EventProtocolType.ACTIVATE_ACCOUNT, async (createdAt: Date, userId: number) => { - logger.info( - `EventProtocol - ${EventProtocolType.ACTIVATE_ACCOUNT}: createdAt=${createdAt}, userId=${userId}`, - ) - await writeEvent( - EventProtocolType.ACTIVATE_ACCOUNT, - createdAt, - userId, - null, - null, - null, - null, - null, - ) -}) - -eventProtocol.on(EventProtocolType.PASSWORD_CHANGE, async (createdAt: Date, userId: number) => { - logger.info( - `EventProtocol - ${EventProtocolType.PASSWORD_CHANGE}: createdAt=${createdAt}, userId=${userId}`, - ) - await writeEvent( - EventProtocolType.PASSWORD_CHANGE, - createdAt, - userId, - null, - null, - null, - null, - null, - ) -}) - -eventProtocol.on(EventProtocolType.TRANSACTION_SEND, async (createdAt: Date, userId: number) => { - logger.info( - `EventProtocol - ${EventProtocolType.TRANSACTION_SEND}: createdAt=${createdAt}, userId=${userId}`, - ) - await writeEvent( - EventProtocolType.TRANSACTION_SEND, - createdAt, - userId, - null, - null, - null, - null, - null, - ) -}) - -eventProtocol.on( - EventProtocolType.TRANSACTION_SEND_REDEEM, - async (createdAt: Date, userId: number) => { - logger.info( - `EventProtocol - ${EventProtocolType.TRANSACTION_SEND_REDEEM}: createdAt=${createdAt}, userId=${userId}`, - ) - await writeEvent( - EventProtocolType.TRANSACTION_SEND_REDEEM, - createdAt, - userId, - null, - null, - null, - null, - null, - ) - }, -) - -eventProtocol.on( - EventProtocolType.TRANSACTION_REPEATE_REDEEM, - async (createdAt: Date, userId: number) => { - logger.info( - `EventProtocol - ${EventProtocolType.TRANSACTION_REPEATE_REDEEM}: createdAt=${createdAt}, userId=${userId}`, - ) - await writeEvent( - EventProtocolType.TRANSACTION_REPEATE_REDEEM, - createdAt, - userId, - null, - null, - null, - null, - null, - ) - }, -) - -eventProtocol.on( - EventProtocolType.TRANSACTION_CREATION, - async (createdAt: Date, userId: number) => { - logger.info( - `EventProtocol - ${EventProtocolType.TRANSACTION_CREATION}: createdAt=${createdAt}, userId=${userId}`, - ) - await writeEvent( - EventProtocolType.TRANSACTION_CREATION, - createdAt, - userId, - null, - null, - null, - null, - null, - ) - }, -) - -eventProtocol.on(EventProtocolType.TRANSACTION_RECEIVE, async (createdAt: Date, userId: number) => { - logger.info( - `EventProtocol - ${EventProtocolType.TRANSACTION_RECEIVE}: createdAt=${createdAt}, userId=${userId}`, - ) - await writeEvent( - EventProtocolType.TRANSACTION_RECEIVE, - createdAt, - userId, - null, - null, - null, - null, - null, - ) -}) - -eventProtocol.on( - EventProtocolType.TRANSACTION_RECEIVE_REDEEM, - async (createdAt: Date, userId: number) => { - logger.info( - `EventProtocol - ${EventProtocolType.TRANSACTION_RECEIVE_REDEEM}: createdAt=${createdAt}, userId=${userId}`, - ) - await writeEvent( - EventProtocolType.TRANSACTION_RECEIVE_REDEEM, - createdAt, - userId, - null, - null, - null, - null, - null, - ) - }, -) - -eventProtocol.on( - EventProtocolType.CONTRIBUTION_CREATE, - async (createdAt: Date, userId: number, contributionId: number) => { - logger.info( - `EventProtocol - ${EventProtocolType.CONTRIBUTION_CREATE}: createdAt=${createdAt}, userId=${userId}, contributionId=${contributionId}`, - ) - await writeEvent( - EventProtocolType.CONTRIBUTION_CREATE, - createdAt, - userId, - null, - null, - null, - contributionId, - null, - ) - }, -) - -eventProtocol.on( - EventProtocolType.CONTRIBUTION_CONFIRM, - async ( - createdAt: Date, - userId: number, - xUserId: number, - xCommunityId: number, - contributionId: number, - ) => { - logger.info( - `EventProtocol - ${EventProtocolType.CONTRIBUTION_CONFIRM}: createdAt=${createdAt}, userId=${userId}, xUserId=${xUserId}, xCommunityId=${xCommunityId}, contributionId=${contributionId}`, - ) - await writeEvent( - EventProtocolType.CONTRIBUTION_CONFIRM, - createdAt, - userId, - xUserId, - xCommunityId, - null, - contributionId, - null, - ) - }, -) - -eventProtocol.on( - EventProtocolType.CONTRIBUTION_LINK_DEFINE, - async (createdAt: Date, userId: number) => { - logger.info( - `EventProtocol - ${EventProtocolType.CONTRIBUTION_LINK_DEFINE}: createdAt=${createdAt}, userId=${userId}`, - ) - await writeEvent( - EventProtocolType.CONTRIBUTION_LINK_DEFINE, - createdAt, - userId, - null, - null, - null, - null, - null, - ) - }, -) - -eventProtocol.on( - EventProtocolType.CONTRIBUTION_LINK_ACTIVATE_REDEEM, - async (createdAt: Date, userId: number) => { - logger.info( - `EventProtocol - ${EventProtocolType.CONTRIBUTION_LINK_ACTIVATE_REDEEM}: createdAt=${createdAt}, userId=${userId}`, - ) - await writeEvent( - EventProtocolType.CONTRIBUTION_LINK_ACTIVATE_REDEEM, - createdAt, - userId, - null, - null, - null, - null, - null, - ) - }, -) -*/ - -export interface EventInterface { - type: string - createdAt: Date - userId: number - xUserId?: number - xCommunityId?: number - transactionId?: number - contributionId?: number - amount?: Decimal -} - -eventProtocol.on('writeEvents', async (events: EventInterface[]) => { +eventProtocol.on('writeEvents', async (events: Event[]) => { for (let i = 0; i < events.length; i++) { await writeEvent(events[i]) } }) -eventProtocol.on('writeEvent', async (event: EventInterface) => { +eventProtocol.on('writeEvent', async (event: Event) => { await writeEvent(event) }) -const writeEvent = async (event: EventInterface): Promise => { +const writeEvent = async (event: Event): Promise => { // if (!eventProtocol.isEnabled()) return logger.info(`writeEvent(${JSON.stringify(event)})`) const dbEvent = new EventProtocol() From 575453fd549d90c00387b4ab78a54400acd0615d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Wed, 6 Jul 2022 02:31:37 +0200 Subject: [PATCH 032/114] modify event emitting on new event type specific usage --- backend/src/graphql/resolver/UserResolver.ts | 45 ++++++-------------- 1 file changed, 14 insertions(+), 31 deletions(-) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index ea4006779..b91b08d9f 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -23,8 +23,9 @@ import { sendAccountMultiRegistrationEmail } from '@/mailer/sendAccountMultiRegi import { klicktippSignIn } from '@/apis/KlicktippController' import { RIGHTS } from '@/auth/RIGHTS' import { hasElopageBuys } from '@/util/hasElopageBuys' -import { EventInterface, eventProtocol } from '@/event/EventProtocolEmitter' +import { eventProtocol } from '@/event/EventProtocolEmitter' import { EventProtocolType } from '@/event/EventProtocolType' +import { Event, EventRedeemRegister, EventRegister } from '@/event/Event' // eslint-disable-next-line @typescript-eslint/no-var-requires const sodium = require('sodium-native') @@ -374,9 +375,8 @@ export class UserResolver { // const encryptedPrivkey = SecretKeyCryptographyEncrypt(keyPair[1], passwordHash[1]) const emailHash = getEmailHash(email) - let eventType = EventProtocolType.REGISTER - let eventContributionId = null - let eventTransactionId = null + const eventRegister = new EventRegister() + const eventRedeemRegister = new EventRedeemRegister() const dbUser = new DbUser() dbUser.email = email dbUser.firstName = firstName @@ -394,30 +394,14 @@ export class UserResolver { logger.info('redeemCode found contributionLink=' + contributionLink) if (contributionLink) { dbUser.contributionLinkId = contributionLink.id - eventType = EventProtocolType.REDEEM_REGISTER - eventContributionId = contributionLink.id - /* eventProtocol.emit( - EventProtocolType.REDEEM_REGISTER, - new Date(Date.now()), - dbUser.id, - null, - contributionLink.id, - ) */ + eventRedeemRegister.contributionId = contributionLink.id } } else { const transactionLink = await dbTransactionLink.findOne({ code: redeemCode }) logger.info('redeemCode found transactionLink=' + transactionLink) if (transactionLink) { dbUser.referrerId = transactionLink.userId - eventType = EventProtocolType.REDEEM_REGISTER - eventTransactionId = transactionLink.id - /* eventProtocol.emit( - EventProtocolType.REDEEM_REGISTER, - new Date(Date.now()), - dbUser.id, - transactionLink.id, - null, - ) */ + eventRedeemRegister.transactionId = transactionLink.id } } } @@ -473,15 +457,14 @@ export class UserResolver { } logger.info('createUser() successful...') - eventProtocol.emit('writeEvent', { - type: eventType, - createdAt: new Date(), - userId: dbUser.id, - xUserId: null, - xCommunityId: null, - transactionId: eventTransactionId, - contributionId: eventContributionId, - }) + const event = new Event() + if (redeemCode) { + eventRedeemRegister.userId = dbUser.id + eventProtocol.emit('writeEvent', event.setEventRedeemRegister(eventRedeemRegister)) + } else { + eventRegister.userId = dbUser.id + eventProtocol.emit('writeEvent', event.setEventRegister(eventRegister)) + } return new User(dbUser) } From 127faf45cd072c3a3288fd94a82405f5132317ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Wed, 6 Jul 2022 03:04:11 +0200 Subject: [PATCH 033/114] Merge remote-tracking branch 'origin/master' into 1794-feature-event-protocol-1-implement-the-basics-of-the-business-event-protocol linting --- backend/src/event/Event.ts | 44 +++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/backend/src/event/Event.ts b/backend/src/event/Event.ts index acfb43519..c51acf627 100644 --- a/backend/src/event/Event.ts +++ b/backend/src/event/Event.ts @@ -40,33 +40,33 @@ export class EventBasicRedeem extends EventBasicUserId { contributionId?: number } -export class EventVisitGradido extends EventBasic { } -export class EventRegister extends EventBasicUserId { } -export class EventRedeemRegister extends EventBasicRedeem { } -export class EventInactiveAccount extends EventBasicUserId { } -export class EventSendConfirmationEmail extends EventBasicUserId { } -export class EventConfirmationEmail extends EventBasicUserId { } -export class EventRegisterEmailKlicktipp extends EventBasicUserId { } -export class EventLogin extends EventBasicUserId { } -export class EventRedeemLogin extends EventBasicRedeem { } -export class EventActivateAccount extends EventBasicUserId { } -export class EventPasswordChange extends EventBasicUserId { } -export class EventTransactionSend extends EventBasicTx { } -export class EventTransactionSendRedeem extends EventBasicTx { } -export class EventTransactionRepeateRedeem extends EventBasicTx { } +export class EventVisitGradido extends EventBasic {} +export class EventRegister extends EventBasicUserId {} +export class EventRedeemRegister extends EventBasicRedeem {} +export class EventInactiveAccount extends EventBasicUserId {} +export class EventSendConfirmationEmail extends EventBasicUserId {} +export class EventConfirmationEmail extends EventBasicUserId {} +export class EventRegisterEmailKlicktipp extends EventBasicUserId {} +export class EventLogin extends EventBasicUserId {} +export class EventRedeemLogin extends EventBasicRedeem {} +export class EventActivateAccount extends EventBasicUserId {} +export class EventPasswordChange extends EventBasicUserId {} +export class EventTransactionSend extends EventBasicTx {} +export class EventTransactionSendRedeem extends EventBasicTx {} +export class EventTransactionRepeateRedeem extends EventBasicTx {} export class EventTransactionCreation extends EventBasicUserId { transactionId: number amount: decimal } -export class EventTransactionReceive extends EventBasicTx { } -export class EventTransactionReceiveRedeem extends EventBasicTx { } -export class EventContributionCreate extends EventBasicCt { } +export class EventTransactionReceive extends EventBasicTx {} +export class EventTransactionReceiveRedeem extends EventBasicTx {} +export class EventContributionCreate extends EventBasicCt {} export class EventContributionConfirm extends EventBasicCt { xUserId: number xCommunityId: number } -export class EventContributionLinkDefine extends EventBasicCt { } -export class EventContributionLinkActivateRedeem extends EventBasicCt { } +export class EventContributionLinkDefine extends EventBasicCt {} +export class EventContributionLinkActivateRedeem extends EventBasicCt {} export class Event { constructor() @@ -84,15 +84,15 @@ export class Event { } } - public setEventBasic(ev?: EventBasic): Event { + public setEventBasic(): Event { this.type = EventProtocolType.BASIC this.createdAt = new Date() return this } - public setEventVisitGradido(ev?: EventVisitGradido): Event { - this.setEventBasic(ev) + public setEventVisitGradido(): Event { + this.setEventBasic() this.type = EventProtocolType.VISIT_GRADIDO return this From 4fb135cc36a9124f899fc18e536ce0ff16aeba6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Wed, 6 Jul 2022 03:05:05 +0200 Subject: [PATCH 034/114] new switch for event protocol enabling --- backend/.env.template | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/.env.template b/backend/.env.template index 94bf41550..764203d7f 100644 --- a/backend/.env.template +++ b/backend/.env.template @@ -50,3 +50,6 @@ EMAIL_CODE_REQUEST_TIME=$EMAIL_CODE_REQUEST_TIME # Webhook WEBHOOK_ELOPAGE_SECRET=$WEBHOOK_ELOPAGE_SECRET + +# EventProtocol +EVENT_PROTOCOL_ENABLED=true From 067e7c3ef7540e473bfa8f656803c6aa3234d900 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Wed, 6 Jul 2022 10:56:02 +0200 Subject: [PATCH 035/114] improve documentation --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 75a9e7e55..a707639ac 100644 --- a/README.md +++ b/README.md @@ -125,13 +125,13 @@ Note: The Changelog will be regenerated with all tags on release on the external Each component (frontend, admin, backend and database) has its own `.env` file. When running in development you usually do not have to care about the `.env`. The defaults are set by the respective config file, found in the `src/config/` folder of each component. But if you have a local `.env`, the defaults set in the config are overwritten by the `.env`. -Each component has a `.env.dist` file. This file contains all environment variables used by the component. If you want to use a local `.env`, copy the `.env.dist` and adjust the variables accordingly. +Each component has a `.env.dist` file. This file contains all environment variables used by the component and can be used as pattern. If you want to use a local `.env`, copy the `.env.dist` and adjust the variables accordingly. Each component has a `.env.template` file. These files are very important on deploy. -There is one `.env.dist` in the `deployment/bare_metal/` folder. This `.env` contains all variables used by the components. On deploy, we set all variables in this file. The deploy script loads this variables and provides them by the `.env.templates` of each component, creating a `.env` for each component. +There is one `.env.dist` in the `deployment/bare_metal/` folder. This `.env.dist` contains all variables used by the components, e.g. unites all `.env.dist` from the components. On deploy, we copy this `.env.dist` to `.env` and set all variables in this new file. The deploy script loads this variables and provides them by the `.env.templates` of each component, creating a `.env` for each component (see in `deployment/bare_metal/start.sh` the `envsubst`). -To avoid forgetting to update the global `.env` when deploying, we have a environment version variable inside the codebase of each component. You should update this version, when environment variables must be changed or added on deploy. The code checks, that the environement version provided by the `.env` is the one expected by the codebase. +To avoid forgetting to update an existing `.env` in the `deployment/bare_metal/` folder when deploying, we have a environment version variable inside the codebase of each component. You should update this version, when environment variables must be changed or added on deploy. The code checks, that the environement version provided by the `.env` is the one expected by the codebase. ## Troubleshooting From c570e5d2e5d67e621dfc5a2d7012f9fa094fa562 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Thu, 7 Jul 2022 01:47:07 +0200 Subject: [PATCH 036/114] Merge remote-tracking branch 'origin/master' into 1794-feature-event-protocol-1-implement-the-basics-of-the-business-event-protocol remove EnumEventType table --- .../0041-add_event_protocol_table/EnumEventType.ts | 13 ------------- database/entity/EnumEventType.ts | 1 - database/entity/index.ts | 2 -- .../migrations/0041-add_event_protocol_table.ts | 4 +++- 4 files changed, 3 insertions(+), 17 deletions(-) delete mode 100644 database/entity/0041-add_event_protocol_table/EnumEventType.ts delete mode 100644 database/entity/EnumEventType.ts diff --git a/database/entity/0041-add_event_protocol_table/EnumEventType.ts b/database/entity/0041-add_event_protocol_table/EnumEventType.ts deleted file mode 100644 index 814ac851b..000000000 --- a/database/entity/0041-add_event_protocol_table/EnumEventType.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { BaseEntity, Entity, Column, PrimaryColumn } from 'typeorm' - -@Entity('enum_event_type') -export class EnumEventType extends BaseEntity { - @PrimaryColumn({ name: 'key', length: 100, nullable: false, collation: 'utf8mb4_unicode_ci' }) - key: string - - @Column({ name: 'value', unsigned: true, nullable: false }) - value: number - - @Column({ length: 200, nullable: false, collation: 'utf8mb4_unicode_ci' }) - description: string -} diff --git a/database/entity/EnumEventType.ts b/database/entity/EnumEventType.ts deleted file mode 100644 index 5b581d25f..000000000 --- a/database/entity/EnumEventType.ts +++ /dev/null @@ -1 +0,0 @@ -export { EnumEventType } from './0041-add_event_protocol_table/EnumEventType' diff --git a/database/entity/index.ts b/database/entity/index.ts index 0974fe900..733c99a3a 100644 --- a/database/entity/index.ts +++ b/database/entity/index.ts @@ -7,7 +7,6 @@ import { TransactionLink } from './TransactionLink' import { User } from './User' import { Contribution } from './Contribution' import { EventProtocol } from './EventProtocol' -import { EnumEventType } from './EnumEventType' export const entities = [ Contribution, @@ -19,5 +18,4 @@ export const entities = [ TransactionLink, User, EventProtocol, - EnumEventType, ] diff --git a/database/migrations/0041-add_event_protocol_table.ts b/database/migrations/0041-add_event_protocol_table.ts index 191ef7f41..65155f238 100644 --- a/database/migrations/0041-add_event_protocol_table.ts +++ b/database/migrations/0041-add_event_protocol_table.ts @@ -20,6 +20,7 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis \`amount\` bigint(20) NULL DEFAULT NULL, PRIMARY KEY (\`id\`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;`) +/* await queryFn(` CREATE TABLE IF NOT EXISTS \`enum_event_type\` ( \`key\` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL, @@ -93,10 +94,11 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis await queryFn( `INSERT INTO \`enum_event_type\` (\`key\`, \`value\`, \`description\`) VALUES ('CONTRIBUTION_LINK_ACTIVATE_REDEEM', 71, 'ContributionLinkActivateRedeemEvent: the user activates a received contributionLink to create a contribution entry for the contributionLink');`, ) + */ } export async function downgrade(queryFn: (query: string, values?: any[]) => Promise>) { // write downgrade logic as parameter of queryFn await queryFn(`DROP TABLE IF EXISTS \`event_protocol\`;`) - await queryFn(`DROP TABLE IF EXISTS \`enum_event_type\`;`) + // await queryFn(`DROP TABLE IF EXISTS \`enum_event_type\`;`) } From 46e2473a88b828c65ae594a7f899b4d7a9a3e2c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Thu, 7 Jul 2022 01:48:33 +0200 Subject: [PATCH 037/114] remove EventEmitter from events-modul and replace it with writeEvent-Methode --- backend/src/event/EventProtocolEmitter.ts | 36 ++++++++++++----------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/backend/src/event/EventProtocolEmitter.ts b/backend/src/event/EventProtocolEmitter.ts index d4ecea27a..1040feb32 100644 --- a/backend/src/event/EventProtocolEmitter.ts +++ b/backend/src/event/EventProtocolEmitter.ts @@ -1,4 +1,3 @@ -import { EventEmitter } from 'events' import { Event } from '@/event/Event' import { backendLogger as logger } from '@/server/logger' // import { EventProtocolType } from './EventProtocolType' @@ -6,7 +5,8 @@ import { EventProtocol } from '@entity/EventProtocol' // import { getConnection } from '@dbTools/typeorm' import CONFIG from '@/config' -class EventProtocolEmitter extends EventEmitter { +class EventProtocolEmitter { + /* }extends EventEmitter { */ private events: Event[] public addEvent(event: Event) { @@ -21,9 +21,25 @@ class EventProtocolEmitter extends EventEmitter { logger.info(`EventProtocol - isEnabled=${CONFIG.EVENT_PROTOCOL_ENABLED}`) return CONFIG.EVENT_PROTOCOL_ENABLED } + + public async writeEvent(event: Event): Promise { + // if (!eventProtocol.isEnabled()) return + logger.info(`writeEvent(${JSON.stringify(event)})`) + const dbEvent = new EventProtocol() + dbEvent.type = event.type + dbEvent.createdAt = event.createdAt + dbEvent.userId = event.userId + if (event.xUserId) dbEvent.xUserId = event.xUserId + if (event.xCommunityId) dbEvent.xCommunityId = event.xCommunityId + if (event.contributionId) dbEvent.contributionId = event.contributionId + if (event.transactionId) dbEvent.transactionId = event.transactionId + if (event.amount) dbEvent.amount = event.amount + await dbEvent.save() + } } export const eventProtocol = new EventProtocolEmitter() +/* eventProtocol.on('error', (err) => { logger.error(`ERROR in EventProtocol: ${err}`) }) @@ -37,18 +53,4 @@ eventProtocol.on('writeEvents', async (events: Event[]) => { eventProtocol.on('writeEvent', async (event: Event) => { await writeEvent(event) }) - -const writeEvent = async (event: Event): Promise => { - // if (!eventProtocol.isEnabled()) return - logger.info(`writeEvent(${JSON.stringify(event)})`) - const dbEvent = new EventProtocol() - dbEvent.type = event.type - dbEvent.createdAt = event.createdAt - dbEvent.userId = event.userId - if (event.xUserId) dbEvent.xUserId = event.xUserId - if (event.xCommunityId) dbEvent.xCommunityId = event.xCommunityId - if (event.contributionId) dbEvent.contributionId = event.contributionId - if (event.transactionId) dbEvent.transactionId = event.transactionId - if (event.amount) dbEvent.amount = event.amount - await dbEvent.save() -} +*/ From d6fe7985453b365ce861451012a68198b96c4f8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Thu, 7 Jul 2022 01:49:16 +0200 Subject: [PATCH 038/114] replace event emitting with event writing --- backend/src/graphql/resolver/UserResolver.ts | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index b91b08d9f..ff687bb3a 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -24,8 +24,7 @@ import { klicktippSignIn } from '@/apis/KlicktippController' import { RIGHTS } from '@/auth/RIGHTS' import { hasElopageBuys } from '@/util/hasElopageBuys' import { eventProtocol } from '@/event/EventProtocolEmitter' -import { EventProtocolType } from '@/event/EventProtocolType' -import { Event, EventRedeemRegister, EventRegister } from '@/event/Event' +import { Event, EventLogin, EventRedeemRegister, EventRegister } from '@/event/Event' // eslint-disable-next-line @typescript-eslint/no-var-requires const sodium = require('sodium-native') @@ -293,11 +292,9 @@ export class UserResolver { key: 'token', value: encode(dbUser.pubKey), }) - eventProtocol.emit('writeEvent', { - type: EventProtocolType.LOGIN, - createdAt: new Date(), - userId: user.id, - }) + const ev = new EventLogin() + ev.userId = user.id + eventProtocol.writeEvent(new Event().setEventLogin(ev)) logger.info('successful Login:' + user) return user } @@ -460,10 +457,10 @@ export class UserResolver { const event = new Event() if (redeemCode) { eventRedeemRegister.userId = dbUser.id - eventProtocol.emit('writeEvent', event.setEventRedeemRegister(eventRedeemRegister)) + eventProtocol.writeEvent(event.setEventRedeemRegister(eventRedeemRegister)) } else { eventRegister.userId = dbUser.id - eventProtocol.emit('writeEvent', event.setEventRegister(eventRegister)) + eventProtocol.writeEvent(event.setEventRegister(eventRegister)) } return new User(dbUser) From 642a3e647c7cf2b5a6408df0925fdbfa0ebeac4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Thu, 7 Jul 2022 02:53:04 +0200 Subject: [PATCH 039/114] increase CONFIG_VERSION after adding Event-Protocol Switch --- backend/src/config/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index 5e0978f3b..8903752c0 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -17,7 +17,7 @@ const constants = { LOG_LEVEL: process.env.LOG_LEVEL || 'info', CONFIG_VERSION: { DEFAULT: 'DEFAULT', - EXPECTED: 'v8.2022-06-20', + EXPECTED: 'v9.2022-07-07', CURRENT: '', }, } From 859ac2cebd13ca52878661ac9facc3e0798bd9a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Thu, 7 Jul 2022 02:53:43 +0200 Subject: [PATCH 040/114] increase CONFIG_VERSION --- backend/.env.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/.env.dist b/backend/.env.dist index 0d1a14d7c..0e8148a8a 100644 --- a/backend/.env.dist +++ b/backend/.env.dist @@ -1,4 +1,4 @@ -CONFIG_VERSION=v8.2022-06-20 +CONFIG_VERSION=v9.2022-07-07 # Server PORT=4000 From 1543c568aecce88311f3066a9d4f025d3b5f3e04 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 7 Jul 2022 13:47:14 +0200 Subject: [PATCH 041/114] Update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Wolfgang Huß --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a707639ac..d12edfb89 100644 --- a/README.md +++ b/README.md @@ -129,7 +129,7 @@ Each component has a `.env.dist` file. This file contains all environment variab Each component has a `.env.template` file. These files are very important on deploy. -There is one `.env.dist` in the `deployment/bare_metal/` folder. This `.env.dist` contains all variables used by the components, e.g. unites all `.env.dist` from the components. On deploy, we copy this `.env.dist` to `.env` and set all variables in this new file. The deploy script loads this variables and provides them by the `.env.templates` of each component, creating a `.env` for each component (see in `deployment/bare_metal/start.sh` the `envsubst`). +There is one `.env.dist` in the `deployment/bare_metal/` folder. This `.env.dist` contains all variables used by the components, e.g. unites all `.env.dist` from the components. On deploy, we copy this `.env.dist` to `.env` and set all variables in this new file. The deploy script loads this variables and provides them by the `.env.templates` of each component, creating an `.env` for each component (see in `deployment/bare_metal/start.sh` the `envsubst`). To avoid forgetting to update an existing `.env` in the `deployment/bare_metal/` folder when deploying, we have a environment version variable inside the codebase of each component. You should update this version, when environment variables must be changed or added on deploy. The code checks, that the environement version provided by the `.env` is the one expected by the codebase. From 9840017f0cd0048ad0bd561ecbb6cc56876632cc Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 7 Jul 2022 13:47:24 +0200 Subject: [PATCH 042/114] Update README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Wolfgang Huß --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d12edfb89..145ce4141 100644 --- a/README.md +++ b/README.md @@ -131,7 +131,7 @@ Each component has a `.env.template` file. These files are very important on dep There is one `.env.dist` in the `deployment/bare_metal/` folder. This `.env.dist` contains all variables used by the components, e.g. unites all `.env.dist` from the components. On deploy, we copy this `.env.dist` to `.env` and set all variables in this new file. The deploy script loads this variables and provides them by the `.env.templates` of each component, creating an `.env` for each component (see in `deployment/bare_metal/start.sh` the `envsubst`). -To avoid forgetting to update an existing `.env` in the `deployment/bare_metal/` folder when deploying, we have a environment version variable inside the codebase of each component. You should update this version, when environment variables must be changed or added on deploy. The code checks, that the environement version provided by the `.env` is the one expected by the codebase. +To avoid forgetting to update an existing `.env` in the `deployment/bare_metal/` folder when deploying, we have an environment version variable inside the codebase of each component. You should update this version, when environment variables must be changed or added on deploy. The code checks, that the environement version provided by the `.env` is the one expected by the codebase. ## Troubleshooting From 5369aced43ee60b6788c6a00ca492efaa6f0452e Mon Sep 17 00:00:00 2001 From: elweyn Date: Tue, 12 Jul 2022 09:37:06 +0200 Subject: [PATCH 043/114] Change mutation to include id in the result, write test to update contribution with inexistent id. --- .../resolver/ContributionResolver.test.ts | 53 +++++++++++++++++++ backend/src/seeds/graphql/mutations.ts | 1 + 2 files changed, 54 insertions(+) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index c9302cf64..697c5ae43 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -13,6 +13,7 @@ import { peterLustig } from '@/seeds/users/peter-lustig' let mutate: any, query: any, con: any let testEnv: any +let result: any beforeAll(async () => { testEnv = await testEnvironment() @@ -159,6 +160,14 @@ describe('ContributionResolver', () => { query: login, variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, }) + await mutate({ + mutation: createContribution, + variables: { + amount: 100.0, + memo: 'Test env contribution', + creationDate: new Date().toString(), + }, + }) }) afterAll(async () => { @@ -233,5 +242,49 @@ describe('ContributionResolver', () => { ) }) }) + + describe('authenticated', () => { + beforeAll(async () => { + await userFactory(testEnv, peterLustig) + await userFactory(testEnv, bibiBloxberg) + // bibi needs GDDs + const bibisCreation = creations.find((creation) => creation.email === 'bibi@bloxberg.de') + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + await creationFactory(testEnv, bibisCreation!) + // await userFactory(testEnv, bibiBloxberg) + await query({ + query: login, + variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, + }) + result = await mutate({ + mutation: createContribution, + variables: { + amount: 100.0, + memo: 'Test env contribution', + creationDate: new Date().toString(), + }, + }) + }) + + describe('wrong contribution id', () => { + it('throws an error', async () => { + await expect( + mutate({ + mutation: updateContribution, + variables: { + contributionId: -1, + amount: 100.0, + memo: 'Test env contribution', + creationDate: new Date().toString(), + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('No contribution found to given id.')], + }), + ) + }) + }) + }) }) }) diff --git a/backend/src/seeds/graphql/mutations.ts b/backend/src/seeds/graphql/mutations.ts index 45adeacc8..bfa9847e0 100644 --- a/backend/src/seeds/graphql/mutations.ts +++ b/backend/src/seeds/graphql/mutations.ts @@ -234,6 +234,7 @@ export const deleteContributionLink = gql` export const createContribution = gql` mutation ($amount: Decimal!, $memo: String!, $creationDate: String!) { createContribution(amount: $amount, memo: $memo, creationDate: $creationDate) { + id amount memo } From 86433478ec24dd58de4f6dcbd6f8560836eabe30 Mon Sep 17 00:00:00 2001 From: elweyn Date: Tue, 12 Jul 2022 09:38:19 +0200 Subject: [PATCH 044/114] Test that only the user that created the contribution can update it with the updateContribution mutation. --- .../resolver/ContributionResolver.test.ts | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index 697c5ae43..41b5808a1 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -285,6 +285,37 @@ describe('ContributionResolver', () => { ) }) }) + + describe('wrong user tries to update the contribution', () => { + beforeAll(async () => { + await query({ + query: login, + variables: { email: 'peter@lustig.de', password: 'Aa12345_' }, + }) + }) + + it('throws an error', async () => { + await expect( + mutate({ + mutation: updateContribution, + variables: { + contributionId: result.data.createContribution.id, + amount: 10.0, + memo: 'Test env contribution', + creationDate: new Date().toString(), + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [ + new GraphQLError( + 'user of the pending contribution and send user does not correspond', + ), + ], + }), + ) + }) + }) }) }) }) From 6348756ab31a18fd1fcb7946918d8fc20a911487 Mon Sep 17 00:00:00 2001 From: elweyn Date: Tue, 12 Jul 2022 09:39:24 +0200 Subject: [PATCH 045/114] Test that the updateContribution mutation can not update more gdd's than allowed in the month. --- .../resolver/ContributionResolver.test.ts | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index 41b5808a1..bdb8453da 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -316,6 +316,37 @@ describe('ContributionResolver', () => { ) }) }) + + describe('update to much so that the limit is exceeded', () => { + beforeAll(async () => { + await query({ + query: login, + variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, + }) + }) + + it('throws an error', async () => { + await expect( + mutate({ + mutation: updateContribution, + variables: { + contributionId: result.data.createContribution.id, + amount: 1019.0, + memo: 'Test env contribution', + creationDate: new Date().toString(), + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [ + new GraphQLError( + 'The amount (1019 GDD) to be created exceeds the amount (1000 GDD) still available for this month.', + ), + ], + }), + ) + }) + }) }) }) }) From 9e355f9202d05e208dcaf36438bfae489d3c8521 Mon Sep 17 00:00:00 2001 From: elweyn Date: Tue, 12 Jul 2022 09:43:47 +0200 Subject: [PATCH 046/114] Test that the updateContribution mutation can not update contribution to a date that is older than 3 month. --- .../resolver/ContributionResolver.test.ts | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index bdb8453da..d3d42be86 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -347,6 +347,29 @@ describe('ContributionResolver', () => { ) }) }) + + describe('update creation to a date that is older than 3 month', () => { + it('throws an error', async () => { + const date = new Date() // , + await expect( + mutate({ + mutation: updateContribution, + variables: { + contributionId: result.data.createContribution.id, + amount: 1019.0, + memo: 'Test env contribution', + creationDate: date.setMonth(date.getMonth() - 3).toString(), + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [ + new GraphQLError('No information for available creations for the given date'), + ], + }), + ) + }) + }) }) }) }) From 9ee40767bbf019e5ed44ed732909d287b00c6fb0 Mon Sep 17 00:00:00 2001 From: elweyn Date: Tue, 12 Jul 2022 09:45:48 +0200 Subject: [PATCH 047/114] Change test so that only the date is to old and the amount could be right. --- backend/src/graphql/resolver/ContributionResolver.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index d3d42be86..31d46e2ae 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -356,7 +356,7 @@ describe('ContributionResolver', () => { mutation: updateContribution, variables: { contributionId: result.data.createContribution.id, - amount: 1019.0, + amount: 10.0, memo: 'Test env contribution', creationDate: date.setMonth(date.getMonth() - 3).toString(), }, From c6ae5760c3072bb89d4d68f395062f1b7eff208a Mon Sep 17 00:00:00 2001 From: elweyn Date: Tue, 12 Jul 2022 09:55:03 +0200 Subject: [PATCH 048/114] Test that the updateContribution mutation updates the contribution with the right values. --- .../resolver/ContributionResolver.test.ts | 26 +++++++++++++++++++ backend/src/seeds/graphql/mutations.ts | 1 + 2 files changed, 27 insertions(+) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index 31d46e2ae..3c8046bc2 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -370,6 +370,32 @@ describe('ContributionResolver', () => { ) }) }) + + describe('valid input', () => { + it('updates contribution', async () => { + await expect( + mutate({ + mutation: updateContribution, + variables: { + contributionId: result.data.createContribution.id, + amount: 10.0, + memo: 'Test contribution', + creationDate: new Date().toString(), + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + data: { + updateContribution: { + id: result.data.createContribution.id, + amount: '10', + memo: 'Test contribution', + }, + }, + }), + ) + }) + }) }) }) }) diff --git a/backend/src/seeds/graphql/mutations.ts b/backend/src/seeds/graphql/mutations.ts index bfa9847e0..4e7fa8a90 100644 --- a/backend/src/seeds/graphql/mutations.ts +++ b/backend/src/seeds/graphql/mutations.ts @@ -249,6 +249,7 @@ export const updateContribution = gql` memo: $memo creationDate: $creationDate ) { + id amount memo } From b991bb0467035a5c18aa409ca99b93292fea41cd Mon Sep 17 00:00:00 2001 From: elweyn Date: Tue, 12 Jul 2022 10:11:28 +0200 Subject: [PATCH 049/114] Delete datas after all listContributions and updateContribution Tests. --- .../src/graphql/resolver/ContributionResolver.test.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index f690e10b1..a1f274fc6 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -169,6 +169,11 @@ describe('ContributionResolver', () => { }) }) + afterAll(async () => { + await cleanDB() + resetToken() + }) + describe('filter confirmed is false', () => { it('returns creations', async () => { await expect( @@ -276,6 +281,11 @@ describe('ContributionResolver', () => { }) }) + afterAll(async () => { + await cleanDB() + resetToken() + }) + describe('wrong contribution id', () => { it('throws an error', async () => { await expect( From 0380609deeea78f4713205c3e0b217814ac2b018 Mon Sep 17 00:00:00 2001 From: Hannes Heine Date: Tue, 12 Jul 2022 12:54:46 +0200 Subject: [PATCH 050/114] Update backend/src/graphql/resolver/ContributionResolver.test.ts Co-authored-by: Moriz Wahl --- backend/src/graphql/resolver/ContributionResolver.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index a1f274fc6..a5c9b2f55 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -368,7 +368,7 @@ describe('ContributionResolver', () => { }) }) - describe('update creation to a date that is older than 3 month', () => { + describe('update creation to a date that is older than 3 months', () => { it('throws an error', async () => { const date = new Date() // , await expect( From 90d2ffbff3bc91713510a1817dcb10f901197a66 Mon Sep 17 00:00:00 2001 From: Hannes Heine Date: Tue, 12 Jul 2022 12:54:55 +0200 Subject: [PATCH 051/114] Update backend/src/graphql/resolver/ContributionResolver.test.ts Co-authored-by: Moriz Wahl --- backend/src/graphql/resolver/ContributionResolver.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index a5c9b2f55..731a897c1 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -370,7 +370,7 @@ describe('ContributionResolver', () => { describe('update creation to a date that is older than 3 months', () => { it('throws an error', async () => { - const date = new Date() // , + const date = new Date() await expect( mutate({ mutation: updateContribution, From 32d79bb61cdf19adee86e0403977e3f54255773f Mon Sep 17 00:00:00 2001 From: elweyn Date: Tue, 12 Jul 2022 13:01:46 +0200 Subject: [PATCH 052/114] Corrected the spelling errors and withdrew admin creation on update scenario. --- backend/src/graphql/resolver/ContributionResolver.test.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index 731a897c1..394d9fc7d 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -262,11 +262,6 @@ describe('ContributionResolver', () => { beforeAll(async () => { await userFactory(testEnv, peterLustig) await userFactory(testEnv, bibiBloxberg) - // bibi needs GDDs - const bibisCreation = creations.find((creation) => creation.email === 'bibi@bloxberg.de') - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - await creationFactory(testEnv, bibisCreation!) - // await userFactory(testEnv, bibiBloxberg) await query({ query: login, variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, @@ -337,7 +332,7 @@ describe('ContributionResolver', () => { }) }) - describe('update to much so that the limit is exceeded', () => { + describe('update too much so that the limit is exceeded', () => { beforeAll(async () => { await query({ query: login, From 3e471eb81ee0037e40c6d127e90ef546250378aa Mon Sep 17 00:00:00 2001 From: ogerly Date: Tue, 12 Jul 2022 16:54:37 +0200 Subject: [PATCH 053/114] add creation on login query and store --- frontend/src/graphql/queries.js | 2 ++ frontend/src/store/store.js | 6 ++++++ frontend/src/store/store.test.js | 25 +++++++++++++++++++++++-- 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/frontend/src/graphql/queries.js b/frontend/src/graphql/queries.js index adcd653a4..27e63d568 100644 --- a/frontend/src/graphql/queries.js +++ b/frontend/src/graphql/queries.js @@ -13,6 +13,7 @@ export const login = gql` hasElopage publisherId isAdmin + creation } } ` @@ -30,6 +31,7 @@ export const verifyLogin = gql` hasElopage publisherId isAdmin + creation } } ` diff --git a/frontend/src/store/store.js b/frontend/src/store/store.js index e95eec7b9..8fdbc519e 100644 --- a/frontend/src/store/store.js +++ b/frontend/src/store/store.js @@ -47,6 +47,9 @@ export const mutations = { hasElopage: (state, hasElopage) => { state.hasElopage = hasElopage }, + creation: (state, creation) => { + state.creation = creation + }, } export const actions = { @@ -60,6 +63,7 @@ export const actions = { commit('hasElopage', data.hasElopage) commit('publisherId', data.publisherId) commit('isAdmin', data.isAdmin) + commit('creation', data.creation) }, logout: ({ commit, state }) => { commit('token', null) @@ -71,6 +75,7 @@ export const actions = { commit('hasElopage', false) commit('publisherId', null) commit('isAdmin', false) + commit('creation', null) localStorage.clear() }, } @@ -96,6 +101,7 @@ try { newsletterState: null, hasElopage: false, publisherId: null, + creation: null, }, getters: {}, // Syncronous mutation of the state diff --git a/frontend/src/store/store.test.js b/frontend/src/store/store.test.js index 3f942fa35..0493d7f53 100644 --- a/frontend/src/store/store.test.js +++ b/frontend/src/store/store.test.js @@ -30,6 +30,7 @@ const { publisherId, isAdmin, hasElopage, + creation, } = mutations const { login, logout } = actions @@ -139,6 +140,14 @@ describe('Vuex store', () => { expect(state.hasElopage).toBeTruthy() }) }) + + describe('creation', () => { + it('sets the state of creation', () => { + const state = { creation: null } + creation(state, true) + expect(state.creation).toEqual(true) + }) + }) }) describe('actions', () => { @@ -156,11 +165,12 @@ describe('Vuex store', () => { hasElopage: false, publisherId: 1234, isAdmin: true, + creation: ['1000', '1000', '1000'], } it('calls nine commits', () => { login({ commit, state }, commitedData) - expect(commit).toHaveBeenCalledTimes(8) + expect(commit).toHaveBeenCalledTimes(9) }) it('commits email', () => { @@ -202,6 +212,11 @@ describe('Vuex store', () => { login({ commit, state }, commitedData) expect(commit).toHaveBeenNthCalledWith(8, 'isAdmin', true) }) + + it('commits creation', () => { + login({ commit, state }, commitedData) + expect(commit).toHaveBeenNthCalledWith(9, 'creation', ['1000', '1000', '1000']) + }) }) describe('logout', () => { @@ -210,7 +225,7 @@ describe('Vuex store', () => { it('calls nine commits', () => { logout({ commit, state }) - expect(commit).toHaveBeenCalledTimes(8) + expect(commit).toHaveBeenCalledTimes(9) }) it('commits token', () => { @@ -253,6 +268,12 @@ describe('Vuex store', () => { expect(commit).toHaveBeenNthCalledWith(8, 'isAdmin', false) }) + it('commits creation', () => { + logout({ commit, state }) + expect(commit).toHaveBeenNthCalledWith(9, 'creation', null) + }) + + // how to get this working? it.skip('calls localStorage.clear()', () => { const clearStorageMock = jest.fn() From bc8078c427883aa5192a5d1b54556fb8f285e5d6 Mon Sep 17 00:00:00 2001 From: ogerly Date: Tue, 12 Jul 2022 16:55:50 +0200 Subject: [PATCH 054/114] fix lint --- frontend/src/store/store.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/store/store.test.js b/frontend/src/store/store.test.js index 0493d7f53..651a3ccc5 100644 --- a/frontend/src/store/store.test.js +++ b/frontend/src/store/store.test.js @@ -273,7 +273,6 @@ describe('Vuex store', () => { expect(commit).toHaveBeenNthCalledWith(9, 'creation', null) }) - // how to get this working? it.skip('calls localStorage.clear()', () => { const clearStorageMock = jest.fn() From 1a2bb1a29a1b3d24f64fee37ac8b2bf7fe7e2702 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Wed, 13 Jul 2022 01:59:37 +0200 Subject: [PATCH 055/114] add eventSendConfirmEmail during createUser() --- backend/src/graphql/resolver/UserResolver.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 26a265071..55ed76e01 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -24,7 +24,7 @@ import { klicktippSignIn } from '@/apis/KlicktippController' import { RIGHTS } from '@/auth/RIGHTS' import { hasElopageBuys } from '@/util/hasElopageBuys' import { eventProtocol } from '@/event/EventProtocolEmitter' -import { Event, EventLogin, EventRedeemRegister, EventRegister } from '@/event/Event' +import { Event, EventLogin, EventRedeemRegister, EventRegister, EventSendConfirmationEmail } from '@/event/Event' import { getUserCreation } from './util/creations' // eslint-disable-next-line @typescript-eslint/no-var-requires @@ -375,6 +375,7 @@ export class UserResolver { const eventRegister = new EventRegister() const eventRedeemRegister = new EventRedeemRegister() + const eventSendConfirmEmail = new EventSendConfirmationEmail() const dbUser = new DbUser() dbUser.email = email dbUser.firstName = firstName @@ -410,6 +411,7 @@ export class UserResolver { // loginUser.pubKey = keyPair[0] // loginUser.privKey = encryptedPrivkey + const event = new Event() const queryRunner = getConnection().createQueryRunner() await queryRunner.connect() await queryRunner.startTransaction('READ UNCOMMITTED') @@ -439,6 +441,9 @@ export class UserResolver { duration: printTimeDuration(CONFIG.EMAIL_CODE_VALID_TIME), }) logger.info(`sendAccountActivationEmail of ${firstName}.${lastName} to ${email}`) + eventSendConfirmEmail.userId = dbUser.id + eventProtocol.writeEvent(event.setEventSendConfirmationEmail(eventSendConfirmEmail)) + /* uncomment this, when you need the activation link on the console */ // In case EMails are disabled log the activation link for the user if (!emailSent) { @@ -455,7 +460,6 @@ export class UserResolver { } logger.info('createUser() successful...') - const event = new Event() if (redeemCode) { eventRedeemRegister.userId = dbUser.id eventProtocol.writeEvent(event.setEventRedeemRegister(eventRedeemRegister)) From 63d84199b018c9a126f7af98038c48fd777cdb6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Wed, 13 Jul 2022 02:06:36 +0200 Subject: [PATCH 056/114] linting --- backend/src/graphql/resolver/UserResolver.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 55ed76e01..a89a8cb0b 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -24,7 +24,13 @@ import { klicktippSignIn } from '@/apis/KlicktippController' import { RIGHTS } from '@/auth/RIGHTS' import { hasElopageBuys } from '@/util/hasElopageBuys' import { eventProtocol } from '@/event/EventProtocolEmitter' -import { Event, EventLogin, EventRedeemRegister, EventRegister, EventSendConfirmationEmail } from '@/event/Event' +import { + Event, + EventLogin, + EventRedeemRegister, + EventRegister, + EventSendConfirmationEmail, +} from '@/event/Event' import { getUserCreation } from './util/creations' // eslint-disable-next-line @typescript-eslint/no-var-requires From c6bab99a2c96e8fcdf80e72c7878ec8e9f5502c2 Mon Sep 17 00:00:00 2001 From: elweyn Date: Wed, 13 Jul 2022 08:26:30 +0200 Subject: [PATCH 057/114] Add Test that adminUpdateContribution is not allowed on creation made by createContribution mutation. --- .../resolver/ContributionResolver.test.ts | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index 394d9fc7d..75d6d1128 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -2,7 +2,7 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' -import { createContribution, updateContribution } from '@/seeds/graphql/mutations' +import { adminUpdateContribution, createContribution, updateContribution } from '@/seeds/graphql/mutations' import { listContributions, login } from '@/seeds/graphql/queries' import { cleanDB, resetToken, testEnvironment } from '@test/helpers' import { GraphQLError } from 'graphql' @@ -332,6 +332,27 @@ describe('ContributionResolver', () => { }) }) + describe('admin tries to update a user contribution', () => { + it('throws an error', async () => { + await expect( + mutate({ + mutation: adminUpdateContribution, + variables: { + id: result.data.createContribution.id, + email: 'bibi@bloxberg.de', + amount: 10.0, + memo: 'Test env contribution', + creationDate: new Date().toString(), + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('An admin is not allowed to update a user contribution.')], + }), + ) + }) + }) + describe('update too much so that the limit is exceeded', () => { beforeAll(async () => { await query({ From 801e223cfd29398004b267ced763eb9d530421f7 Mon Sep 17 00:00:00 2001 From: elweyn Date: Wed, 13 Jul 2022 08:27:05 +0200 Subject: [PATCH 058/114] Implement that adminUpdateContribution is not allowed when moderator is null. --- backend/src/graphql/resolver/AdminResolver.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index e3c61c300..12cad529c 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -321,6 +321,10 @@ export class AdminResolver { throw new Error('user of the pending contribution and send user does not correspond') } + if (contributionToUpdate.moderatorId === null) { + throw new Error('An admin is not allowed to update a user contribution.') + } + const creationDateObj = new Date(creationDate) let creations = await getUserCreation(user.id) if (contributionToUpdate.contributionDate.getMonth() === creationDateObj.getMonth()) { From e1d50cacb521b3fabec9eaae67cdf29987531139 Mon Sep 17 00:00:00 2001 From: elweyn Date: Wed, 13 Jul 2022 09:55:21 +0200 Subject: [PATCH 059/114] Fix linting. --- backend/src/graphql/resolver/ContributionResolver.test.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index 75d6d1128..7afae08f6 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -2,7 +2,11 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' -import { adminUpdateContribution, createContribution, updateContribution } from '@/seeds/graphql/mutations' +import { + adminUpdateContribution, + createContribution, + updateContribution, +} from '@/seeds/graphql/mutations' import { listContributions, login } from '@/seeds/graphql/queries' import { cleanDB, resetToken, testEnvironment } from '@test/helpers' import { GraphQLError } from 'graphql' From 9d9d1a78f18abda66333139ac1b4ffd66e631607 Mon Sep 17 00:00:00 2001 From: elweyn Date: Wed, 13 Jul 2022 11:01:44 +0200 Subject: [PATCH 060/114] Add confirmedBy and confirmedAt for the contribution query. --- backend/src/graphql/model/Contribution.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/backend/src/graphql/model/Contribution.ts b/backend/src/graphql/model/Contribution.ts index dc1dd39e9..348a6eb98 100644 --- a/backend/src/graphql/model/Contribution.ts +++ b/backend/src/graphql/model/Contribution.ts @@ -12,6 +12,8 @@ export class Contribution { this.memo = contribution.memo this.createdAt = contribution.createdAt this.deletedAt = contribution.deletedAt + this.confirmedAt = contribution.confirmedAt + this.confirmedBy = contribution.confirmedBy } @Field(() => Number) @@ -31,6 +33,12 @@ export class Contribution { @Field(() => Date, { nullable: true }) deletedAt: Date | null + + @Field(() => Date, { nullable: true }) + confirmedAt: Date | null + + @Field(() => Number, { nullable: true }) + confirmedBy: number | null } @ObjectType() From 99c4e8367048fe1d100a307be5febd84b6036177 Mon Sep 17 00:00:00 2001 From: elweyn Date: Wed, 13 Jul 2022 11:26:18 +0200 Subject: [PATCH 061/114] Add deleted contribution to the list of contribution. --- backend/src/graphql/resolver/ContributionResolver.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 4424b40d0..562859116 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -58,6 +58,7 @@ export class ContributionResolver { order: { createdAt: order, }, + withDeleted: true, skip: (currentPage - 1) * pageSize, take: pageSize, }) From b7c24978392ae1f74baf3442ed32521d167c6637 Mon Sep 17 00:00:00 2001 From: elweyn Date: Wed, 13 Jul 2022 12:18:47 +0200 Subject: [PATCH 062/114] Add new right LIST_ALL_CONFIRMED_CONTRIBUTIONS. --- backend/src/auth/RIGHTS.ts | 1 + backend/src/auth/ROLES.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/backend/src/auth/RIGHTS.ts b/backend/src/auth/RIGHTS.ts index 6a6f8b7c0..975c2006a 100644 --- a/backend/src/auth/RIGHTS.ts +++ b/backend/src/auth/RIGHTS.ts @@ -27,6 +27,7 @@ export enum RIGHTS { GDT_BALANCE = 'GDT_BALANCE', CREATE_CONTRIBUTION = 'CREATE_CONTRIBUTION', LIST_CONTRIBUTIONS = 'LIST_CONTRIBUTIONS', + LIST_ALL_CONFIRMED_CONTRIBUTIONS = 'LIST_ALL_CONFIRMED_CONTRIBUTIONS', // Admin SEARCH_USERS = 'SEARCH_USERS', SET_USER_ROLE = 'SET_USER_ROLE', diff --git a/backend/src/auth/ROLES.ts b/backend/src/auth/ROLES.ts index f56106664..e5628bb62 100644 --- a/backend/src/auth/ROLES.ts +++ b/backend/src/auth/ROLES.ts @@ -25,6 +25,7 @@ export const ROLE_USER = new Role('user', [ RIGHTS.GDT_BALANCE, RIGHTS.CREATE_CONTRIBUTION, RIGHTS.LIST_CONTRIBUTIONS, + RIGHTS.LIST_ALL_CONFIRMED_CONTRIBUTIONS, ]) export const ROLE_ADMIN = new Role('admin', Object.values(RIGHTS)) // all rights From ed10d7d1a00b8cc8ae65d6efa1323921e800e649 Mon Sep 17 00:00:00 2001 From: mahula Date: Wed, 13 Jul 2022 14:54:17 +0200 Subject: [PATCH 063/114] set session timer to 0, if expiration is greater then 0 seconds --- frontend/src/components/SessionLogoutTimeout.vue | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/SessionLogoutTimeout.vue b/frontend/src/components/SessionLogoutTimeout.vue index 1e5a27998..113362abf 100644 --- a/frontend/src/components/SessionLogoutTimeout.vue +++ b/frontend/src/components/SessionLogoutTimeout.vue @@ -65,7 +65,7 @@ export default { this.$timer.restart('tokenExpires') this.$bvModal.show('modalSessionTimeOut') } - if (this.tokenExpiresInSeconds <= 0) { + if (this.tokenExpiresInSeconds === 0) { this.$timer.stop('tokenExpires') this.$emit('logout') } @@ -90,7 +90,11 @@ export default { }, computed: { tokenExpiresInSeconds() { - return Math.floor((new Date(this.$store.state.tokenTime * 1000).getTime() - this.now) / 1000) + const remainingSecs = Math.floor( + (new Date(this.$store.state.tokenTime * 1000).getTime() - this.now) / 1000, + ) + if (remainingSecs <= 0) return 0 + return remainingSecs }, }, beforeDestroy() { From b2164e6d1dc90fed257fcbb95601b5b5cc218e46 Mon Sep 17 00:00:00 2001 From: mahula Date: Wed, 13 Jul 2022 14:54:47 +0200 Subject: [PATCH 064/114] add unit test for this fix --- frontend/src/components/SessionLogoutTimeout.spec.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/SessionLogoutTimeout.spec.js b/frontend/src/components/SessionLogoutTimeout.spec.js index 0f5d21d36..94751f9cb 100644 --- a/frontend/src/components/SessionLogoutTimeout.spec.js +++ b/frontend/src/components/SessionLogoutTimeout.spec.js @@ -62,12 +62,16 @@ describe('SessionLogoutTimeout', () => { }) }) - describe('token is expired', () => { + describe('token is expired for several seconds', () => { beforeEach(() => { mocks.$store.state.tokenTime = setTokenTime(-60) wrapper = Wrapper() }) + it('value for remaining seconds is 0', () => { + expect(wrapper.tokenExpiresInSeconds === 0) + }) + it('emits logout', () => { expect(wrapper.emitted('logout')).toBeTruthy() }) From 1d1cc7e960aa845de7a659f6e5f4f25442c52e1b Mon Sep 17 00:00:00 2001 From: mahula Date: Wed, 13 Jul 2022 15:36:15 +0200 Subject: [PATCH 065/114] Update frontend/src/components/SessionLogoutTimeout.spec.js Co-authored-by: Moriz Wahl --- frontend/src/components/SessionLogoutTimeout.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/SessionLogoutTimeout.spec.js b/frontend/src/components/SessionLogoutTimeout.spec.js index 94751f9cb..bd6911d13 100644 --- a/frontend/src/components/SessionLogoutTimeout.spec.js +++ b/frontend/src/components/SessionLogoutTimeout.spec.js @@ -68,7 +68,7 @@ describe('SessionLogoutTimeout', () => { wrapper = Wrapper() }) - it('value for remaining seconds is 0', () => { + it('has value for remaining seconds equal 0', () => { expect(wrapper.tokenExpiresInSeconds === 0) }) From 2302da9054785b8b4a7ca330fd1ddbdd42826ce0 Mon Sep 17 00:00:00 2001 From: mahula Date: Wed, 13 Jul 2022 15:36:40 +0200 Subject: [PATCH 066/114] Update frontend/src/components/SessionLogoutTimeout.vue Co-authored-by: Moriz Wahl --- frontend/src/components/SessionLogoutTimeout.vue | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/frontend/src/components/SessionLogoutTimeout.vue b/frontend/src/components/SessionLogoutTimeout.vue index 113362abf..f10b8114a 100644 --- a/frontend/src/components/SessionLogoutTimeout.vue +++ b/frontend/src/components/SessionLogoutTimeout.vue @@ -93,8 +93,7 @@ export default { const remainingSecs = Math.floor( (new Date(this.$store.state.tokenTime * 1000).getTime() - this.now) / 1000, ) - if (remainingSecs <= 0) return 0 - return remainingSecs + return remainingSecs <= 0 ? 0 : remainingSecs }, }, beforeDestroy() { From 14619384a4f7171f8505fa9047480309814ccde5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Wed, 13 Jul 2022 18:52:11 +0200 Subject: [PATCH 067/114] remove comments --- backend/src/event/Event.ts | 13 ------------- backend/src/event/EventProtocolEmitter.ts | 20 +------------------- 2 files changed, 1 insertion(+), 32 deletions(-) diff --git a/backend/src/event/Event.ts b/backend/src/event/Event.ts index c51acf627..6f07661f1 100644 --- a/backend/src/event/Event.ts +++ b/backend/src/event/Event.ts @@ -2,19 +2,6 @@ import { EventProtocol } from '@entity/EventProtocol' import decimal from 'decimal.js-light' import { EventProtocolType } from './EventProtocolType' -/* -export interface EventInterface { - type: string - createdAt: Date - userId: number - xUserId?: number - xCommunityId?: number - transactionId?: number - contributionId?: number - amount?: Decimal -} -*/ - export class EventBasic { type: string createdAt: Date diff --git a/backend/src/event/EventProtocolEmitter.ts b/backend/src/event/EventProtocolEmitter.ts index 1040feb32..5991bbded 100644 --- a/backend/src/event/EventProtocolEmitter.ts +++ b/backend/src/event/EventProtocolEmitter.ts @@ -1,8 +1,6 @@ import { Event } from '@/event/Event' import { backendLogger as logger } from '@/server/logger' -// import { EventProtocolType } from './EventProtocolType' import { EventProtocol } from '@entity/EventProtocol' -// import { getConnection } from '@dbTools/typeorm' import CONFIG from '@/config' class EventProtocolEmitter { @@ -23,7 +21,7 @@ class EventProtocolEmitter { } public async writeEvent(event: Event): Promise { - // if (!eventProtocol.isEnabled()) return + if (!eventProtocol.isEnabled()) return logger.info(`writeEvent(${JSON.stringify(event)})`) const dbEvent = new EventProtocol() dbEvent.type = event.type @@ -38,19 +36,3 @@ class EventProtocolEmitter { } } export const eventProtocol = new EventProtocolEmitter() - -/* -eventProtocol.on('error', (err) => { - logger.error(`ERROR in EventProtocol: ${err}`) -}) - -eventProtocol.on('writeEvents', async (events: Event[]) => { - for (let i = 0; i < events.length; i++) { - await writeEvent(events[i]) - } -}) - -eventProtocol.on('writeEvent', async (event: Event) => { - await writeEvent(event) -}) -*/ From 90d90ca9bd9960457aa6a3267e73628d21675519 Mon Sep 17 00:00:00 2001 From: mahula Date: Wed, 13 Jul 2022 19:04:38 +0200 Subject: [PATCH 068/114] fix linting --- frontend/src/components/SessionLogoutTimeout.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/SessionLogoutTimeout.vue b/frontend/src/components/SessionLogoutTimeout.vue index f10b8114a..1ebff752a 100644 --- a/frontend/src/components/SessionLogoutTimeout.vue +++ b/frontend/src/components/SessionLogoutTimeout.vue @@ -93,7 +93,7 @@ export default { const remainingSecs = Math.floor( (new Date(this.$store.state.tokenTime * 1000).getTime() - this.now) / 1000, ) - return remainingSecs <= 0 ? 0 : remainingSecs + return remainingSecs <= 0 ? 0 : remainingSecs }, }, beforeDestroy() { From 7c698de325294811d144f6ac7bac058d44200735 Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 14 Jul 2022 12:25:45 +0200 Subject: [PATCH 069/114] Add constructor to ContributionListResult. --- backend/src/graphql/model/Contribution.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/backend/src/graphql/model/Contribution.ts b/backend/src/graphql/model/Contribution.ts index dc1dd39e9..989296848 100644 --- a/backend/src/graphql/model/Contribution.ts +++ b/backend/src/graphql/model/Contribution.ts @@ -35,6 +35,11 @@ export class Contribution { @ObjectType() export class ContributionListResult { + constructor(count: number, list: Contribution[]) { + this.linkCount = count + this.linkList = list + } + @Field(() => Int) linkCount: number From 2f90bd981126ef77f744beacb5fa8d27bc3cc225 Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 14 Jul 2022 12:58:01 +0200 Subject: [PATCH 070/114] Withdrew User from Contribution object and replaced it with userId, firstName and lastName. --- backend/src/graphql/model/Contribution.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/backend/src/graphql/model/Contribution.ts b/backend/src/graphql/model/Contribution.ts index 989296848..324b0ff07 100644 --- a/backend/src/graphql/model/Contribution.ts +++ b/backend/src/graphql/model/Contribution.ts @@ -7,7 +7,9 @@ import { User } from './User' export class Contribution { constructor(contribution: dbContribution, user: User) { this.id = contribution.id - this.user = user + this.userId = user ? user.id : null + this.firstName = user ? user.firstName : null + this.lastName = user ? user.lastName : null this.amount = contribution.amount this.memo = contribution.memo this.createdAt = contribution.createdAt @@ -17,8 +19,14 @@ export class Contribution { @Field(() => Number) id: number - @Field(() => User) - user: User + @Field(() => Number, { nullable: true }) + userId: number | null + + @Field(() => String, { nullable: true }) + firstName: string | null + + @Field(() => String, { nullable: true }) + lastName: string | null @Field(() => Decimal) amount: Decimal From c02f575780166a8f2e6c29df4a83ffac59fcd36d Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 14 Jul 2022 12:59:21 +0200 Subject: [PATCH 071/114] Withdrew userid from contribution object. --- backend/src/graphql/model/Contribution.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/backend/src/graphql/model/Contribution.ts b/backend/src/graphql/model/Contribution.ts index 324b0ff07..a1537244d 100644 --- a/backend/src/graphql/model/Contribution.ts +++ b/backend/src/graphql/model/Contribution.ts @@ -7,7 +7,6 @@ import { User } from './User' export class Contribution { constructor(contribution: dbContribution, user: User) { this.id = contribution.id - this.userId = user ? user.id : null this.firstName = user ? user.firstName : null this.lastName = user ? user.lastName : null this.amount = contribution.amount @@ -19,9 +18,6 @@ export class Contribution { @Field(() => Number) id: number - @Field(() => Number, { nullable: true }) - userId: number | null - @Field(() => String, { nullable: true }) firstName: string | null From 8c6ec08e88aa4350134c2efd812a77ddfbeea2d6 Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 14 Jul 2022 16:42:55 +0200 Subject: [PATCH 072/114] Gives a list of allCreations and calls the User one time in the creation. --- .../graphql/resolver/ContributionResolver.ts | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 4424b40d0..8a23b3150 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -2,12 +2,13 @@ import { RIGHTS } from '@/auth/RIGHTS' import { Context, getUser } from '@/server/context' import { backendLogger as logger } from '@/server/logger' import { Contribution as dbContribution } from '@entity/Contribution' +import { User as dbUser } from '@entity/User' import { Arg, Args, Authorized, Ctx, Mutation, Query, Resolver } from 'type-graphql' -import { FindOperator, IsNull } from '@dbTools/typeorm' +import { FindOperator, IsNull, Not } from '@dbTools/typeorm' import ContributionArgs from '@arg/ContributionArgs' import Paginated from '@arg/Paginated' import { Order } from '@enum/Order' -import { Contribution } from '@model/Contribution' +import { Contribution, ContributionListResult } from '@model/Contribution' import { UnconfirmedContribution } from '@model/UnconfirmedContribution' import { User } from '@model/User' import { validateContribution, getUserCreation } from './util/creations' @@ -63,4 +64,37 @@ export class ContributionResolver { }) return contributions.map((contribution) => new Contribution(contribution, new User(user))) } + + @Authorized([RIGHTS.LIST_ALL_CONFIRMED_CONTRIBUTIONS]) + @Query(() => ContributionListResult) + async listAllConfirmedContributions( + @Args() + { currentPage = 1, pageSize = 5, order = Order.DESC }: Paginated, + ): Promise { + const dbContributions = await dbContribution.find({ + order: { + createdAt: order, + }, + skip: (currentPage - 1) * pageSize, + take: pageSize, + }) + const contributions: Contribution[] = [] + const userIds: number[] = [] + dbContributions.forEach(async (dbContribution) => { + userIds.push(dbContribution.userId) + }) + userIds.filter((elem, index, self) => { + return index === self.indexOf(elem) + }) + const users = new Map() + for (let i = 0; i < userIds.length; i++) { + const id = userIds[i] + const user = await dbUser.findOneOrFail({ id }) + users.set(id, user) + } + dbContributions.forEach((dbContribution) => { + contributions.push(new Contribution(dbContribution, users.get(dbContribution.userId))) + }) + return new ContributionListResult(contributions.length, contributions) + } } From fdea5f68ef8fd78176ce3ea5707c6cc270d2abbd Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 14 Jul 2022 16:43:20 +0200 Subject: [PATCH 073/114] Add confirmedBy and confirmedAt for the contribution query. --- backend/src/graphql/model/Contribution.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/backend/src/graphql/model/Contribution.ts b/backend/src/graphql/model/Contribution.ts index a1537244d..34bffd6d7 100644 --- a/backend/src/graphql/model/Contribution.ts +++ b/backend/src/graphql/model/Contribution.ts @@ -13,6 +13,8 @@ export class Contribution { this.memo = contribution.memo this.createdAt = contribution.createdAt this.deletedAt = contribution.deletedAt + this.confirmedAt = contribution.confirmedAt + this.confirmedBy = contribution.confirmedBy } @Field(() => Number) @@ -35,6 +37,12 @@ export class Contribution { @Field(() => Date, { nullable: true }) deletedAt: Date | null + + @Field(() => Date, { nullable: true }) + confirmedAt: Date | null + + @Field(() => Number, { nullable: true }) + confirmedBy: number | null } @ObjectType() From cbbe0ffad2cf8a528d5a3c5c5a336cfed7afe82b Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 14 Jul 2022 16:45:19 +0200 Subject: [PATCH 074/114] Change the method name from listAllConfirmedContributions to listAllContributions. --- backend/src/auth/RIGHTS.ts | 2 +- backend/src/auth/ROLES.ts | 2 +- backend/src/graphql/resolver/ContributionResolver.ts | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/src/auth/RIGHTS.ts b/backend/src/auth/RIGHTS.ts index 975c2006a..5258c9e3b 100644 --- a/backend/src/auth/RIGHTS.ts +++ b/backend/src/auth/RIGHTS.ts @@ -27,7 +27,7 @@ export enum RIGHTS { GDT_BALANCE = 'GDT_BALANCE', CREATE_CONTRIBUTION = 'CREATE_CONTRIBUTION', LIST_CONTRIBUTIONS = 'LIST_CONTRIBUTIONS', - LIST_ALL_CONFIRMED_CONTRIBUTIONS = 'LIST_ALL_CONFIRMED_CONTRIBUTIONS', + LIST_ALL_CONTRIBUTIONS = 'LIST_ALL_CONTRIBUTIONS', // Admin SEARCH_USERS = 'SEARCH_USERS', SET_USER_ROLE = 'SET_USER_ROLE', diff --git a/backend/src/auth/ROLES.ts b/backend/src/auth/ROLES.ts index e5628bb62..4a96d4813 100644 --- a/backend/src/auth/ROLES.ts +++ b/backend/src/auth/ROLES.ts @@ -25,7 +25,7 @@ export const ROLE_USER = new Role('user', [ RIGHTS.GDT_BALANCE, RIGHTS.CREATE_CONTRIBUTION, RIGHTS.LIST_CONTRIBUTIONS, - RIGHTS.LIST_ALL_CONFIRMED_CONTRIBUTIONS, + RIGHTS.LIST_ALL_CONTRIBUTIONS, ]) export const ROLE_ADMIN = new Role('admin', Object.values(RIGHTS)) // all rights diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 8a23b3150..c015496c1 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -65,9 +65,9 @@ export class ContributionResolver { return contributions.map((contribution) => new Contribution(contribution, new User(user))) } - @Authorized([RIGHTS.LIST_ALL_CONFIRMED_CONTRIBUTIONS]) + @Authorized([RIGHTS.LIST_ALL_CONTRIBUTIONS]) @Query(() => ContributionListResult) - async listAllConfirmedContributions( + async listAllContributions( @Args() { currentPage = 1, pageSize = 5, order = Order.DESC }: Paginated, ): Promise { From ab77a798f589c4907ae149f127e9e7c7c56219bb Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 14 Jul 2022 16:57:25 +0200 Subject: [PATCH 075/114] Add query seed for listAllContributions. --- backend/src/seeds/graphql/queries.ts | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/backend/src/seeds/graphql/queries.ts b/backend/src/seeds/graphql/queries.ts index c27ecdd66..deae5f97b 100644 --- a/backend/src/seeds/graphql/queries.ts +++ b/backend/src/seeds/graphql/queries.ts @@ -191,6 +191,24 @@ export const listContributions = gql` } } ` + +export const listAllContributions = ` +query ($currentPage: Int = 1, $pageSize: Int = 5, $order: Order = DESC) { + listAllContributions(currentPage: $currentPage, pageSize: $pageSize, order: $order) { + linkCount + linkList { + id + firstName + lastName + amount + memo + createdAt + confirmedAt + confirmedBy + } + } +} +` // from admin interface export const listUnconfirmedContributions = gql` From ba90911aec704026ee6953e9db0f3731ef263116 Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 14 Jul 2022 16:57:57 +0200 Subject: [PATCH 076/114] Test that unauthenticated user can not query listAllContributions. --- .../resolver/ContributionResolver.test.ts | 56 ++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index 9b0f6a3bc..a4cb1d714 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -3,7 +3,7 @@ import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { createContribution } from '@/seeds/graphql/mutations' -import { listContributions, login } from '@/seeds/graphql/queries' +import { listAllContributions, listContributions, login } from '@/seeds/graphql/queries' import { cleanDB, resetToken, testEnvironment } from '@test/helpers' import { GraphQLError } from 'graphql' import { userFactory } from '@/seeds/factory/user' @@ -168,6 +168,11 @@ describe('ContributionResolver', () => { }) }) + afterAll(async () => { + await cleanDB() + await con.close() + }) + describe('filter confirmed is false', () => { it('returns creations', async () => { await expect( @@ -230,4 +235,53 @@ describe('ContributionResolver', () => { }) }) }) + + describe('listAllContribution', () => { + describe('unauthenticated', () => { + it('returns an error', async () => { + await expect( + query({ + query: listAllContributions, + variables: { + currentPage: 1, + pageSize: 25, + order: 'DESC', + filterConfirmed: false, + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('401 Unauthorized')], + }), + ) + }) + }) + + describe('authenticated', () => { + beforeAll(async () => { + await userFactory(testEnv, bibiBloxberg) + await userFactory(testEnv, peterLustig) + const bibisCreation = creations.find((creation) => creation.email === 'bibi@bloxberg.de') + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + await creationFactory(testEnv, bibisCreation!) + await query({ + query: login, + variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, + }) + await mutate({ + mutation: createContribution, + variables: { + amount: 100.0, + memo: 'Test env contribution', + creationDate: new Date().toString(), + }, + }) + }) + + afterAll(async () => { + await cleanDB() + await con.close() + }) + }) + }) }) From 246edadc1314e6092eb51daa7ffdf9eeff72e72f Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 14 Jul 2022 17:22:22 +0200 Subject: [PATCH 077/114] Test that authenticated user gets allContributions. --- .../resolver/ContributionResolver.test.ts | 35 +++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index a4cb1d714..9aa247d4e 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -261,9 +261,9 @@ describe('ContributionResolver', () => { beforeAll(async () => { await userFactory(testEnv, bibiBloxberg) await userFactory(testEnv, peterLustig) - const bibisCreation = creations.find((creation) => creation.email === 'bibi@bloxberg.de') + creations.forEach(async (creation) => await creationFactory(testEnv, creation!)) // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - await creationFactory(testEnv, bibisCreation!) + // await creationFactory(testEnv, creations!) await query({ query: login, variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, @@ -282,6 +282,37 @@ describe('ContributionResolver', () => { await cleanDB() await con.close() }) + + it('returns allCreation', async () => { + await expect( + query({ + query: listAllContributions, + variables: { + currentPage: 1, + pageSize: 25, + order: 'DESC', + filterConfirmed: false, + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + data: { + listAllContributions: expect.arrayContaining([ + expect.objectContaining({ + id: expect.any(Number), + memo: 'Herzlich Willkommen bei Gradido!', + amount: '1000', + }), + expect.objectContaining({ + id: expect.any(Number), + memo: 'Test env contribution', + amount: '100', + }), + ]), + }, + }), + ) + }) }) }) }) From 3733bf511483f09fae6d37c2e5926c75ae247487 Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 14 Jul 2022 17:30:21 +0200 Subject: [PATCH 078/114] Change con.close to resetToken method. --- backend/src/graphql/resolver/ContributionResolver.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index 9aa247d4e..124adff18 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -170,7 +170,7 @@ describe('ContributionResolver', () => { afterAll(async () => { await cleanDB() - await con.close() + resetToken() }) describe('filter confirmed is false', () => { @@ -280,7 +280,7 @@ describe('ContributionResolver', () => { afterAll(async () => { await cleanDB() - await con.close() + resetToken() }) it('returns allCreation', async () => { From 34de4bb9014497a0db5a2d0d5cdcf662ff954ee2 Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 14 Jul 2022 17:42:49 +0200 Subject: [PATCH 079/114] Merge conflict on contribution resolver test file --- .../resolver/ContributionResolver.test.ts | 142 ++++++++++-------- 1 file changed, 78 insertions(+), 64 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index fd9636439..4f57cc0a1 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -2,17 +2,12 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' -<<<<<<< HEAD -import { createContribution } from '@/seeds/graphql/mutations' -import { listAllContributions, listContributions, login } from '@/seeds/graphql/queries' -======= import { adminUpdateContribution, createContribution, updateContribution, } from '@/seeds/graphql/mutations' -import { listContributions, login } from '@/seeds/graphql/queries' ->>>>>>> master +import { listAllContributions, listContributions, login } from '@/seeds/graphql/queries' import { cleanDB, resetToken, testEnvironment } from '@test/helpers' import { GraphQLError } from 'graphql' import { userFactory } from '@/seeds/factory/user' @@ -246,19 +241,6 @@ describe('ContributionResolver', () => { }) }) -<<<<<<< HEAD - describe('listAllContribution', () => { - describe('unauthenticated', () => { - it('returns an error', async () => { - await expect( - query({ - query: listAllContributions, - variables: { - currentPage: 1, - pageSize: 25, - order: 'DESC', - filterConfirmed: false, -======= describe('updateContribution', () => { describe('unauthenticated', () => { it('returns an error', async () => { @@ -270,7 +252,6 @@ describe('ContributionResolver', () => { amount: 100.0, memo: 'Test Contribution', creationDate: 'not-valid', ->>>>>>> master }, }), ).resolves.toEqual( @@ -283,25 +264,13 @@ describe('ContributionResolver', () => { describe('authenticated', () => { beforeAll(async () => { -<<<<<<< HEAD - await userFactory(testEnv, bibiBloxberg) - await userFactory(testEnv, peterLustig) - creations.forEach(async (creation) => await creationFactory(testEnv, creation!)) - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - // await creationFactory(testEnv, creations!) -======= await userFactory(testEnv, peterLustig) await userFactory(testEnv, bibiBloxberg) ->>>>>>> master await query({ query: login, variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, }) -<<<<<<< HEAD - await mutate({ -======= result = await mutate({ ->>>>>>> master mutation: createContribution, variables: { amount: 100.0, @@ -316,37 +285,6 @@ describe('ContributionResolver', () => { resetToken() }) -<<<<<<< HEAD - it('returns allCreation', async () => { - await expect( - query({ - query: listAllContributions, - variables: { - currentPage: 1, - pageSize: 25, - order: 'DESC', - filterConfirmed: false, - }, - }), - ).resolves.toEqual( - expect.objectContaining({ - data: { - listAllContributions: expect.arrayContaining([ - expect.objectContaining({ - id: expect.any(Number), - memo: 'Herzlich Willkommen bei Gradido!', - amount: '1000', - }), - expect.objectContaining({ - id: expect.any(Number), - memo: 'Test env contribution', - amount: '100', - }), - ]), - }, - }), - ) -======= describe('wrong contribution id', () => { it('throws an error', async () => { await expect( @@ -497,8 +435,84 @@ describe('ContributionResolver', () => { }), ) }) ->>>>>>> master + }) + + describe('listAllContribution', () => { + describe('unauthenticated', () => { + it('returns an error', async () => { + await expect( + query({ + query: listAllContributions, + variables: { + currentPage: 1, + pageSize: 25, + order: 'DESC', + filterConfirmed: false, + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('401 Unauthorized')], + }), + ) + }) + }) }) }) }) + + describe('authenticated', () => { + beforeAll(async () => { + await userFactory(testEnv, bibiBloxberg) + await userFactory(testEnv, peterLustig) + creations.forEach(async (creation) => await creationFactory(testEnv, creation!)) + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + // await creationFactory(testEnv, creations!) + await userFactory(testEnv, peterLustig) + await userFactory(testEnv, bibiBloxberg) + await query({ + query: login, + variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, + }) + result = await mutate({ + mutation: createContribution, + variables: { + amount: 100.0, + memo: 'Test env contribution', + creationDate: new Date().toString(), + }, + }) + }) + + it('returns allCreation', async () => { + await expect( + query({ + query: listAllContributions, + variables: { + currentPage: 1, + pageSize: 25, + order: 'DESC', + filterConfirmed: false, + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + data: { + listAllContributions: expect.arrayContaining([ + expect.objectContaining({ + id: expect.any(Number), + memo: 'Herzlich Willkommen bei Gradido!', + amount: '1000', + }), + expect.objectContaining({ + id: expect.any(Number), + memo: 'Test env contribution', + amount: '100', + }), + ]), + }, + }), + ) + }) + }) }) From c242f977337a5e048dcd1cfecf818f3d92d0456d Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 14 Jul 2022 17:52:31 +0200 Subject: [PATCH 080/114] Change the test for listAllContributions to have every seed user and create all creations, add Test suite that checks if every seeded data arrives as well. --- .../resolver/ContributionResolver.test.ts | 141 +++++++++--------- 1 file changed, 72 insertions(+), 69 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index 4f57cc0a1..b294fb40d 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -14,6 +14,8 @@ import { userFactory } from '@/seeds/factory/user' import { creationFactory } from '@/seeds/factory/creation' import { creations } from '@/seeds/creation/index' import { peterLustig } from '@/seeds/users/peter-lustig' +import { bobBaumeister } from '@/seeds/users/bob-baumeister' +import { raeuberHotzenplotz } from '@/seeds/users/raeuber-hotzenplotz' let mutate: any, query: any, con: any let testEnv: any @@ -436,83 +438,84 @@ describe('ContributionResolver', () => { ) }) }) - - describe('listAllContribution', () => { - describe('unauthenticated', () => { - it('returns an error', async () => { - await expect( - query({ - query: listAllContributions, - variables: { - currentPage: 1, - pageSize: 25, - order: 'DESC', - filterConfirmed: false, - }, - }), - ).resolves.toEqual( - expect.objectContaining({ - errors: [new GraphQLError('401 Unauthorized')], - }), - ) - }) - }) - }) }) }) - describe('authenticated', () => { - beforeAll(async () => { - await userFactory(testEnv, bibiBloxberg) - await userFactory(testEnv, peterLustig) - creations.forEach(async (creation) => await creationFactory(testEnv, creation!)) - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - // await creationFactory(testEnv, creations!) - await userFactory(testEnv, peterLustig) - await userFactory(testEnv, bibiBloxberg) - await query({ - query: login, - variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, - }) - result = await mutate({ - mutation: createContribution, - variables: { - amount: 100.0, - memo: 'Test env contribution', - creationDate: new Date().toString(), - }, + describe('listAllContribution', () => { + describe('unauthenticated', () => { + it('returns an error', async () => { + await expect( + query({ + query: listAllContributions, + variables: { + currentPage: 1, + pageSize: 25, + order: 'DESC', + filterConfirmed: false, + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('401 Unauthorized')], + }), + ) }) }) - it('returns allCreation', async () => { - await expect( - query({ - query: listAllContributions, + describe('authenticated', () => { + beforeAll(async () => { + await userFactory(testEnv, bibiBloxberg) + await userFactory(testEnv, peterLustig) + await userFactory(testEnv, raeuberHotzenplotz) + await userFactory(testEnv, bobBaumeister) + creations.forEach(async (creation) => await creationFactory(testEnv, creation!)) + await query({ + query: login, + variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, + }) + result = await mutate({ + mutation: createContribution, variables: { - currentPage: 1, - pageSize: 25, - order: 'DESC', - filterConfirmed: false, + amount: 100.0, + memo: 'Test env contribution', + creationDate: new Date().toString(), }, - }), - ).resolves.toEqual( - expect.objectContaining({ - data: { - listAllContributions: expect.arrayContaining([ - expect.objectContaining({ - id: expect.any(Number), - memo: 'Herzlich Willkommen bei Gradido!', - amount: '1000', - }), - expect.objectContaining({ - id: expect.any(Number), - memo: 'Test env contribution', - amount: '100', - }), - ]), - }, - }), - ) + }) + }) + + it('returns allCreation', async () => { + await expect( + query({ + query: listAllContributions, + variables: { + currentPage: 1, + pageSize: 25, + order: 'DESC', + filterConfirmed: false, + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + data: { + listAllContributions: { + linkCount: 25, + linkList: expect.arrayContaining([ + expect.objectContaining({ + id: expect.any(Number), + memo: 'Herzlich Willkommen bei Gradido!', + amount: '1000', + }), + expect.objectContaining({ + id: expect.any(Number), + memo: 'Test env contribution', + amount: '100', + }), + ]), + }, + }, + }), + ) + }) }) }) }) From b86ddbf8b0be90856de0a3a3e2b990745e9a5804 Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 14 Jul 2022 18:08:51 +0200 Subject: [PATCH 081/114] Fix linting. --- backend/src/graphql/resolver/ContributionResolver.test.ts | 1 + backend/src/graphql/resolver/ContributionResolver.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index b294fb40d..247d1be0e 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -468,6 +468,7 @@ describe('ContributionResolver', () => { await userFactory(testEnv, peterLustig) await userFactory(testEnv, raeuberHotzenplotz) await userFactory(testEnv, bobBaumeister) + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion creations.forEach(async (creation) => await creationFactory(testEnv, creation!)) await query({ query: login, diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 3faffb95d..cdaa5faa3 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -4,7 +4,7 @@ import { backendLogger as logger } from '@/server/logger' import { Contribution as dbContribution } from '@entity/Contribution' import { User as dbUser } from '@entity/User' import { Arg, Args, Authorized, Ctx, Int, Mutation, Query, Resolver } from 'type-graphql' -import { FindOperator, IsNull, Not } from '@dbTools/typeorm' +import { FindOperator, IsNull } from '@dbTools/typeorm' import ContributionArgs from '@arg/ContributionArgs' import Paginated from '@arg/Paginated' import { Order } from '@enum/Order' From 9af614d437b845e8c5e3eafb48de78a2b21da61b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Fri, 15 Jul 2022 00:37:07 +0200 Subject: [PATCH 082/114] invert default setting of EVENT_PROTOCOL_ENABLED --- backend/.env.dist | 120 +++++----- backend/.env.template | 110 ++++----- backend/src/config/index.ts | 258 +++++++++++----------- backend/src/event/EventProtocolEmitter.ts | 77 +++---- deployment/bare_metal/.env.dist | 158 ++++++------- 5 files changed, 362 insertions(+), 361 deletions(-) diff --git a/backend/.env.dist b/backend/.env.dist index 0e8148a8a..fc8544b96 100644 --- a/backend/.env.dist +++ b/backend/.env.dist @@ -1,60 +1,60 @@ -CONFIG_VERSION=v9.2022-07-07 - -# Server -PORT=4000 -JWT_SECRET=secret123 -JWT_EXPIRES_IN=10m -GRAPHIQL=false -GDT_API_URL=https://gdt.gradido.net - -# Database -DB_HOST=localhost -DB_PORT=3306 -DB_USER=root -DB_PASSWORD= -DB_DATABASE=gradido_community -TYPEORM_LOGGING_RELATIVE_PATH=typeorm.backend.log - -# Klicktipp -KLICKTIPP=false -KLICKTTIPP_API_URL=https://api.klicktipp.com -KLICKTIPP_USER=gradido_test -KLICKTIPP_PASSWORD=secret321 -KLICKTIPP_APIKEY_DE=SomeFakeKeyDE -KLICKTIPP_APIKEY_EN=SomeFakeKeyEN - -# Community -COMMUNITY_NAME=Gradido Entwicklung -COMMUNITY_URL=http://localhost/ -COMMUNITY_REGISTER_URL=http://localhost/register -COMMUNITY_REDEEM_URL=http://localhost/redeem/{code} -COMMUNITY_REDEEM_CONTRIBUTION_URL=http://localhost/redeem/CL-{code} -COMMUNITY_DESCRIPTION=Die lokale Entwicklungsumgebung von Gradido. - -# Login Server -LOGIN_APP_SECRET=21ffbbc616fe -LOGIN_SERVER_KEY=a51ef8ac7ef1abf162fb7a65261acd7a - -# EMail -EMAIL=false -EMAIL_USERNAME=gradido_email -EMAIL_SENDER=info@gradido.net -EMAIL_PASSWORD=xxx -EMAIL_SMTP_URL=gmail.com -EMAIL_SMTP_PORT=587 -EMAIL_LINK_VERIFICATION=http://localhost/checkEmail/{optin}{code} -EMAIL_LINK_SETPASSWORD=http://localhost/reset-password/{optin} -EMAIL_LINK_FORGOTPASSWORD=http://localhost/forgot-password -EMAIL_LINK_OVERVIEW=http://localhost/overview -EMAIL_CODE_VALID_TIME=1440 -EMAIL_CODE_REQUEST_TIME=10 - -# Webhook -WEBHOOK_ELOPAGE_SECRET=secret - -# EventProtocol -EVENT_PROTOCOL_ENABLED=true - -# SET LOG LEVEL AS NEEDED IN YOUR .ENV -# POSSIBLE VALUES: all | trace | debug | info | warn | error | fatal -# LOG_LEVEL=info +CONFIG_VERSION=v9.2022-07-07 + +# Server +PORT=4000 +JWT_SECRET=secret123 +JWT_EXPIRES_IN=10m +GRAPHIQL=false +GDT_API_URL=https://gdt.gradido.net + +# Database +DB_HOST=localhost +DB_PORT=3306 +DB_USER=root +DB_PASSWORD= +DB_DATABASE=gradido_community +TYPEORM_LOGGING_RELATIVE_PATH=typeorm.backend.log + +# Klicktipp +KLICKTIPP=false +KLICKTTIPP_API_URL=https://api.klicktipp.com +KLICKTIPP_USER=gradido_test +KLICKTIPP_PASSWORD=secret321 +KLICKTIPP_APIKEY_DE=SomeFakeKeyDE +KLICKTIPP_APIKEY_EN=SomeFakeKeyEN + +# Community +COMMUNITY_NAME=Gradido Entwicklung +COMMUNITY_URL=http://localhost/ +COMMUNITY_REGISTER_URL=http://localhost/register +COMMUNITY_REDEEM_URL=http://localhost/redeem/{code} +COMMUNITY_REDEEM_CONTRIBUTION_URL=http://localhost/redeem/CL-{code} +COMMUNITY_DESCRIPTION=Die lokale Entwicklungsumgebung von Gradido. + +# Login Server +LOGIN_APP_SECRET=21ffbbc616fe +LOGIN_SERVER_KEY=a51ef8ac7ef1abf162fb7a65261acd7a + +# EMail +EMAIL=false +EMAIL_USERNAME=gradido_email +EMAIL_SENDER=info@gradido.net +EMAIL_PASSWORD=xxx +EMAIL_SMTP_URL=gmail.com +EMAIL_SMTP_PORT=587 +EMAIL_LINK_VERIFICATION=http://localhost/checkEmail/{optin}{code} +EMAIL_LINK_SETPASSWORD=http://localhost/reset-password/{optin} +EMAIL_LINK_FORGOTPASSWORD=http://localhost/forgot-password +EMAIL_LINK_OVERVIEW=http://localhost/overview +EMAIL_CODE_VALID_TIME=1440 +EMAIL_CODE_REQUEST_TIME=10 + +# Webhook +WEBHOOK_ELOPAGE_SECRET=secret + +# EventProtocol +EVENT_PROTOCOL_ENABLED=true + +# SET LOG LEVEL AS NEEDED IN YOUR .ENV +# POSSIBLE VALUES: all | trace | debug | info | warn | error | fatal +# LOG_LEVEL=info diff --git a/backend/.env.template b/backend/.env.template index 764203d7f..c6c0819e3 100644 --- a/backend/.env.template +++ b/backend/.env.template @@ -1,55 +1,55 @@ -CONFIG_VERSION=$BACKEND_CONFIG_VERSION - -# Server -JWT_SECRET=$JWT_SECRET -JWT_EXPIRES_IN=$JWT_EXPIRES_IN -GRAPHIQL=false -GDT_API_URL=$GDT_API_URL - -# Database -DB_HOST=localhost -DB_PORT=3306 -DB_USER=$DB_USER -DB_PASSWORD=$DB_PASSWORD -DB_DATABASE=gradido_community -TYPEORM_LOGGING_RELATIVE_PATH=$TYPEORM_LOGGING_RELATIVE_PATH - -# Klicktipp -KLICKTIPP=$KLICKTIPP -KLICKTTIPP_API_URL=https://api.klicktipp.com -KLICKTIPP_USER=$KLICKTIPP_USER -KLICKTIPP_PASSWORD=$KLICKTIPP_PASSWORD -KLICKTIPP_APIKEY_DE=$KLICKTIPP_APIKEY_DE -KLICKTIPP_APIKEY_EN=$KLICKTIPP_APIKEY_EN - -# Community -COMMUNITY_NAME=$COMMUNITY_NAME -COMMUNITY_URL=$COMMUNITY_URL -COMMUNITY_REGISTER_URL=$COMMUNITY_REGISTER_URL -COMMUNITY_REDEEM_URL=$COMMUNITY_REDEEM_URL -COMMUNITY_REDEEM_CONTRIBUTION_URL=$COMMUNITY_REDEEM_CONTRIBUTION_URL -COMMUNITY_DESCRIPTION=$COMMUNITY_DESCRIPTION - -# Login Server -LOGIN_APP_SECRET=21ffbbc616fe -LOGIN_SERVER_KEY=a51ef8ac7ef1abf162fb7a65261acd7a - -# EMail -EMAIL=$EMAIL -EMAIL_USERNAME=$EMAIL_USERNAME -EMAIL_SENDER=$EMAIL_SENDER -EMAIL_PASSWORD=$EMAIL_PASSWORD -EMAIL_SMTP_URL=$EMAIL_SMTP_URL -EMAIL_SMTP_PORT=587 -EMAIL_LINK_VERIFICATION=$EMAIL_LINK_VERIFICATION -EMAIL_LINK_SETPASSWORD=$EMAIL_LINK_SETPASSWORD -EMAIL_LINK_FORGOTPASSWORD=$EMAIL_LINK_FORGOTPASSWORD -EMAIL_LINK_OVERVIEW=$EMAIL_LINK_OVERVIEW -EMAIL_CODE_VALID_TIME=$EMAIL_CODE_VALID_TIME -EMAIL_CODE_REQUEST_TIME=$EMAIL_CODE_REQUEST_TIME - -# Webhook -WEBHOOK_ELOPAGE_SECRET=$WEBHOOK_ELOPAGE_SECRET - -# EventProtocol -EVENT_PROTOCOL_ENABLED=true +CONFIG_VERSION=$BACKEND_CONFIG_VERSION + +# Server +JWT_SECRET=$JWT_SECRET +JWT_EXPIRES_IN=$JWT_EXPIRES_IN +GRAPHIQL=false +GDT_API_URL=$GDT_API_URL + +# Database +DB_HOST=localhost +DB_PORT=3306 +DB_USER=$DB_USER +DB_PASSWORD=$DB_PASSWORD +DB_DATABASE=gradido_community +TYPEORM_LOGGING_RELATIVE_PATH=$TYPEORM_LOGGING_RELATIVE_PATH + +# Klicktipp +KLICKTIPP=$KLICKTIPP +KLICKTTIPP_API_URL=https://api.klicktipp.com +KLICKTIPP_USER=$KLICKTIPP_USER +KLICKTIPP_PASSWORD=$KLICKTIPP_PASSWORD +KLICKTIPP_APIKEY_DE=$KLICKTIPP_APIKEY_DE +KLICKTIPP_APIKEY_EN=$KLICKTIPP_APIKEY_EN + +# Community +COMMUNITY_NAME=$COMMUNITY_NAME +COMMUNITY_URL=$COMMUNITY_URL +COMMUNITY_REGISTER_URL=$COMMUNITY_REGISTER_URL +COMMUNITY_REDEEM_URL=$COMMUNITY_REDEEM_URL +COMMUNITY_REDEEM_CONTRIBUTION_URL=$COMMUNITY_REDEEM_CONTRIBUTION_URL +COMMUNITY_DESCRIPTION=$COMMUNITY_DESCRIPTION + +# Login Server +LOGIN_APP_SECRET=21ffbbc616fe +LOGIN_SERVER_KEY=a51ef8ac7ef1abf162fb7a65261acd7a + +# EMail +EMAIL=$EMAIL +EMAIL_USERNAME=$EMAIL_USERNAME +EMAIL_SENDER=$EMAIL_SENDER +EMAIL_PASSWORD=$EMAIL_PASSWORD +EMAIL_SMTP_URL=$EMAIL_SMTP_URL +EMAIL_SMTP_PORT=587 +EMAIL_LINK_VERIFICATION=$EMAIL_LINK_VERIFICATION +EMAIL_LINK_SETPASSWORD=$EMAIL_LINK_SETPASSWORD +EMAIL_LINK_FORGOTPASSWORD=$EMAIL_LINK_FORGOTPASSWORD +EMAIL_LINK_OVERVIEW=$EMAIL_LINK_OVERVIEW +EMAIL_CODE_VALID_TIME=$EMAIL_CODE_VALID_TIME +EMAIL_CODE_REQUEST_TIME=$EMAIL_CODE_REQUEST_TIME + +# Webhook +WEBHOOK_ELOPAGE_SECRET=$WEBHOOK_ELOPAGE_SECRET + +# EventProtocol +EVENT_PROTOCOL_ENABLED=true diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index cb56f7971..240b4d61e 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -1,129 +1,129 @@ -// ATTENTION: DO NOT PUT ANY SECRETS IN HERE (or the .env) - -import dotenv from 'dotenv' -import Decimal from 'decimal.js-light' -dotenv.config() - -Decimal.set({ - precision: 25, - rounding: Decimal.ROUND_HALF_UP, -}) - -const constants = { - DB_VERSION: '0043-add_event_protocol_table', - DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0 - LOG4JS_CONFIG: 'log4js-config.json', - // default log level on production should be info - LOG_LEVEL: process.env.LOG_LEVEL || 'info', - CONFIG_VERSION: { - DEFAULT: 'DEFAULT', - EXPECTED: 'v9.2022-07-07', - CURRENT: '', - }, -} - -const server = { - PORT: process.env.PORT || 4000, - JWT_SECRET: process.env.JWT_SECRET || 'secret123', - JWT_EXPIRES_IN: process.env.JWT_EXPIRES_IN || '10m', - GRAPHIQL: process.env.GRAPHIQL === 'true' || false, - GDT_API_URL: process.env.GDT_API_URL || 'https://gdt.gradido.net', - PRODUCTION: process.env.NODE_ENV === 'production' || false, -} - -const database = { - DB_HOST: process.env.DB_HOST || 'localhost', - DB_PORT: process.env.DB_PORT ? parseInt(process.env.DB_PORT) : 3306, - DB_USER: process.env.DB_USER || 'root', - DB_PASSWORD: process.env.DB_PASSWORD || '', - DB_DATABASE: process.env.DB_DATABASE || 'gradido_community', - TYPEORM_LOGGING_RELATIVE_PATH: process.env.TYPEORM_LOGGING_RELATIVE_PATH || 'typeorm.backend.log', -} - -const klicktipp = { - KLICKTIPP: process.env.KLICKTIPP === 'true' || false, - KLICKTTIPP_API_URL: process.env.KLICKTIPP_API_URL || 'https://api.klicktipp.com', - KLICKTIPP_USER: process.env.KLICKTIPP_USER || 'gradido_test', - KLICKTIPP_PASSWORD: process.env.KLICKTIPP_PASSWORD || 'secret321', - KLICKTIPP_APIKEY_DE: process.env.KLICKTIPP_APIKEY_DE || 'SomeFakeKeyDE', - KLICKTIPP_APIKEY_EN: process.env.KLICKTIPP_APIKEY_EN || 'SomeFakeKeyEN', -} - -const community = { - COMMUNITY_NAME: process.env.COMMUNITY_NAME || 'Gradido Entwicklung', - COMMUNITY_URL: process.env.COMMUNITY_URL || 'http://localhost/', - COMMUNITY_REGISTER_URL: process.env.COMMUNITY_REGISTER_URL || 'http://localhost/register', - COMMUNITY_REDEEM_URL: process.env.COMMUNITY_REDEEM_URL || 'http://localhost/redeem/{code}', - COMMUNITY_REDEEM_CONTRIBUTION_URL: - process.env.COMMUNITY_REDEEM_CONTRIBUTION_URL || 'http://localhost/redeem/CL-{code}', - COMMUNITY_DESCRIPTION: - process.env.COMMUNITY_DESCRIPTION || 'Die lokale Entwicklungsumgebung von Gradido.', -} - -const loginServer = { - LOGIN_APP_SECRET: process.env.LOGIN_APP_SECRET || '21ffbbc616fe', - LOGIN_SERVER_KEY: process.env.LOGIN_SERVER_KEY || 'a51ef8ac7ef1abf162fb7a65261acd7a', -} - -const email = { - EMAIL: process.env.EMAIL === 'true' || false, - EMAIL_USERNAME: process.env.EMAIL_USERNAME || 'gradido_email', - EMAIL_SENDER: process.env.EMAIL_SENDER || 'info@gradido.net', - EMAIL_PASSWORD: process.env.EMAIL_PASSWORD || 'xxx', - EMAIL_SMTP_URL: process.env.EMAIL_SMTP_URL || 'gmail.com', - EMAIL_SMTP_PORT: process.env.EMAIL_SMTP_PORT || '587', - EMAIL_LINK_VERIFICATION: - process.env.EMAIL_LINK_VERIFICATION || 'http://localhost/checkEmail/{optin}{code}', - EMAIL_LINK_SETPASSWORD: - process.env.EMAIL_LINK_SETPASSWORD || 'http://localhost/reset-password/{optin}', - EMAIL_LINK_FORGOTPASSWORD: - process.env.EMAIL_LINK_FORGOTPASSWORD || 'http://localhost/forgot-password', - EMAIL_LINK_OVERVIEW: process.env.EMAIL_LINK_OVERVIEW || 'http://localhost/overview', - // time in minutes a optin code is valid - EMAIL_CODE_VALID_TIME: process.env.EMAIL_CODE_VALID_TIME - ? parseInt(process.env.EMAIL_CODE_VALID_TIME) || 1440 - : 1440, - // time in minutes that must pass to request a new optin code - EMAIL_CODE_REQUEST_TIME: process.env.EMAIL_CODE_REQUEST_TIME - ? parseInt(process.env.EMAIL_CODE_REQUEST_TIME) || 10 - : 10, -} - -const webhook = { - // Elopage - WEBHOOK_ELOPAGE_SECRET: process.env.WEBHOOK_ELOPAGE_SECRET || 'secret', -} - -const eventProtocol = { - // global switch to enable writing of EventProtocol-Entries - EVENT_PROTOCOL_ENABLED: process.env.EVENT_PROTOCOL_ENABLED === 'true' || false, -} - -// This is needed by graphql-directive-auth -process.env.APP_SECRET = server.JWT_SECRET - -// Check config version -constants.CONFIG_VERSION.CURRENT = process.env.CONFIG_VERSION || constants.CONFIG_VERSION.DEFAULT -if ( - ![constants.CONFIG_VERSION.EXPECTED, constants.CONFIG_VERSION.DEFAULT].includes( - constants.CONFIG_VERSION.CURRENT, - ) -) { - throw new Error( - `Fatal: Config Version incorrect - expected "${constants.CONFIG_VERSION.EXPECTED}" or "${constants.CONFIG_VERSION.DEFAULT}", but found "${constants.CONFIG_VERSION.CURRENT}"`, - ) -} - -const CONFIG = { - ...constants, - ...server, - ...database, - ...klicktipp, - ...community, - ...email, - ...loginServer, - ...webhook, - ...eventProtocol, -} - -export default CONFIG +// ATTENTION: DO NOT PUT ANY SECRETS IN HERE (or the .env) + +import dotenv from 'dotenv' +import Decimal from 'decimal.js-light' +dotenv.config() + +Decimal.set({ + precision: 25, + rounding: Decimal.ROUND_HALF_UP, +}) + +const constants = { + DB_VERSION: '0043-add_event_protocol_table', + DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0 + LOG4JS_CONFIG: 'log4js-config.json', + // default log level on production should be info + LOG_LEVEL: process.env.LOG_LEVEL || 'info', + CONFIG_VERSION: { + DEFAULT: 'DEFAULT', + EXPECTED: 'v9.2022-07-07', + CURRENT: '', + }, +} + +const server = { + PORT: process.env.PORT || 4000, + JWT_SECRET: process.env.JWT_SECRET || 'secret123', + JWT_EXPIRES_IN: process.env.JWT_EXPIRES_IN || '10m', + GRAPHIQL: process.env.GRAPHIQL === 'true' || false, + GDT_API_URL: process.env.GDT_API_URL || 'https://gdt.gradido.net', + PRODUCTION: process.env.NODE_ENV === 'production' || false, +} + +const database = { + DB_HOST: process.env.DB_HOST || 'localhost', + DB_PORT: process.env.DB_PORT ? parseInt(process.env.DB_PORT) : 3306, + DB_USER: process.env.DB_USER || 'root', + DB_PASSWORD: process.env.DB_PASSWORD || '', + DB_DATABASE: process.env.DB_DATABASE || 'gradido_community', + TYPEORM_LOGGING_RELATIVE_PATH: process.env.TYPEORM_LOGGING_RELATIVE_PATH || 'typeorm.backend.log', +} + +const klicktipp = { + KLICKTIPP: process.env.KLICKTIPP === 'true' || false, + KLICKTTIPP_API_URL: process.env.KLICKTIPP_API_URL || 'https://api.klicktipp.com', + KLICKTIPP_USER: process.env.KLICKTIPP_USER || 'gradido_test', + KLICKTIPP_PASSWORD: process.env.KLICKTIPP_PASSWORD || 'secret321', + KLICKTIPP_APIKEY_DE: process.env.KLICKTIPP_APIKEY_DE || 'SomeFakeKeyDE', + KLICKTIPP_APIKEY_EN: process.env.KLICKTIPP_APIKEY_EN || 'SomeFakeKeyEN', +} + +const community = { + COMMUNITY_NAME: process.env.COMMUNITY_NAME || 'Gradido Entwicklung', + COMMUNITY_URL: process.env.COMMUNITY_URL || 'http://localhost/', + COMMUNITY_REGISTER_URL: process.env.COMMUNITY_REGISTER_URL || 'http://localhost/register', + COMMUNITY_REDEEM_URL: process.env.COMMUNITY_REDEEM_URL || 'http://localhost/redeem/{code}', + COMMUNITY_REDEEM_CONTRIBUTION_URL: + process.env.COMMUNITY_REDEEM_CONTRIBUTION_URL || 'http://localhost/redeem/CL-{code}', + COMMUNITY_DESCRIPTION: + process.env.COMMUNITY_DESCRIPTION || 'Die lokale Entwicklungsumgebung von Gradido.', +} + +const loginServer = { + LOGIN_APP_SECRET: process.env.LOGIN_APP_SECRET || '21ffbbc616fe', + LOGIN_SERVER_KEY: process.env.LOGIN_SERVER_KEY || 'a51ef8ac7ef1abf162fb7a65261acd7a', +} + +const email = { + EMAIL: process.env.EMAIL === 'true' || false, + EMAIL_USERNAME: process.env.EMAIL_USERNAME || 'gradido_email', + EMAIL_SENDER: process.env.EMAIL_SENDER || 'info@gradido.net', + EMAIL_PASSWORD: process.env.EMAIL_PASSWORD || 'xxx', + EMAIL_SMTP_URL: process.env.EMAIL_SMTP_URL || 'gmail.com', + EMAIL_SMTP_PORT: process.env.EMAIL_SMTP_PORT || '587', + EMAIL_LINK_VERIFICATION: + process.env.EMAIL_LINK_VERIFICATION || 'http://localhost/checkEmail/{optin}{code}', + EMAIL_LINK_SETPASSWORD: + process.env.EMAIL_LINK_SETPASSWORD || 'http://localhost/reset-password/{optin}', + EMAIL_LINK_FORGOTPASSWORD: + process.env.EMAIL_LINK_FORGOTPASSWORD || 'http://localhost/forgot-password', + EMAIL_LINK_OVERVIEW: process.env.EMAIL_LINK_OVERVIEW || 'http://localhost/overview', + // time in minutes a optin code is valid + EMAIL_CODE_VALID_TIME: process.env.EMAIL_CODE_VALID_TIME + ? parseInt(process.env.EMAIL_CODE_VALID_TIME) || 1440 + : 1440, + // time in minutes that must pass to request a new optin code + EMAIL_CODE_REQUEST_TIME: process.env.EMAIL_CODE_REQUEST_TIME + ? parseInt(process.env.EMAIL_CODE_REQUEST_TIME) || 10 + : 10, +} + +const webhook = { + // Elopage + WEBHOOK_ELOPAGE_SECRET: process.env.WEBHOOK_ELOPAGE_SECRET || 'secret', +} + +const eventProtocol = { + // global switch to enable writing of EventProtocol-Entries + EVENT_PROTOCOL_ENABLED: process.env.EVENT_PROTOCOL_ENABLED || true, +} + +// This is needed by graphql-directive-auth +process.env.APP_SECRET = server.JWT_SECRET + +// Check config version +constants.CONFIG_VERSION.CURRENT = process.env.CONFIG_VERSION || constants.CONFIG_VERSION.DEFAULT +if ( + ![constants.CONFIG_VERSION.EXPECTED, constants.CONFIG_VERSION.DEFAULT].includes( + constants.CONFIG_VERSION.CURRENT, + ) +) { + throw new Error( + `Fatal: Config Version incorrect - expected "${constants.CONFIG_VERSION.EXPECTED}" or "${constants.CONFIG_VERSION.DEFAULT}", but found "${constants.CONFIG_VERSION.CURRENT}"`, + ) +} + +const CONFIG = { + ...constants, + ...server, + ...database, + ...klicktipp, + ...community, + ...email, + ...loginServer, + ...webhook, + ...eventProtocol, +} + +export default CONFIG diff --git a/backend/src/event/EventProtocolEmitter.ts b/backend/src/event/EventProtocolEmitter.ts index 5991bbded..4ee092772 100644 --- a/backend/src/event/EventProtocolEmitter.ts +++ b/backend/src/event/EventProtocolEmitter.ts @@ -1,38 +1,39 @@ -import { Event } from '@/event/Event' -import { backendLogger as logger } from '@/server/logger' -import { EventProtocol } from '@entity/EventProtocol' -import CONFIG from '@/config' - -class EventProtocolEmitter { - /* }extends EventEmitter { */ - private events: Event[] - - public addEvent(event: Event) { - this.events.push(event) - } - - public getEvents(): Event[] { - return this.events - } - - public isEnabled() { - logger.info(`EventProtocol - isEnabled=${CONFIG.EVENT_PROTOCOL_ENABLED}`) - return CONFIG.EVENT_PROTOCOL_ENABLED - } - - public async writeEvent(event: Event): Promise { - if (!eventProtocol.isEnabled()) return - logger.info(`writeEvent(${JSON.stringify(event)})`) - const dbEvent = new EventProtocol() - dbEvent.type = event.type - dbEvent.createdAt = event.createdAt - dbEvent.userId = event.userId - if (event.xUserId) dbEvent.xUserId = event.xUserId - if (event.xCommunityId) dbEvent.xCommunityId = event.xCommunityId - if (event.contributionId) dbEvent.contributionId = event.contributionId - if (event.transactionId) dbEvent.transactionId = event.transactionId - if (event.amount) dbEvent.amount = event.amount - await dbEvent.save() - } -} -export const eventProtocol = new EventProtocolEmitter() +import { Event } from '@/event/Event' +import { backendLogger as logger } from '@/server/logger' +import { EventProtocol } from '@entity/EventProtocol' +import CONFIG from '@/config' + +class EventProtocolEmitter { + /* }extends EventEmitter { */ + private events: Event[] + + public addEvent(event: Event) { + this.events.push(event) + } + + public getEvents(): Event[] { + return this.events + } + + public isEnabled() { + logger.info(`EventProtocol - isEnabled=${CONFIG.EVENT_PROTOCOL_ENABLED}`) + return CONFIG.EVENT_PROTOCOL_ENABLED === true + } + + public async writeEvent(event: Event): Promise { + if (eventProtocol.isEnabled()) { + logger.info(`writeEvent(${JSON.stringify(event)})`) + const dbEvent = new EventProtocol() + dbEvent.type = event.type + dbEvent.createdAt = event.createdAt + dbEvent.userId = event.userId + if (event.xUserId) dbEvent.xUserId = event.xUserId + if (event.xCommunityId) dbEvent.xCommunityId = event.xCommunityId + if (event.contributionId) dbEvent.contributionId = event.contributionId + if (event.transactionId) dbEvent.transactionId = event.transactionId + if (event.amount) dbEvent.amount = event.amount + await dbEvent.save() + } + } +} +export const eventProtocol = new EventProtocolEmitter() diff --git a/deployment/bare_metal/.env.dist b/deployment/bare_metal/.env.dist index edb878040..5747e40ef 100644 --- a/deployment/bare_metal/.env.dist +++ b/deployment/bare_metal/.env.dist @@ -1,80 +1,80 @@ -GRADIDO_LOG_PATH=/home/gradido/gradido/deployment/bare_metal/log - -# start script -DEPLOY_SEED_DATA=false - -# nginx -NGINX_REWRITE_LEGACY_URLS=true -NGINX_SSL=true -NGINX_SERVER_NAME=stage1.gradido.net -NGINX_SSL_CERTIFICATE=/etc/letsencrypt/live/stage1.gradido.net/fullchain.pem -NGINX_SSL_CERTIFICATE_KEY=/etc/letsencrypt/live/stage1.gradido.net/privkey.pem -NGINX_SSL_DHPARAM=/etc/letsencrypt/ssl-dhparams.pem -NGINX_SSL_INCLUDE=/etc/letsencrypt/options-ssl-nginx.conf -NGINX_UPDATE_PAGE_ROOT=/home/gradido/gradido/deployment/bare_metal/nginx/update-page - -# webhook -WEBHOOK_GITHUB_SECRET=secret -WEBHOOK_GITHUB_BRANCH=master - -# community -COMMUNITY_NAME="Gradido Development Stage1" -COMMUNITY_URL=https://stage1.gradido.net/ -COMMUNITY_REGISTER_URL=https://stage1.gradido.net/register -COMMUNITY_REDEEM_URL=https://stage1.gradido.net/redeem/{code} -COMMUNITY_REDEEM_CONTRIBUTION_URL=https://stage1.gradido.net/redeem/CL-{code} -COMMUNITY_DESCRIPTION="Gradido Development Stage1 Test Community" - -# backend -BACKEND_CONFIG_VERSION=v8.2022-06-20 - -JWT_EXPIRES_IN=10m -GDT_API_URL=https://gdt.gradido.net - -TYPEORM_LOGGING_RELATIVE_PATH=../deployment/bare_metal/log/typeorm.backend.log - -KLICKTIPP=false -KLICKTIPP_USER= -KLICKTIPP_PASSWORD= -KLICKTIPP_APIKEY_DE= -KLICKTIPP_APIKEY_EN= - -EMAIL=true -EMAIL_USERNAME=peter@lustig.de -EMAIL_SENDER=peter@lustig.de -EMAIL_PASSWORD=1234 -EMAIL_SMTP_URL=smtp.lustig.de -EMAIL_LINK_VERIFICATION=https://stage1.gradido.net/checkEmail/{optin}{code} -EMAIL_LINK_SETPASSWORD=https://stage1.gradido.net/reset-password/{optin} -EMAIL_LINK_FORGOTPASSWORD=https://stage1.gradido.net/forgot-password -EMAIL_LINK_OVERVIEW=https://stage1.gradido.net/overview -EMAIL_CODE_VALID_TIME=1440 -EMAIL_CODE_REQUEST_TIME=10 - -WEBHOOK_ELOPAGE_SECRET=secret - -# database -DATABASE_CONFIG_VERSION=v1.2022-03-18 - -# frontend -FRONTEND_CONFIG_VERSION=v2.2022-04-07 - -GRAPHQL_URI=https://stage1.gradido.net/graphql -ADMIN_AUTH_URL=https://stage1.gradido.net/admin/authenticate?token={token} - -DEFAULT_PUBLISHER_ID=2896 - -META_URL=http://localhost -META_TITLE_DE="Gradido – Dein Dankbarkeitskonto" -META_TITLE_EN="Gradido - Your gratitude account" -META_DESCRIPTION_DE="Dankbarkeit ist die Währung der neuen Zeit. Immer mehr Menschen entfalten ihr Potenzial und gestalten eine gute Zukunft für alle." -META_DESCRIPTION_EN="Gratitude is the currency of the new age. More and more people are unleashing their potential and shaping a good future for all." -META_KEYWORDS_DE="Grundeinkommen, Währung, Dankbarkeit, Schenk-Ökonomie, Natürliche Ökonomie des Lebens, Ökonomie, Ökologie, Potenzialentfaltung, Schenken und Danken, Kreislauf des Lebens, Geldsystem" -META_KEYWORDS_EN="Basic Income, Currency, Gratitude, Gift Economy, Natural Economy of Life, Economy, Ecology, Potential Development, Giving and Thanking, Cycle of Life, Monetary System" -META_AUTHOR="Bernd Hückstädt - Gradido-Akademie" - -# admin -ADMIN_CONFIG_VERSION=v1.2022-03-18 - -WALLET_AUTH_URL=https://stage1.gradido.net/authenticate?token={token} +GRADIDO_LOG_PATH=/home/gradido/gradido/deployment/bare_metal/log + +# start script +DEPLOY_SEED_DATA=false + +# nginx +NGINX_REWRITE_LEGACY_URLS=true +NGINX_SSL=true +NGINX_SERVER_NAME=stage1.gradido.net +NGINX_SSL_CERTIFICATE=/etc/letsencrypt/live/stage1.gradido.net/fullchain.pem +NGINX_SSL_CERTIFICATE_KEY=/etc/letsencrypt/live/stage1.gradido.net/privkey.pem +NGINX_SSL_DHPARAM=/etc/letsencrypt/ssl-dhparams.pem +NGINX_SSL_INCLUDE=/etc/letsencrypt/options-ssl-nginx.conf +NGINX_UPDATE_PAGE_ROOT=/home/gradido/gradido/deployment/bare_metal/nginx/update-page + +# webhook +WEBHOOK_GITHUB_SECRET=secret +WEBHOOK_GITHUB_BRANCH=master + +# community +COMMUNITY_NAME="Gradido Development Stage1" +COMMUNITY_URL=https://stage1.gradido.net/ +COMMUNITY_REGISTER_URL=https://stage1.gradido.net/register +COMMUNITY_REDEEM_URL=https://stage1.gradido.net/redeem/{code} +COMMUNITY_REDEEM_CONTRIBUTION_URL=https://stage1.gradido.net/redeem/CL-{code} +COMMUNITY_DESCRIPTION="Gradido Development Stage1 Test Community" + +# backend +BACKEND_CONFIG_VERSION=v9.2022-07-07 + +JWT_EXPIRES_IN=10m +GDT_API_URL=https://gdt.gradido.net + +TYPEORM_LOGGING_RELATIVE_PATH=../deployment/bare_metal/log/typeorm.backend.log + +KLICKTIPP=false +KLICKTIPP_USER= +KLICKTIPP_PASSWORD= +KLICKTIPP_APIKEY_DE= +KLICKTIPP_APIKEY_EN= + +EMAIL=true +EMAIL_USERNAME=peter@lustig.de +EMAIL_SENDER=peter@lustig.de +EMAIL_PASSWORD=1234 +EMAIL_SMTP_URL=smtp.lustig.de +EMAIL_LINK_VERIFICATION=https://stage1.gradido.net/checkEmail/{optin}{code} +EMAIL_LINK_SETPASSWORD=https://stage1.gradido.net/reset-password/{optin} +EMAIL_LINK_FORGOTPASSWORD=https://stage1.gradido.net/forgot-password +EMAIL_LINK_OVERVIEW=https://stage1.gradido.net/overview +EMAIL_CODE_VALID_TIME=1440 +EMAIL_CODE_REQUEST_TIME=10 + +WEBHOOK_ELOPAGE_SECRET=secret + +# database +DATABASE_CONFIG_VERSION=v1.2022-03-18 + +# frontend +FRONTEND_CONFIG_VERSION=v2.2022-04-07 + +GRAPHQL_URI=https://stage1.gradido.net/graphql +ADMIN_AUTH_URL=https://stage1.gradido.net/admin/authenticate?token={token} + +DEFAULT_PUBLISHER_ID=2896 + +META_URL=http://localhost +META_TITLE_DE="Gradido – Dein Dankbarkeitskonto" +META_TITLE_EN="Gradido - Your gratitude account" +META_DESCRIPTION_DE="Dankbarkeit ist die Währung der neuen Zeit. Immer mehr Menschen entfalten ihr Potenzial und gestalten eine gute Zukunft für alle." +META_DESCRIPTION_EN="Gratitude is the currency of the new age. More and more people are unleashing their potential and shaping a good future for all." +META_KEYWORDS_DE="Grundeinkommen, Währung, Dankbarkeit, Schenk-Ökonomie, Natürliche Ökonomie des Lebens, Ökonomie, Ökologie, Potenzialentfaltung, Schenken und Danken, Kreislauf des Lebens, Geldsystem" +META_KEYWORDS_EN="Basic Income, Currency, Gratitude, Gift Economy, Natural Economy of Life, Economy, Ecology, Potential Development, Giving and Thanking, Cycle of Life, Monetary System" +META_AUTHOR="Bernd Hückstädt - Gradido-Akademie" + +# admin +ADMIN_CONFIG_VERSION=v1.2022-03-18 + +WALLET_AUTH_URL=https://stage1.gradido.net/authenticate?token={token} WALLET_URL=https://stage1.gradido.net/login \ No newline at end of file From 175bc514be7fea2f1737e4e6861c1fa7c5680e5b Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Fri, 15 Jul 2022 13:36:31 +0200 Subject: [PATCH 083/114] feat: Do not log IntrospectionQuery from Query Browser --- backend/src/server/plugins.ts | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/backend/src/server/plugins.ts b/backend/src/server/plugins.ts index 1972bc1c8..24df45baa 100644 --- a/backend/src/server/plugins.ts +++ b/backend/src/server/plugins.ts @@ -31,20 +31,24 @@ const filterVariables = (variables: any) => { const logPlugin = { requestDidStart(requestContext: any) { const { logger } = requestContext - const { query, mutation, variables } = requestContext.request - logger.info(`Request: + const { query, mutation, variables, operationName } = requestContext.request + if (operationName !== 'IntrospectionQuery') { + logger.info(`Request: ${mutation || query}variables: ${JSON.stringify(filterVariables(variables), null, 2)}`) + } return { willSendResponse(requestContext: any) { - if (requestContext.context.user) logger.info(`User ID: ${requestContext.context.user.id}`) - if (requestContext.response.data) { - logger.info('Response Success!') - logger.trace(`Response-Data: + if (operationName !== 'IntrospectionQuery') { + if (requestContext.context.user) logger.info(`User ID: ${requestContext.context.user.id}`) + if (requestContext.response.data) { + logger.info('Response Success!') + logger.trace(`Response-Data: ${JSON.stringify(requestContext.response.data, null, 2)}`) - } - if (requestContext.response.errors) - logger.error(`Response-Errors: + } + if (requestContext.response.errors) + logger.error(`Response-Errors: ${JSON.stringify(requestContext.response.errors, null, 2)}`) + } return requestContext }, } From d0662270431f112710c23748c72c6577c99eef3e Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 15 Jul 2022 14:13:33 +0200 Subject: [PATCH 084/114] Change the Contribution entity to join on user. --- .../0039-contributions_table/Contribution.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/database/entity/0039-contributions_table/Contribution.ts b/database/entity/0039-contributions_table/Contribution.ts index 6c7358f90..ee6e0f73f 100644 --- a/database/entity/0039-contributions_table/Contribution.ts +++ b/database/entity/0039-contributions_table/Contribution.ts @@ -1,6 +1,15 @@ import Decimal from 'decimal.js-light' -import { BaseEntity, Column, Entity, PrimaryGeneratedColumn, DeleteDateColumn } from 'typeorm' +import { + BaseEntity, + Column, + Entity, + PrimaryGeneratedColumn, + DeleteDateColumn, + OneToOne, + JoinColumn, +} from 'typeorm' import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer' +import { User } from '../User' @Entity('contributions') export class Contribution extends BaseEntity { @@ -10,6 +19,10 @@ export class Contribution extends BaseEntity { @Column({ unsigned: true, nullable: false, name: 'user_id' }) userId: number + @OneToOne(() => User) + @JoinColumn({ name: 'user_id' }) + user: User + @Column({ type: 'datetime', default: () => 'CURRENT_TIMESTAMP', name: 'created_at' }) createdAt: Date From 5f5c19e6ba364ee036284fb47a197a6da3683832 Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 15 Jul 2022 14:14:15 +0200 Subject: [PATCH 085/114] Change find to much more efficient code. --- .../graphql/resolver/ContributionResolver.ts | 28 ++++++------------- 1 file changed, 8 insertions(+), 20 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 812e81527..d71ecac59 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -2,7 +2,6 @@ import { RIGHTS } from '@/auth/RIGHTS' import { Context, getUser } from '@/server/context' import { backendLogger as logger } from '@/server/logger' import { Contribution as dbContribution } from '@entity/Contribution' -import { User as dbUser } from '@entity/User' import { Arg, Args, Authorized, Ctx, Int, Mutation, Query, Resolver } from 'type-graphql' import { FindOperator, IsNull } from '@dbTools/typeorm' import ContributionArgs from '@arg/ContributionArgs' @@ -72,31 +71,20 @@ export class ContributionResolver { @Args() { currentPage = 1, pageSize = 5, order = Order.DESC }: Paginated, ): Promise { - const dbContributions = await dbContribution.find({ + const [dbContributions, count] = await dbContribution.findAndCount({ + relations: ['user'], order: { createdAt: order, }, skip: (currentPage - 1) * pageSize, take: pageSize, }) - const contributions: Contribution[] = [] - const userIds: number[] = [] - dbContributions.forEach(async (dbContribution) => { - userIds.push(dbContribution.userId) - }) - userIds.filter((elem, index, self) => { - return index === self.indexOf(elem) - }) - const users = new Map() - for (let i = 0; i < userIds.length; i++) { - const id = userIds[i] - const user = await dbUser.findOneOrFail({ id }) - users.set(id, user) - } - dbContributions.forEach((dbContribution) => { - contributions.push(new Contribution(dbContribution, users.get(dbContribution.userId))) - }) - return new ContributionListResult(contributions.length, contributions) + return new ContributionListResult( + count, + dbContributions.map( + (contribution) => new Contribution(contribution, new User(contribution.user)), + ), + ) } @Authorized([RIGHTS.UPDATE_CONTRIBUTION]) From 382211f3ca12fa9585ef853751d886672997876e Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 15 Jul 2022 14:14:55 +0200 Subject: [PATCH 086/114] Adapt test so that we check findAllContributions. --- .../src/graphql/resolver/ContributionResolver.test.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index 247d1be0e..fd5ff68a2 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -466,15 +466,14 @@ describe('ContributionResolver', () => { beforeAll(async () => { await userFactory(testEnv, bibiBloxberg) await userFactory(testEnv, peterLustig) - await userFactory(testEnv, raeuberHotzenplotz) - await userFactory(testEnv, bobBaumeister) + const bibisCreation = creations.find((creation) => creation.email === 'bibi@bloxberg.de') // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - creations.forEach(async (creation) => await creationFactory(testEnv, creation!)) + await creationFactory(testEnv, bibisCreation!) await query({ query: login, variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, }) - result = await mutate({ + await mutate({ mutation: createContribution, variables: { amount: 100.0, @@ -499,7 +498,7 @@ describe('ContributionResolver', () => { expect.objectContaining({ data: { listAllContributions: { - linkCount: 25, + linkCount: 2, linkList: expect.arrayContaining([ expect.objectContaining({ id: expect.any(Number), From cada4eca19cfa95b3ba7603838f2f163effb05ad Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 15 Jul 2022 14:32:20 +0200 Subject: [PATCH 087/114] Change OneToOne relation to OneToMany / ManyToOne. --- .../0039-contributions_table/Contribution.ts | 3 ++- .../0040-add_contribution_link_id_to_user/User.ts | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/database/entity/0039-contributions_table/Contribution.ts b/database/entity/0039-contributions_table/Contribution.ts index ee6e0f73f..5df527530 100644 --- a/database/entity/0039-contributions_table/Contribution.ts +++ b/database/entity/0039-contributions_table/Contribution.ts @@ -7,6 +7,7 @@ import { DeleteDateColumn, OneToOne, JoinColumn, + ManyToOne, } from 'typeorm' import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer' import { User } from '../User' @@ -19,7 +20,7 @@ export class Contribution extends BaseEntity { @Column({ unsigned: true, nullable: false, name: 'user_id' }) userId: number - @OneToOne(() => User) + @ManyToOne(() => User, (user) => user.contributions) @JoinColumn({ name: 'user_id' }) user: User diff --git a/database/entity/0040-add_contribution_link_id_to_user/User.ts b/database/entity/0040-add_contribution_link_id_to_user/User.ts index 9bf76e5f5..56047345a 100644 --- a/database/entity/0040-add_contribution_link_id_to_user/User.ts +++ b/database/entity/0040-add_contribution_link_id_to_user/User.ts @@ -1,4 +1,13 @@ -import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, DeleteDateColumn } from 'typeorm' +import { + BaseEntity, + Entity, + PrimaryGeneratedColumn, + Column, + DeleteDateColumn, + OneToMany, + JoinColumn, +} from 'typeorm' +import { Contribution } from '../Contribution' @Entity('users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) export class User extends BaseEntity { @@ -76,4 +85,8 @@ export class User extends BaseEntity { default: null, }) passphrase: string + + @OneToMany(() => Contribution, (contribution) => contribution.user) + @JoinColumn({ name: 'user_id' }) + contributions?: Contribution[] } From 843993e34085397eb86b8e67477bf58e94debd6a Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 15 Jul 2022 14:34:47 +0200 Subject: [PATCH 088/114] Fix linting. --- backend/src/graphql/resolver/ContributionResolver.test.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index fd5ff68a2..e6478ffc2 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -14,8 +14,6 @@ import { userFactory } from '@/seeds/factory/user' import { creationFactory } from '@/seeds/factory/creation' import { creations } from '@/seeds/creation/index' import { peterLustig } from '@/seeds/users/peter-lustig' -import { bobBaumeister } from '@/seeds/users/bob-baumeister' -import { raeuberHotzenplotz } from '@/seeds/users/raeuber-hotzenplotz' let mutate: any, query: any, con: any let testEnv: any From 5892f7b42947db8270fe4d26a4faed587abe68c3 Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 15 Jul 2022 14:48:51 +0200 Subject: [PATCH 089/114] Remove OneToOne import from contribution entity. --- database/entity/0039-contributions_table/Contribution.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/database/entity/0039-contributions_table/Contribution.ts b/database/entity/0039-contributions_table/Contribution.ts index 5df527530..b5e6ac0e0 100644 --- a/database/entity/0039-contributions_table/Contribution.ts +++ b/database/entity/0039-contributions_table/Contribution.ts @@ -5,7 +5,6 @@ import { Entity, PrimaryGeneratedColumn, DeleteDateColumn, - OneToOne, JoinColumn, ManyToOne, } from 'typeorm' From 5810235cec56053a6413b5601544a14b1d2b77db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Fri, 15 Jul 2022 16:40:46 +0200 Subject: [PATCH 090/114] add EVENT_PROTOCOL_ENABLED --- deployment/bare_metal/.env.dist | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/deployment/bare_metal/.env.dist b/deployment/bare_metal/.env.dist index 5747e40ef..a7f63fa27 100644 --- a/deployment/bare_metal/.env.dist +++ b/deployment/bare_metal/.env.dist @@ -53,6 +53,10 @@ EMAIL_CODE_REQUEST_TIME=10 WEBHOOK_ELOPAGE_SECRET=secret +# EventProtocol +EVENT_PROTOCOL_ENABLED=true + + # database DATABASE_CONFIG_VERSION=v1.2022-03-18 From 93c2d6814ad1952105d1fbdc05f94ef174712c10 Mon Sep 17 00:00:00 2001 From: elweyn Date: Mon, 18 Jul 2022 11:27:44 +0200 Subject: [PATCH 091/114] Change the listContribution query to give back ContributionListResult object with linkCount. --- backend/src/graphql/resolver/ContributionResolver.ts | 12 ++++++++---- backend/src/seeds/graphql/queries.ts | 9 ++++++--- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index d71ecac59..c834904d6 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -2,6 +2,7 @@ import { RIGHTS } from '@/auth/RIGHTS' import { Context, getUser } from '@/server/context' import { backendLogger as logger } from '@/server/logger' import { Contribution as dbContribution } from '@entity/Contribution' +import { User as dbUser } from '@entity/User' import { Arg, Args, Authorized, Ctx, Int, Mutation, Query, Resolver } from 'type-graphql' import { FindOperator, IsNull } from '@dbTools/typeorm' import ContributionArgs from '@arg/ContributionArgs' @@ -39,21 +40,21 @@ export class ContributionResolver { } @Authorized([RIGHTS.LIST_CONTRIBUTIONS]) - @Query(() => [Contribution]) + @Query(() => ContributionListResult) async listContributions( @Args() { currentPage = 1, pageSize = 5, order = Order.DESC }: Paginated, @Arg('filterConfirmed', () => Boolean) filterConfirmed: boolean | null, @Ctx() context: Context, - ): Promise { + ): Promise { const user = getUser(context) const where: { userId: number confirmedBy?: FindOperator | null } = { userId: user.id } if (filterConfirmed) where.confirmedBy = IsNull() - const contributions = await dbContribution.find({ + const [contributions, count] = await dbContribution.findAndCount({ where, order: { createdAt: order, @@ -62,7 +63,10 @@ export class ContributionResolver { skip: (currentPage - 1) * pageSize, take: pageSize, }) - return contributions.map((contribution) => new Contribution(contribution, new User(user))) + return new ContributionListResult( + count, + contributions.map((contribution) => new Contribution(contribution, new User(user))), + ) } @Authorized([RIGHTS.LIST_ALL_CONTRIBUTIONS]) diff --git a/backend/src/seeds/graphql/queries.ts b/backend/src/seeds/graphql/queries.ts index deae5f97b..e18d6b303 100644 --- a/backend/src/seeds/graphql/queries.ts +++ b/backend/src/seeds/graphql/queries.ts @@ -185,9 +185,12 @@ export const listContributions = gql` order: $order filterConfirmed: $filterConfirmed ) { - id - amount - memo + linkCount + linkList { + id + amount + memo + } } } ` From 495fbfd05ce3b16b3d081ed128854d0c32e014eb Mon Sep 17 00:00:00 2001 From: elweyn Date: Mon, 18 Jul 2022 11:31:04 +0200 Subject: [PATCH 092/114] Change linkCount to contributionCount and linkList to contributionList. --- backend/src/graphql/model/Contribution.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/src/graphql/model/Contribution.ts b/backend/src/graphql/model/Contribution.ts index 34bffd6d7..13c2d40d7 100644 --- a/backend/src/graphql/model/Contribution.ts +++ b/backend/src/graphql/model/Contribution.ts @@ -48,13 +48,13 @@ export class Contribution { @ObjectType() export class ContributionListResult { constructor(count: number, list: Contribution[]) { - this.linkCount = count - this.linkList = list + this.contributionCount = count + this.contributionList = list } @Field(() => Int) - linkCount: number + contributionCount: number @Field(() => [Contribution]) - linkList: Contribution[] + contributionList: Contribution[] } From 3a8fb6b353454452e344ae9eef76cfeea51ed8d4 Mon Sep 17 00:00:00 2001 From: elweyn Date: Mon, 18 Jul 2022 11:31:39 +0200 Subject: [PATCH 093/114] Change query of listContribution to get contributionCount and contributionList instead of link... --- backend/src/seeds/graphql/queries.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/seeds/graphql/queries.ts b/backend/src/seeds/graphql/queries.ts index e18d6b303..0d72c165d 100644 --- a/backend/src/seeds/graphql/queries.ts +++ b/backend/src/seeds/graphql/queries.ts @@ -185,8 +185,8 @@ export const listContributions = gql` order: $order filterConfirmed: $filterConfirmed ) { - linkCount - linkList { + contributionCount + contributionList { id amount memo From 11dacd40be4c9fec9000253d1898ee536a3eb0c1 Mon Sep 17 00:00:00 2001 From: elweyn Date: Mon, 18 Jul 2022 11:34:30 +0200 Subject: [PATCH 094/114] Change query listAllContributions now gets contributionCount and contributionList instead of linkCount and linkList. --- backend/src/seeds/graphql/queries.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/seeds/graphql/queries.ts b/backend/src/seeds/graphql/queries.ts index 0d72c165d..9f7a02e70 100644 --- a/backend/src/seeds/graphql/queries.ts +++ b/backend/src/seeds/graphql/queries.ts @@ -198,8 +198,8 @@ export const listContributions = gql` export const listAllContributions = ` query ($currentPage: Int = 1, $pageSize: Int = 5, $order: Order = DESC) { listAllContributions(currentPage: $currentPage, pageSize: $pageSize, order: $order) { - linkCount - linkList { + contributionCount + contributionList { id firstName lastName From 1ec317259b2e1b65eb70303355395c081d060004 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Mon, 18 Jul 2022 11:35:31 +0200 Subject: [PATCH 095/114] Document the setup of the GraphQL Playground --- backend/README.md | 52 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/backend/README.md b/backend/README.md index e74750c46..173450fe7 100644 --- a/backend/README.md +++ b/backend/README.md @@ -1,16 +1,18 @@ # backend ## Project setup -``` + +```bash yarn install ``` ## Seed DB -``` + +```bash yarn seed ``` -Deletes all data in database. Then seeds data in database. +Deletes all data in database. Then seeds data in database. ## Seeded Users @@ -22,3 +24,47 @@ Deletes all data in database. Then seeds data in database. | bob@baumeister.de | `Aa12345_` | `false` | `true` | `false` | | garrick@ollivander.com | | `false` | `false` | `false` | | stephen@hawking.uk | `Aa12345_` | `false` | `true` | `true` | + +## Setup GraphQL Playground + +### Setup In The Code + +Setting up the GraphQL Playground in our code requires the following steps: + +- Create an empty `.env` file in the `backend` folder and set "GRAPHIQL=true" there. +- Start or restart Docker Compose. +- For verification, Docker should display `GraphQL available at http://localhost:4000` in the terminal. +- If you open "http://localhost:4000/" in your browser, you should see the GraphQL Playground. + +### Authentication + +To authenticate yourself in GraphQL Playground to be able to send queries and mutations, follow the steps below: + +- in Firefox go to "Network Analysis" and delete all entries +- enter and send the login query: + +```gql +{ + login(email: "bibi@bloxberg.de", password:"Aa12345_") { + id + publisherId + email + firstName + lastName + emailChecked + language + hasElopage + } +} +``` + +- search in Firefox under „Network Analysis" for the smallest size of a header and copy the token +- open the header section in GraphQL Playground and set your current token by filling in and replacing `XXX`: + +```qgl +{ + "Authorization": "XXX" +} +``` + +Now you can open a new tap in the Playground and enter your query or mutation there. From 42b8d625da34a908c5c3dd79254141f7bc5ee52f Mon Sep 17 00:00:00 2001 From: elweyn Date: Mon, 18 Jul 2022 11:38:58 +0200 Subject: [PATCH 096/114] Change query fields to new names. --- .../resolver/ContributionResolver.test.ts | 48 +++++++++++-------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index e6478ffc2..37ff45f25 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -193,18 +193,21 @@ describe('ContributionResolver', () => { ).resolves.toEqual( expect.objectContaining({ data: { - listContributions: expect.arrayContaining([ - expect.objectContaining({ - id: expect.any(Number), - memo: 'Herzlich Willkommen bei Gradido!', - amount: '1000', - }), - expect.objectContaining({ - id: expect.any(Number), - memo: 'Test env contribution', - amount: '100', - }), - ]), + listContributions: { + contributionCount: 2, + contributionList: expect.arrayContaining([ + expect.objectContaining({ + id: expect.any(Number), + memo: 'Herzlich Willkommen bei Gradido!', + amount: '1000', + }), + expect.objectContaining({ + id: expect.any(Number), + memo: 'Test env contribution', + amount: '100', + }), + ]), + }, }, }), ) @@ -226,13 +229,16 @@ describe('ContributionResolver', () => { ).resolves.toEqual( expect.objectContaining({ data: { - listContributions: expect.arrayContaining([ - expect.objectContaining({ - id: expect.any(Number), - memo: 'Test env contribution', - amount: '100', - }), - ]), + listContributions: { + contributionCount: 1, + contributionList: expect.arrayContaining([ + expect.objectContaining({ + id: expect.any(Number), + memo: 'Test env contribution', + amount: '100', + }), + ]), + }, }, }), ) @@ -496,8 +502,8 @@ describe('ContributionResolver', () => { expect.objectContaining({ data: { listAllContributions: { - linkCount: 2, - linkList: expect.arrayContaining([ + contributionCount: 2, + contributionList: expect.arrayContaining([ expect.objectContaining({ id: expect.any(Number), memo: 'Herzlich Willkommen bei Gradido!', From ae04024dd38b56ed5e702fc7a9e37d183cf76066 Mon Sep 17 00:00:00 2001 From: elweyn Date: Mon, 18 Jul 2022 11:39:17 +0200 Subject: [PATCH 097/114] Remove unused import. --- backend/src/graphql/resolver/ContributionResolver.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index c834904d6..f21c65068 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -2,7 +2,6 @@ import { RIGHTS } from '@/auth/RIGHTS' import { Context, getUser } from '@/server/context' import { backendLogger as logger } from '@/server/logger' import { Contribution as dbContribution } from '@entity/Contribution' -import { User as dbUser } from '@entity/User' import { Arg, Args, Authorized, Ctx, Int, Mutation, Query, Resolver } from 'type-graphql' import { FindOperator, IsNull } from '@dbTools/typeorm' import ContributionArgs from '@arg/ContributionArgs' From c6279a3ba141f4a93dc29783ef42f718db517ab8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Mon, 18 Jul 2022 12:25:36 +0200 Subject: [PATCH 098/114] Update backend/README.md Co-authored-by: Hannes Heine --- backend/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/README.md b/backend/README.md index 173450fe7..c28469aa9 100644 --- a/backend/README.md +++ b/backend/README.md @@ -38,7 +38,7 @@ Setting up the GraphQL Playground in our code requires the following steps: ### Authentication -To authenticate yourself in GraphQL Playground to be able to send queries and mutations, follow the steps below: +You need to authenticate yourself in GraphQL Playground to be able to send queries and mutations, to do so follow the steps below: - in Firefox go to "Network Analysis" and delete all entries - enter and send the login query: From b7949a62201e5592a8ddc4d0c6af113a335d0903 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Mon, 18 Jul 2022 12:25:58 +0200 Subject: [PATCH 099/114] Update backend/README.md Co-authored-by: Hannes Heine --- backend/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/README.md b/backend/README.md index c28469aa9..b27ab16d9 100644 --- a/backend/README.md +++ b/backend/README.md @@ -58,7 +58,7 @@ You need to authenticate yourself in GraphQL Playground to be able to send queri } ``` -- search in Firefox under „Network Analysis" for the smallest size of a header and copy the token +- search in Firefox under „Network Analysis" for the smallest size of a header and copy the value of the token - open the header section in GraphQL Playground and set your current token by filling in and replacing `XXX`: ```qgl From da3574edb81aa93a362aa61a69ff5cbd459fe5ba Mon Sep 17 00:00:00 2001 From: elweyn Date: Mon, 18 Jul 2022 12:35:42 +0200 Subject: [PATCH 100/114] Fix merge conflict and reviewed name changes. --- .../graphql/resolver/ContributionResolver.ts | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 20eeaa199..90ec6b5a6 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -1,13 +1,6 @@ import { RIGHTS } from '@/auth/RIGHTS' import { Context, getUser } from '@/server/context' import { backendLogger as logger } from '@/server/logger' -<<<<<<< HEAD -import { Contribution } from '@entity/Contribution' -import { Arg, Args, Authorized, Ctx, Int, Mutation, Resolver } from 'type-graphql' -import ContributionArgs from '../arg/ContributionArgs' -import { UnconfirmedContribution } from '../model/UnconfirmedContribution' -import { validateContribution, getUserCreation } from './util/creations' -======= import { Contribution as dbContribution } from '@entity/Contribution' import { Arg, Args, Authorized, Ctx, Int, Mutation, Query, Resolver } from 'type-graphql' import { FindOperator, IsNull } from '@dbTools/typeorm' @@ -18,7 +11,6 @@ import { Contribution, ContributionListResult } from '@model/Contribution' import { UnconfirmedContribution } from '@model/UnconfirmedContribution' import { User } from '@model/User' import { validateContribution, getUserCreation, updateCreations } from './util/creations' ->>>>>>> master @Resolver() export class ContributionResolver { @@ -46,15 +38,14 @@ export class ContributionResolver { return new UnconfirmedContribution(contribution, user, creations) } -<<<<<<< HEAD @Authorized([RIGHTS.DELETE_CONTRIBUTION]) @Mutation(() => Boolean) - async adminDeleteContribution( + async deleteContribution( @Arg('id', () => Int) id: number, @Ctx() context: Context, ): Promise { const user = getUser(context) - const contribution = await Contribution.findOne(id) + const contribution = await dbContribution.findOne(id) if (!contribution) { throw new Error('Contribution not found for given id.') } @@ -63,7 +54,8 @@ export class ContributionResolver { } const res = await contribution.softRemove() return !!res -======= + } + @Authorized([RIGHTS.LIST_CONTRIBUTIONS]) @Query(() => [Contribution]) async listContributions( @@ -147,6 +139,5 @@ export class ContributionResolver { dbContribution.save(contributionToUpdate) return new UnconfirmedContribution(contributionToUpdate, user, creations) ->>>>>>> master } } From 4c33d3784b4dfcbe13ad0d2054c0e3d3863f904d Mon Sep 17 00:00:00 2001 From: elweyn Date: Mon, 18 Jul 2022 13:07:44 +0200 Subject: [PATCH 101/114] Added mutation for deleteContribution --- backend/src/seeds/graphql/mutations.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/backend/src/seeds/graphql/mutations.ts b/backend/src/seeds/graphql/mutations.ts index 4e7fa8a90..bf898bd7d 100644 --- a/backend/src/seeds/graphql/mutations.ts +++ b/backend/src/seeds/graphql/mutations.ts @@ -255,3 +255,9 @@ export const updateContribution = gql` } } ` + +export const deleteContribution = gql` + mutation ($id: Int!) { + deleteContribution(id: $id) + } +` From e84061c412a9ba5ecb3b7f0c35dff2ba8702c35d Mon Sep 17 00:00:00 2001 From: elweyn Date: Mon, 18 Jul 2022 13:08:27 +0200 Subject: [PATCH 102/114] Added tests for deleteContribution --- .../resolver/ContributionResolver.test.ts | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index e6478ffc2..37cb2c645 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -5,6 +5,7 @@ import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { adminUpdateContribution, createContribution, + deleteContribution, updateContribution, } from '@/seeds/graphql/mutations' import { listAllContributions, listContributions, login } from '@/seeds/graphql/queries' @@ -481,6 +482,11 @@ describe('ContributionResolver', () => { }) }) + afterAll(async () => { + await cleanDB() + resetToken() + }) + it('returns allCreation', async () => { await expect( query({ @@ -516,4 +522,98 @@ describe('ContributionResolver', () => { }) }) }) + + describe('deleteContribution', () => { + describe('unauthenticated', () => { + it('returns an error', async () => { + await expect( + query({ + query: deleteContribution, + variables: { + id: -1, + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('401 Unauthorized')], + }), + ) + }) + }) + + describe('authenticated', () => { + beforeAll(async () => { + await userFactory(testEnv, bibiBloxberg) + await userFactory(testEnv, peterLustig) + await query({ + query: login, + variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, + }) + result = await mutate({ + mutation: createContribution, + variables: { + amount: 100.0, + memo: 'Test env contribution', + creationDate: new Date().toString(), + }, + }) + }) + + afterAll(async () => { + await cleanDB() + resetToken() + }) + + describe('wrong contribution id', () => { + it('returns an error', async () => { + await expect( + query({ + query: deleteContribution, + variables: { + id: -1, + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('Contribution not found for given id.')], + }), + ) + }) + }) + + describe('other user sends a deleteContribtuion', () => { + it('returns an error', async () => { + await query({ + query: login, + variables: { email: 'peter@lustig.de', password: 'Aa12345_' }, + }) + await expect( + query({ + query: deleteContribution, + variables: { + id: result.data.createContribution.id, + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('Can not delete contribution of another user')], + }), + ) + }) + }) + + describe('User deletes own contribution', () => { + it('deletes successfully', async () => { + await expect( + query({ + query: deleteContribution, + variables: { + id: result.data.createContribution.id, + }, + }), + ).resolves.toBeTruthy() + }) + }) + }) + }) }) From 212952cf5658478e2cf914a4bc1f90178589e2fc Mon Sep 17 00:00:00 2001 From: clauspeterhuebner <86960882+clauspeterhuebner@users.noreply.github.com> Date: Mon, 18 Jul 2022 19:30:25 +0200 Subject: [PATCH 103/114] Update backend/.env.dist Co-authored-by: Moriz Wahl --- backend/.env.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/.env.dist b/backend/.env.dist index fc8544b96..ae89985e3 100644 --- a/backend/.env.dist +++ b/backend/.env.dist @@ -53,7 +53,7 @@ EMAIL_CODE_REQUEST_TIME=10 WEBHOOK_ELOPAGE_SECRET=secret # EventProtocol -EVENT_PROTOCOL_ENABLED=true +EVENT_PROTOCOL_DISABLED=false # SET LOG LEVEL AS NEEDED IN YOUR .ENV # POSSIBLE VALUES: all | trace | debug | info | warn | error | fatal From d4f32f42e050a069c87621716f08dcda8d13a700 Mon Sep 17 00:00:00 2001 From: clauspeterhuebner <86960882+clauspeterhuebner@users.noreply.github.com> Date: Mon, 18 Jul 2022 19:30:56 +0200 Subject: [PATCH 104/114] Update backend/.env.template Co-authored-by: Moriz Wahl --- backend/.env.template | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/.env.template b/backend/.env.template index c6c0819e3..8812806cc 100644 --- a/backend/.env.template +++ b/backend/.env.template @@ -52,4 +52,4 @@ EMAIL_CODE_REQUEST_TIME=$EMAIL_CODE_REQUEST_TIME WEBHOOK_ELOPAGE_SECRET=$WEBHOOK_ELOPAGE_SECRET # EventProtocol -EVENT_PROTOCOL_ENABLED=true +EVENT_PROTOCOL_DISABLED=$EVENT_PROTOCOL_DISABLED From 3e617fdf9596b075dd720750109d68444cdf870c Mon Sep 17 00:00:00 2001 From: clauspeterhuebner <86960882+clauspeterhuebner@users.noreply.github.com> Date: Mon, 18 Jul 2022 19:31:24 +0200 Subject: [PATCH 105/114] Update deployment/bare_metal/.env.dist Co-authored-by: Moriz Wahl --- deployment/bare_metal/.env.dist | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployment/bare_metal/.env.dist b/deployment/bare_metal/.env.dist index a7f63fa27..d53ffebbe 100644 --- a/deployment/bare_metal/.env.dist +++ b/deployment/bare_metal/.env.dist @@ -54,7 +54,7 @@ EMAIL_CODE_REQUEST_TIME=10 WEBHOOK_ELOPAGE_SECRET=secret # EventProtocol -EVENT_PROTOCOL_ENABLED=true +EVENT_PROTOCOL_DISABLED=false # database From 1691167582e94a8ee7b77269d9867713ebd4636f Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 18 Jul 2022 23:47:24 +0200 Subject: [PATCH 106/114] explain nginx ports with docker --- README.md | 2 +- frontend/.env.old | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 frontend/.env.old diff --git a/README.md b/README.md index 145ce4141..3d086018e 100644 --- a/README.md +++ b/README.md @@ -123,7 +123,7 @@ Note: The Changelog will be regenerated with all tags on release on the external ## How the different .env work on deploy -Each component (frontend, admin, backend and database) has its own `.env` file. When running in development you usually do not have to care about the `.env`. The defaults are set by the respective config file, found in the `src/config/` folder of each component. But if you have a local `.env`, the defaults set in the config are overwritten by the `.env`. +Each component (frontend, admin, backend and database) has its own `.env` file. When running in development with docker and nginx you usually do not have to care about the `.env`. The defaults are set by the respective config file, found in the `src/config/` folder of each component. But if you have a local `.env`, the defaults set in the config are overwritten by the `.env`. If you do not use docker, you need the `.env` in the frontend and admin interface because nginx is not running in order to find the backend. Each component has a `.env.dist` file. This file contains all environment variables used by the component and can be used as pattern. If you want to use a local `.env`, copy the `.env.dist` and adjust the variables accordingly. diff --git a/frontend/.env.old b/frontend/.env.old new file mode 100644 index 000000000..a22b31307 --- /dev/null +++ b/frontend/.env.old @@ -0,0 +1,4 @@ +LOGIN_API_URL=http://localhost/login_api/ +COMMUNITY_API_URL=http://localhost/api/ +ALLOW_REGISTER=true +GRAPHQL_URI=http://localhost:4000/graphql From e9b8691b388aad7032d4db11316e318f62acc9cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Mon, 18 Jul 2022 23:53:59 +0200 Subject: [PATCH 107/114] turned around the logic --- backend/src/config/index.ts | 2 +- backend/src/event/EventProtocolEmitter.ts | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index 240b4d61e..2120fce71 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -96,7 +96,7 @@ const webhook = { const eventProtocol = { // global switch to enable writing of EventProtocol-Entries - EVENT_PROTOCOL_ENABLED: process.env.EVENT_PROTOCOL_ENABLED || true, + EVENT_PROTOCOL_DISABLED: process.env.EVENT_PROTOCOL_DISABLED === 'true' || false, } // This is needed by graphql-directive-auth diff --git a/backend/src/event/EventProtocolEmitter.ts b/backend/src/event/EventProtocolEmitter.ts index 4ee092772..6dea99810 100644 --- a/backend/src/event/EventProtocolEmitter.ts +++ b/backend/src/event/EventProtocolEmitter.ts @@ -15,13 +15,13 @@ class EventProtocolEmitter { return this.events } - public isEnabled() { - logger.info(`EventProtocol - isEnabled=${CONFIG.EVENT_PROTOCOL_ENABLED}`) - return CONFIG.EVENT_PROTOCOL_ENABLED === true + public isDisabled() { + logger.info(`EventProtocol - isDisabled=${CONFIG.EVENT_PROTOCOL_DISABLED}`) + return CONFIG.EVENT_PROTOCOL_DISABLED === true } public async writeEvent(event: Event): Promise { - if (eventProtocol.isEnabled()) { + if (!eventProtocol.isDisabled()) { logger.info(`writeEvent(${JSON.stringify(event)})`) const dbEvent = new EventProtocol() dbEvent.type = event.type From 86487a2ddb08dec60dc9f8a596bc0dbfeed687d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Mon, 18 Jul 2022 23:55:13 +0200 Subject: [PATCH 108/114] change to Unix LF --- backend/.env.template | 110 +++++++++++++++++++++--------------------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/backend/.env.template b/backend/.env.template index 8812806cc..beaa256ef 100644 --- a/backend/.env.template +++ b/backend/.env.template @@ -1,55 +1,55 @@ -CONFIG_VERSION=$BACKEND_CONFIG_VERSION - -# Server -JWT_SECRET=$JWT_SECRET -JWT_EXPIRES_IN=$JWT_EXPIRES_IN -GRAPHIQL=false -GDT_API_URL=$GDT_API_URL - -# Database -DB_HOST=localhost -DB_PORT=3306 -DB_USER=$DB_USER -DB_PASSWORD=$DB_PASSWORD -DB_DATABASE=gradido_community -TYPEORM_LOGGING_RELATIVE_PATH=$TYPEORM_LOGGING_RELATIVE_PATH - -# Klicktipp -KLICKTIPP=$KLICKTIPP -KLICKTTIPP_API_URL=https://api.klicktipp.com -KLICKTIPP_USER=$KLICKTIPP_USER -KLICKTIPP_PASSWORD=$KLICKTIPP_PASSWORD -KLICKTIPP_APIKEY_DE=$KLICKTIPP_APIKEY_DE -KLICKTIPP_APIKEY_EN=$KLICKTIPP_APIKEY_EN - -# Community -COMMUNITY_NAME=$COMMUNITY_NAME -COMMUNITY_URL=$COMMUNITY_URL -COMMUNITY_REGISTER_URL=$COMMUNITY_REGISTER_URL -COMMUNITY_REDEEM_URL=$COMMUNITY_REDEEM_URL -COMMUNITY_REDEEM_CONTRIBUTION_URL=$COMMUNITY_REDEEM_CONTRIBUTION_URL -COMMUNITY_DESCRIPTION=$COMMUNITY_DESCRIPTION - -# Login Server -LOGIN_APP_SECRET=21ffbbc616fe -LOGIN_SERVER_KEY=a51ef8ac7ef1abf162fb7a65261acd7a - -# EMail -EMAIL=$EMAIL -EMAIL_USERNAME=$EMAIL_USERNAME -EMAIL_SENDER=$EMAIL_SENDER -EMAIL_PASSWORD=$EMAIL_PASSWORD -EMAIL_SMTP_URL=$EMAIL_SMTP_URL -EMAIL_SMTP_PORT=587 -EMAIL_LINK_VERIFICATION=$EMAIL_LINK_VERIFICATION -EMAIL_LINK_SETPASSWORD=$EMAIL_LINK_SETPASSWORD -EMAIL_LINK_FORGOTPASSWORD=$EMAIL_LINK_FORGOTPASSWORD -EMAIL_LINK_OVERVIEW=$EMAIL_LINK_OVERVIEW -EMAIL_CODE_VALID_TIME=$EMAIL_CODE_VALID_TIME -EMAIL_CODE_REQUEST_TIME=$EMAIL_CODE_REQUEST_TIME - -# Webhook -WEBHOOK_ELOPAGE_SECRET=$WEBHOOK_ELOPAGE_SECRET - -# EventProtocol -EVENT_PROTOCOL_DISABLED=$EVENT_PROTOCOL_DISABLED +CONFIG_VERSION=$BACKEND_CONFIG_VERSION + +# Server +JWT_SECRET=$JWT_SECRET +JWT_EXPIRES_IN=$JWT_EXPIRES_IN +GRAPHIQL=false +GDT_API_URL=$GDT_API_URL + +# Database +DB_HOST=localhost +DB_PORT=3306 +DB_USER=$DB_USER +DB_PASSWORD=$DB_PASSWORD +DB_DATABASE=gradido_community +TYPEORM_LOGGING_RELATIVE_PATH=$TYPEORM_LOGGING_RELATIVE_PATH + +# Klicktipp +KLICKTIPP=$KLICKTIPP +KLICKTTIPP_API_URL=https://api.klicktipp.com +KLICKTIPP_USER=$KLICKTIPP_USER +KLICKTIPP_PASSWORD=$KLICKTIPP_PASSWORD +KLICKTIPP_APIKEY_DE=$KLICKTIPP_APIKEY_DE +KLICKTIPP_APIKEY_EN=$KLICKTIPP_APIKEY_EN + +# Community +COMMUNITY_NAME=$COMMUNITY_NAME +COMMUNITY_URL=$COMMUNITY_URL +COMMUNITY_REGISTER_URL=$COMMUNITY_REGISTER_URL +COMMUNITY_REDEEM_URL=$COMMUNITY_REDEEM_URL +COMMUNITY_REDEEM_CONTRIBUTION_URL=$COMMUNITY_REDEEM_CONTRIBUTION_URL +COMMUNITY_DESCRIPTION=$COMMUNITY_DESCRIPTION + +# Login Server +LOGIN_APP_SECRET=21ffbbc616fe +LOGIN_SERVER_KEY=a51ef8ac7ef1abf162fb7a65261acd7a + +# EMail +EMAIL=$EMAIL +EMAIL_USERNAME=$EMAIL_USERNAME +EMAIL_SENDER=$EMAIL_SENDER +EMAIL_PASSWORD=$EMAIL_PASSWORD +EMAIL_SMTP_URL=$EMAIL_SMTP_URL +EMAIL_SMTP_PORT=587 +EMAIL_LINK_VERIFICATION=$EMAIL_LINK_VERIFICATION +EMAIL_LINK_SETPASSWORD=$EMAIL_LINK_SETPASSWORD +EMAIL_LINK_FORGOTPASSWORD=$EMAIL_LINK_FORGOTPASSWORD +EMAIL_LINK_OVERVIEW=$EMAIL_LINK_OVERVIEW +EMAIL_CODE_VALID_TIME=$EMAIL_CODE_VALID_TIME +EMAIL_CODE_REQUEST_TIME=$EMAIL_CODE_REQUEST_TIME + +# Webhook +WEBHOOK_ELOPAGE_SECRET=$WEBHOOK_ELOPAGE_SECRET + +# EventProtocol +EVENT_PROTOCOL_DISABLED=$EVENT_PROTOCOL_DISABLED From b31309f7ef76fb87e4b0ca7d75351d30b73b35ea Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 19 Jul 2022 00:22:47 +0200 Subject: [PATCH 109/114] remove file artifact --- frontend/.env.old | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 frontend/.env.old diff --git a/frontend/.env.old b/frontend/.env.old deleted file mode 100644 index a22b31307..000000000 --- a/frontend/.env.old +++ /dev/null @@ -1,4 +0,0 @@ -LOGIN_API_URL=http://localhost/login_api/ -COMMUNITY_API_URL=http://localhost/api/ -ALLOW_REGISTER=true -GRAPHQL_URI=http://localhost:4000/graphql From c9098fa2cf10aefbfa4bbc4add1ccc269cc49023 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 19 Jul 2022 11:47:03 +0200 Subject: [PATCH 110/114] fix: Add Contributions to User --- .../entity/0039-contributions_table/User.ts | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 database/entity/0039-contributions_table/User.ts diff --git a/database/entity/0039-contributions_table/User.ts b/database/entity/0039-contributions_table/User.ts new file mode 100644 index 000000000..147ae6f6f --- /dev/null +++ b/database/entity/0039-contributions_table/User.ts @@ -0,0 +1,83 @@ +import { + BaseEntity, + Entity, + PrimaryGeneratedColumn, + Column, + DeleteDateColumn, + OneToMany, + JoinColumn, +} from 'typeorm' +import { Contribution } from '../Contribution' + +@Entity('users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) +export class User extends BaseEntity { + @PrimaryGeneratedColumn('increment', { unsigned: true }) + id: number + + @Column({ name: 'public_key', type: 'binary', length: 32, default: null, nullable: true }) + pubKey: Buffer + + @Column({ name: 'privkey', type: 'binary', length: 80, default: null, nullable: true }) + privKey: Buffer + + @Column({ length: 255, unique: true, nullable: false, collation: 'utf8mb4_unicode_ci' }) + email: string + + @Column({ + name: 'first_name', + length: 255, + nullable: true, + default: null, + collation: 'utf8mb4_unicode_ci', + }) + firstName: string + + @Column({ + name: 'last_name', + length: 255, + nullable: true, + default: null, + collation: 'utf8mb4_unicode_ci', + }) + lastName: string + + @DeleteDateColumn() + deletedAt: Date | null + + @Column({ type: 'bigint', default: 0, unsigned: true }) + password: BigInt + + @Column({ name: 'email_hash', type: 'binary', length: 32, default: null, nullable: true }) + emailHash: Buffer + + @Column({ name: 'created', default: () => 'CURRENT_TIMESTAMP', nullable: false }) + createdAt: Date + + @Column({ name: 'email_checked', type: 'bool', nullable: false, default: false }) + emailChecked: boolean + + @Column({ length: 4, default: 'de', collation: 'utf8mb4_unicode_ci', nullable: false }) + language: string + + @Column({ name: 'is_admin', type: 'datetime', nullable: true, default: null }) + isAdmin: Date | null + + @Column({ name: 'referrer_id', type: 'int', unsigned: true, nullable: true, default: null }) + referrerId?: number | null + + @Column({ name: 'publisher_id', default: 0 }) + publisherId: number + + @Column({ + type: 'text', + name: 'passphrase', + collation: 'utf8mb4_unicode_ci', + nullable: true, + default: null, + }) + passphrase: string + + @OneToMany(() => Contribution, (contribution) => contribution.user) + @JoinColumn({ name: 'user_id' }) + contributions?: Contribution[] +} From b4a4a9e12699ce49ba77bafe927a0f460b874d09 Mon Sep 17 00:00:00 2001 From: elweyn Date: Tue, 19 Jul 2022 13:09:03 +0200 Subject: [PATCH 111/114] Throw error if confirmedAt is present. --- backend/src/graphql/resolver/ContributionResolver.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 8ee994989..ef4467a71 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -52,6 +52,9 @@ export class ContributionResolver { if (contribution.userId !== user.id) { throw new Error('Can not delete contribution of another user') } + if (contribution.confirmedAt) { + throw new Error('A confirmed contribution can not be deleted') + } const res = await contribution.softRemove() return !!res } From ccc16b4083acb5c2607af5e20b7dd58c92d27bd7 Mon Sep 17 00:00:00 2001 From: elweyn Date: Tue, 19 Jul 2022 13:09:44 +0200 Subject: [PATCH 112/114] Test that an already confirmed contribution can not be deleted. --- .../resolver/ContributionResolver.test.ts | 44 ++++++++++++++++--- 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index 0fcd0f5af..b584624c2 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -4,6 +4,7 @@ import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { adminUpdateContribution, + confirmContribution, createContribution, deleteContribution, updateContribution, @@ -573,8 +574,8 @@ describe('ContributionResolver', () => { describe('wrong contribution id', () => { it('returns an error', async () => { await expect( - query({ - query: deleteContribution, + mutate({ + mutation: deleteContribution, variables: { id: -1, }, @@ -594,8 +595,8 @@ describe('ContributionResolver', () => { variables: { email: 'peter@lustig.de', password: 'Aa12345_' }, }) await expect( - query({ - query: deleteContribution, + mutate({ + mutation: deleteContribution, variables: { id: result.data.createContribution.id, }, @@ -611,8 +612,8 @@ describe('ContributionResolver', () => { describe('User deletes own contribution', () => { it('deletes successfully', async () => { await expect( - query({ - query: deleteContribution, + mutate({ + mutation: deleteContribution, variables: { id: result.data.createContribution.id, }, @@ -620,6 +621,37 @@ describe('ContributionResolver', () => { ).resolves.toBeTruthy() }) }) + + describe('User deletes already confirmed contribution', () => { + it('throws an error', async () => { + await query({ + query: login, + variables: { email: 'peter@lustig.de', password: 'Aa12345_' }, + }) + await mutate({ + mutation: confirmContribution, + variables: { + id: result.data.createContribution.id, + }, + }) + await query({ + query: login, + variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, + }) + await expect( + mutate({ + mutation: deleteContribution, + variables: { + id: result.data.createContribution.id, + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('A confirmed contribution can not be deleted')], + }), + ) + }) + }) }) }) }) From 1e5738f0aa2fafba945012e88611f0349c28bdb9 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 19 Jul 2022 15:11:27 +0200 Subject: [PATCH 113/114] fix: Windows 0D 0A Linebreaks to Unix 0A --- backend/.env.dist | 120 +++++++-------- backend/src/config/index.ts | 258 ++++++++++++++++---------------- deployment/bare_metal/.env.dist | 166 ++++++++++---------- 3 files changed, 272 insertions(+), 272 deletions(-) diff --git a/backend/.env.dist b/backend/.env.dist index ae89985e3..69b1d6a46 100644 --- a/backend/.env.dist +++ b/backend/.env.dist @@ -1,60 +1,60 @@ -CONFIG_VERSION=v9.2022-07-07 - -# Server -PORT=4000 -JWT_SECRET=secret123 -JWT_EXPIRES_IN=10m -GRAPHIQL=false -GDT_API_URL=https://gdt.gradido.net - -# Database -DB_HOST=localhost -DB_PORT=3306 -DB_USER=root -DB_PASSWORD= -DB_DATABASE=gradido_community -TYPEORM_LOGGING_RELATIVE_PATH=typeorm.backend.log - -# Klicktipp -KLICKTIPP=false -KLICKTTIPP_API_URL=https://api.klicktipp.com -KLICKTIPP_USER=gradido_test -KLICKTIPP_PASSWORD=secret321 -KLICKTIPP_APIKEY_DE=SomeFakeKeyDE -KLICKTIPP_APIKEY_EN=SomeFakeKeyEN - -# Community -COMMUNITY_NAME=Gradido Entwicklung -COMMUNITY_URL=http://localhost/ -COMMUNITY_REGISTER_URL=http://localhost/register -COMMUNITY_REDEEM_URL=http://localhost/redeem/{code} -COMMUNITY_REDEEM_CONTRIBUTION_URL=http://localhost/redeem/CL-{code} -COMMUNITY_DESCRIPTION=Die lokale Entwicklungsumgebung von Gradido. - -# Login Server -LOGIN_APP_SECRET=21ffbbc616fe -LOGIN_SERVER_KEY=a51ef8ac7ef1abf162fb7a65261acd7a - -# EMail -EMAIL=false -EMAIL_USERNAME=gradido_email -EMAIL_SENDER=info@gradido.net -EMAIL_PASSWORD=xxx -EMAIL_SMTP_URL=gmail.com -EMAIL_SMTP_PORT=587 -EMAIL_LINK_VERIFICATION=http://localhost/checkEmail/{optin}{code} -EMAIL_LINK_SETPASSWORD=http://localhost/reset-password/{optin} -EMAIL_LINK_FORGOTPASSWORD=http://localhost/forgot-password -EMAIL_LINK_OVERVIEW=http://localhost/overview -EMAIL_CODE_VALID_TIME=1440 -EMAIL_CODE_REQUEST_TIME=10 - -# Webhook -WEBHOOK_ELOPAGE_SECRET=secret - -# EventProtocol -EVENT_PROTOCOL_DISABLED=false - -# SET LOG LEVEL AS NEEDED IN YOUR .ENV -# POSSIBLE VALUES: all | trace | debug | info | warn | error | fatal -# LOG_LEVEL=info +CONFIG_VERSION=v9.2022-07-07 + +# Server +PORT=4000 +JWT_SECRET=secret123 +JWT_EXPIRES_IN=10m +GRAPHIQL=false +GDT_API_URL=https://gdt.gradido.net + +# Database +DB_HOST=localhost +DB_PORT=3306 +DB_USER=root +DB_PASSWORD= +DB_DATABASE=gradido_community +TYPEORM_LOGGING_RELATIVE_PATH=typeorm.backend.log + +# Klicktipp +KLICKTIPP=false +KLICKTTIPP_API_URL=https://api.klicktipp.com +KLICKTIPP_USER=gradido_test +KLICKTIPP_PASSWORD=secret321 +KLICKTIPP_APIKEY_DE=SomeFakeKeyDE +KLICKTIPP_APIKEY_EN=SomeFakeKeyEN + +# Community +COMMUNITY_NAME=Gradido Entwicklung +COMMUNITY_URL=http://localhost/ +COMMUNITY_REGISTER_URL=http://localhost/register +COMMUNITY_REDEEM_URL=http://localhost/redeem/{code} +COMMUNITY_REDEEM_CONTRIBUTION_URL=http://localhost/redeem/CL-{code} +COMMUNITY_DESCRIPTION=Die lokale Entwicklungsumgebung von Gradido. + +# Login Server +LOGIN_APP_SECRET=21ffbbc616fe +LOGIN_SERVER_KEY=a51ef8ac7ef1abf162fb7a65261acd7a + +# EMail +EMAIL=false +EMAIL_USERNAME=gradido_email +EMAIL_SENDER=info@gradido.net +EMAIL_PASSWORD=xxx +EMAIL_SMTP_URL=gmail.com +EMAIL_SMTP_PORT=587 +EMAIL_LINK_VERIFICATION=http://localhost/checkEmail/{optin}{code} +EMAIL_LINK_SETPASSWORD=http://localhost/reset-password/{optin} +EMAIL_LINK_FORGOTPASSWORD=http://localhost/forgot-password +EMAIL_LINK_OVERVIEW=http://localhost/overview +EMAIL_CODE_VALID_TIME=1440 +EMAIL_CODE_REQUEST_TIME=10 + +# Webhook +WEBHOOK_ELOPAGE_SECRET=secret + +# EventProtocol +EVENT_PROTOCOL_DISABLED=false + +# SET LOG LEVEL AS NEEDED IN YOUR .ENV +# POSSIBLE VALUES: all | trace | debug | info | warn | error | fatal +# LOG_LEVEL=info diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index 2120fce71..313c26149 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -1,129 +1,129 @@ -// ATTENTION: DO NOT PUT ANY SECRETS IN HERE (or the .env) - -import dotenv from 'dotenv' -import Decimal from 'decimal.js-light' -dotenv.config() - -Decimal.set({ - precision: 25, - rounding: Decimal.ROUND_HALF_UP, -}) - -const constants = { - DB_VERSION: '0043-add_event_protocol_table', - DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0 - LOG4JS_CONFIG: 'log4js-config.json', - // default log level on production should be info - LOG_LEVEL: process.env.LOG_LEVEL || 'info', - CONFIG_VERSION: { - DEFAULT: 'DEFAULT', - EXPECTED: 'v9.2022-07-07', - CURRENT: '', - }, -} - -const server = { - PORT: process.env.PORT || 4000, - JWT_SECRET: process.env.JWT_SECRET || 'secret123', - JWT_EXPIRES_IN: process.env.JWT_EXPIRES_IN || '10m', - GRAPHIQL: process.env.GRAPHIQL === 'true' || false, - GDT_API_URL: process.env.GDT_API_URL || 'https://gdt.gradido.net', - PRODUCTION: process.env.NODE_ENV === 'production' || false, -} - -const database = { - DB_HOST: process.env.DB_HOST || 'localhost', - DB_PORT: process.env.DB_PORT ? parseInt(process.env.DB_PORT) : 3306, - DB_USER: process.env.DB_USER || 'root', - DB_PASSWORD: process.env.DB_PASSWORD || '', - DB_DATABASE: process.env.DB_DATABASE || 'gradido_community', - TYPEORM_LOGGING_RELATIVE_PATH: process.env.TYPEORM_LOGGING_RELATIVE_PATH || 'typeorm.backend.log', -} - -const klicktipp = { - KLICKTIPP: process.env.KLICKTIPP === 'true' || false, - KLICKTTIPP_API_URL: process.env.KLICKTIPP_API_URL || 'https://api.klicktipp.com', - KLICKTIPP_USER: process.env.KLICKTIPP_USER || 'gradido_test', - KLICKTIPP_PASSWORD: process.env.KLICKTIPP_PASSWORD || 'secret321', - KLICKTIPP_APIKEY_DE: process.env.KLICKTIPP_APIKEY_DE || 'SomeFakeKeyDE', - KLICKTIPP_APIKEY_EN: process.env.KLICKTIPP_APIKEY_EN || 'SomeFakeKeyEN', -} - -const community = { - COMMUNITY_NAME: process.env.COMMUNITY_NAME || 'Gradido Entwicklung', - COMMUNITY_URL: process.env.COMMUNITY_URL || 'http://localhost/', - COMMUNITY_REGISTER_URL: process.env.COMMUNITY_REGISTER_URL || 'http://localhost/register', - COMMUNITY_REDEEM_URL: process.env.COMMUNITY_REDEEM_URL || 'http://localhost/redeem/{code}', - COMMUNITY_REDEEM_CONTRIBUTION_URL: - process.env.COMMUNITY_REDEEM_CONTRIBUTION_URL || 'http://localhost/redeem/CL-{code}', - COMMUNITY_DESCRIPTION: - process.env.COMMUNITY_DESCRIPTION || 'Die lokale Entwicklungsumgebung von Gradido.', -} - -const loginServer = { - LOGIN_APP_SECRET: process.env.LOGIN_APP_SECRET || '21ffbbc616fe', - LOGIN_SERVER_KEY: process.env.LOGIN_SERVER_KEY || 'a51ef8ac7ef1abf162fb7a65261acd7a', -} - -const email = { - EMAIL: process.env.EMAIL === 'true' || false, - EMAIL_USERNAME: process.env.EMAIL_USERNAME || 'gradido_email', - EMAIL_SENDER: process.env.EMAIL_SENDER || 'info@gradido.net', - EMAIL_PASSWORD: process.env.EMAIL_PASSWORD || 'xxx', - EMAIL_SMTP_URL: process.env.EMAIL_SMTP_URL || 'gmail.com', - EMAIL_SMTP_PORT: process.env.EMAIL_SMTP_PORT || '587', - EMAIL_LINK_VERIFICATION: - process.env.EMAIL_LINK_VERIFICATION || 'http://localhost/checkEmail/{optin}{code}', - EMAIL_LINK_SETPASSWORD: - process.env.EMAIL_LINK_SETPASSWORD || 'http://localhost/reset-password/{optin}', - EMAIL_LINK_FORGOTPASSWORD: - process.env.EMAIL_LINK_FORGOTPASSWORD || 'http://localhost/forgot-password', - EMAIL_LINK_OVERVIEW: process.env.EMAIL_LINK_OVERVIEW || 'http://localhost/overview', - // time in minutes a optin code is valid - EMAIL_CODE_VALID_TIME: process.env.EMAIL_CODE_VALID_TIME - ? parseInt(process.env.EMAIL_CODE_VALID_TIME) || 1440 - : 1440, - // time in minutes that must pass to request a new optin code - EMAIL_CODE_REQUEST_TIME: process.env.EMAIL_CODE_REQUEST_TIME - ? parseInt(process.env.EMAIL_CODE_REQUEST_TIME) || 10 - : 10, -} - -const webhook = { - // Elopage - WEBHOOK_ELOPAGE_SECRET: process.env.WEBHOOK_ELOPAGE_SECRET || 'secret', -} - -const eventProtocol = { - // global switch to enable writing of EventProtocol-Entries - EVENT_PROTOCOL_DISABLED: process.env.EVENT_PROTOCOL_DISABLED === 'true' || false, -} - -// This is needed by graphql-directive-auth -process.env.APP_SECRET = server.JWT_SECRET - -// Check config version -constants.CONFIG_VERSION.CURRENT = process.env.CONFIG_VERSION || constants.CONFIG_VERSION.DEFAULT -if ( - ![constants.CONFIG_VERSION.EXPECTED, constants.CONFIG_VERSION.DEFAULT].includes( - constants.CONFIG_VERSION.CURRENT, - ) -) { - throw new Error( - `Fatal: Config Version incorrect - expected "${constants.CONFIG_VERSION.EXPECTED}" or "${constants.CONFIG_VERSION.DEFAULT}", but found "${constants.CONFIG_VERSION.CURRENT}"`, - ) -} - -const CONFIG = { - ...constants, - ...server, - ...database, - ...klicktipp, - ...community, - ...email, - ...loginServer, - ...webhook, - ...eventProtocol, -} - -export default CONFIG +// ATTENTION: DO NOT PUT ANY SECRETS IN HERE (or the .env) + +import dotenv from 'dotenv' +import Decimal from 'decimal.js-light' +dotenv.config() + +Decimal.set({ + precision: 25, + rounding: Decimal.ROUND_HALF_UP, +}) + +const constants = { + DB_VERSION: '0043-add_event_protocol_table', + DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0 + LOG4JS_CONFIG: 'log4js-config.json', + // default log level on production should be info + LOG_LEVEL: process.env.LOG_LEVEL || 'info', + CONFIG_VERSION: { + DEFAULT: 'DEFAULT', + EXPECTED: 'v9.2022-07-07', + CURRENT: '', + }, +} + +const server = { + PORT: process.env.PORT || 4000, + JWT_SECRET: process.env.JWT_SECRET || 'secret123', + JWT_EXPIRES_IN: process.env.JWT_EXPIRES_IN || '10m', + GRAPHIQL: process.env.GRAPHIQL === 'true' || false, + GDT_API_URL: process.env.GDT_API_URL || 'https://gdt.gradido.net', + PRODUCTION: process.env.NODE_ENV === 'production' || false, +} + +const database = { + DB_HOST: process.env.DB_HOST || 'localhost', + DB_PORT: process.env.DB_PORT ? parseInt(process.env.DB_PORT) : 3306, + DB_USER: process.env.DB_USER || 'root', + DB_PASSWORD: process.env.DB_PASSWORD || '', + DB_DATABASE: process.env.DB_DATABASE || 'gradido_community', + TYPEORM_LOGGING_RELATIVE_PATH: process.env.TYPEORM_LOGGING_RELATIVE_PATH || 'typeorm.backend.log', +} + +const klicktipp = { + KLICKTIPP: process.env.KLICKTIPP === 'true' || false, + KLICKTTIPP_API_URL: process.env.KLICKTIPP_API_URL || 'https://api.klicktipp.com', + KLICKTIPP_USER: process.env.KLICKTIPP_USER || 'gradido_test', + KLICKTIPP_PASSWORD: process.env.KLICKTIPP_PASSWORD || 'secret321', + KLICKTIPP_APIKEY_DE: process.env.KLICKTIPP_APIKEY_DE || 'SomeFakeKeyDE', + KLICKTIPP_APIKEY_EN: process.env.KLICKTIPP_APIKEY_EN || 'SomeFakeKeyEN', +} + +const community = { + COMMUNITY_NAME: process.env.COMMUNITY_NAME || 'Gradido Entwicklung', + COMMUNITY_URL: process.env.COMMUNITY_URL || 'http://localhost/', + COMMUNITY_REGISTER_URL: process.env.COMMUNITY_REGISTER_URL || 'http://localhost/register', + COMMUNITY_REDEEM_URL: process.env.COMMUNITY_REDEEM_URL || 'http://localhost/redeem/{code}', + COMMUNITY_REDEEM_CONTRIBUTION_URL: + process.env.COMMUNITY_REDEEM_CONTRIBUTION_URL || 'http://localhost/redeem/CL-{code}', + COMMUNITY_DESCRIPTION: + process.env.COMMUNITY_DESCRIPTION || 'Die lokale Entwicklungsumgebung von Gradido.', +} + +const loginServer = { + LOGIN_APP_SECRET: process.env.LOGIN_APP_SECRET || '21ffbbc616fe', + LOGIN_SERVER_KEY: process.env.LOGIN_SERVER_KEY || 'a51ef8ac7ef1abf162fb7a65261acd7a', +} + +const email = { + EMAIL: process.env.EMAIL === 'true' || false, + EMAIL_USERNAME: process.env.EMAIL_USERNAME || 'gradido_email', + EMAIL_SENDER: process.env.EMAIL_SENDER || 'info@gradido.net', + EMAIL_PASSWORD: process.env.EMAIL_PASSWORD || 'xxx', + EMAIL_SMTP_URL: process.env.EMAIL_SMTP_URL || 'gmail.com', + EMAIL_SMTP_PORT: process.env.EMAIL_SMTP_PORT || '587', + EMAIL_LINK_VERIFICATION: + process.env.EMAIL_LINK_VERIFICATION || 'http://localhost/checkEmail/{optin}{code}', + EMAIL_LINK_SETPASSWORD: + process.env.EMAIL_LINK_SETPASSWORD || 'http://localhost/reset-password/{optin}', + EMAIL_LINK_FORGOTPASSWORD: + process.env.EMAIL_LINK_FORGOTPASSWORD || 'http://localhost/forgot-password', + EMAIL_LINK_OVERVIEW: process.env.EMAIL_LINK_OVERVIEW || 'http://localhost/overview', + // time in minutes a optin code is valid + EMAIL_CODE_VALID_TIME: process.env.EMAIL_CODE_VALID_TIME + ? parseInt(process.env.EMAIL_CODE_VALID_TIME) || 1440 + : 1440, + // time in minutes that must pass to request a new optin code + EMAIL_CODE_REQUEST_TIME: process.env.EMAIL_CODE_REQUEST_TIME + ? parseInt(process.env.EMAIL_CODE_REQUEST_TIME) || 10 + : 10, +} + +const webhook = { + // Elopage + WEBHOOK_ELOPAGE_SECRET: process.env.WEBHOOK_ELOPAGE_SECRET || 'secret', +} + +const eventProtocol = { + // global switch to enable writing of EventProtocol-Entries + EVENT_PROTOCOL_DISABLED: process.env.EVENT_PROTOCOL_DISABLED === 'true' || false, +} + +// This is needed by graphql-directive-auth +process.env.APP_SECRET = server.JWT_SECRET + +// Check config version +constants.CONFIG_VERSION.CURRENT = process.env.CONFIG_VERSION || constants.CONFIG_VERSION.DEFAULT +if ( + ![constants.CONFIG_VERSION.EXPECTED, constants.CONFIG_VERSION.DEFAULT].includes( + constants.CONFIG_VERSION.CURRENT, + ) +) { + throw new Error( + `Fatal: Config Version incorrect - expected "${constants.CONFIG_VERSION.EXPECTED}" or "${constants.CONFIG_VERSION.DEFAULT}", but found "${constants.CONFIG_VERSION.CURRENT}"`, + ) +} + +const CONFIG = { + ...constants, + ...server, + ...database, + ...klicktipp, + ...community, + ...email, + ...loginServer, + ...webhook, + ...eventProtocol, +} + +export default CONFIG diff --git a/deployment/bare_metal/.env.dist b/deployment/bare_metal/.env.dist index d53ffebbe..1255104c9 100644 --- a/deployment/bare_metal/.env.dist +++ b/deployment/bare_metal/.env.dist @@ -1,84 +1,84 @@ -GRADIDO_LOG_PATH=/home/gradido/gradido/deployment/bare_metal/log - -# start script -DEPLOY_SEED_DATA=false - -# nginx -NGINX_REWRITE_LEGACY_URLS=true -NGINX_SSL=true -NGINX_SERVER_NAME=stage1.gradido.net -NGINX_SSL_CERTIFICATE=/etc/letsencrypt/live/stage1.gradido.net/fullchain.pem -NGINX_SSL_CERTIFICATE_KEY=/etc/letsencrypt/live/stage1.gradido.net/privkey.pem -NGINX_SSL_DHPARAM=/etc/letsencrypt/ssl-dhparams.pem -NGINX_SSL_INCLUDE=/etc/letsencrypt/options-ssl-nginx.conf -NGINX_UPDATE_PAGE_ROOT=/home/gradido/gradido/deployment/bare_metal/nginx/update-page - -# webhook -WEBHOOK_GITHUB_SECRET=secret -WEBHOOK_GITHUB_BRANCH=master - -# community -COMMUNITY_NAME="Gradido Development Stage1" -COMMUNITY_URL=https://stage1.gradido.net/ -COMMUNITY_REGISTER_URL=https://stage1.gradido.net/register -COMMUNITY_REDEEM_URL=https://stage1.gradido.net/redeem/{code} -COMMUNITY_REDEEM_CONTRIBUTION_URL=https://stage1.gradido.net/redeem/CL-{code} -COMMUNITY_DESCRIPTION="Gradido Development Stage1 Test Community" - -# backend -BACKEND_CONFIG_VERSION=v9.2022-07-07 - -JWT_EXPIRES_IN=10m -GDT_API_URL=https://gdt.gradido.net - -TYPEORM_LOGGING_RELATIVE_PATH=../deployment/bare_metal/log/typeorm.backend.log - -KLICKTIPP=false -KLICKTIPP_USER= -KLICKTIPP_PASSWORD= -KLICKTIPP_APIKEY_DE= -KLICKTIPP_APIKEY_EN= - -EMAIL=true -EMAIL_USERNAME=peter@lustig.de -EMAIL_SENDER=peter@lustig.de -EMAIL_PASSWORD=1234 -EMAIL_SMTP_URL=smtp.lustig.de -EMAIL_LINK_VERIFICATION=https://stage1.gradido.net/checkEmail/{optin}{code} -EMAIL_LINK_SETPASSWORD=https://stage1.gradido.net/reset-password/{optin} -EMAIL_LINK_FORGOTPASSWORD=https://stage1.gradido.net/forgot-password -EMAIL_LINK_OVERVIEW=https://stage1.gradido.net/overview -EMAIL_CODE_VALID_TIME=1440 -EMAIL_CODE_REQUEST_TIME=10 - -WEBHOOK_ELOPAGE_SECRET=secret - -# EventProtocol -EVENT_PROTOCOL_DISABLED=false - - -# database -DATABASE_CONFIG_VERSION=v1.2022-03-18 - -# frontend -FRONTEND_CONFIG_VERSION=v2.2022-04-07 - -GRAPHQL_URI=https://stage1.gradido.net/graphql -ADMIN_AUTH_URL=https://stage1.gradido.net/admin/authenticate?token={token} - -DEFAULT_PUBLISHER_ID=2896 - -META_URL=http://localhost -META_TITLE_DE="Gradido – Dein Dankbarkeitskonto" -META_TITLE_EN="Gradido - Your gratitude account" -META_DESCRIPTION_DE="Dankbarkeit ist die Währung der neuen Zeit. Immer mehr Menschen entfalten ihr Potenzial und gestalten eine gute Zukunft für alle." -META_DESCRIPTION_EN="Gratitude is the currency of the new age. More and more people are unleashing their potential and shaping a good future for all." -META_KEYWORDS_DE="Grundeinkommen, Währung, Dankbarkeit, Schenk-Ökonomie, Natürliche Ökonomie des Lebens, Ökonomie, Ökologie, Potenzialentfaltung, Schenken und Danken, Kreislauf des Lebens, Geldsystem" -META_KEYWORDS_EN="Basic Income, Currency, Gratitude, Gift Economy, Natural Economy of Life, Economy, Ecology, Potential Development, Giving and Thanking, Cycle of Life, Monetary System" -META_AUTHOR="Bernd Hückstädt - Gradido-Akademie" - -# admin -ADMIN_CONFIG_VERSION=v1.2022-03-18 - -WALLET_AUTH_URL=https://stage1.gradido.net/authenticate?token={token} +GRADIDO_LOG_PATH=/home/gradido/gradido/deployment/bare_metal/log + +# start script +DEPLOY_SEED_DATA=false + +# nginx +NGINX_REWRITE_LEGACY_URLS=true +NGINX_SSL=true +NGINX_SERVER_NAME=stage1.gradido.net +NGINX_SSL_CERTIFICATE=/etc/letsencrypt/live/stage1.gradido.net/fullchain.pem +NGINX_SSL_CERTIFICATE_KEY=/etc/letsencrypt/live/stage1.gradido.net/privkey.pem +NGINX_SSL_DHPARAM=/etc/letsencrypt/ssl-dhparams.pem +NGINX_SSL_INCLUDE=/etc/letsencrypt/options-ssl-nginx.conf +NGINX_UPDATE_PAGE_ROOT=/home/gradido/gradido/deployment/bare_metal/nginx/update-page + +# webhook +WEBHOOK_GITHUB_SECRET=secret +WEBHOOK_GITHUB_BRANCH=master + +# community +COMMUNITY_NAME="Gradido Development Stage1" +COMMUNITY_URL=https://stage1.gradido.net/ +COMMUNITY_REGISTER_URL=https://stage1.gradido.net/register +COMMUNITY_REDEEM_URL=https://stage1.gradido.net/redeem/{code} +COMMUNITY_REDEEM_CONTRIBUTION_URL=https://stage1.gradido.net/redeem/CL-{code} +COMMUNITY_DESCRIPTION="Gradido Development Stage1 Test Community" + +# backend +BACKEND_CONFIG_VERSION=v9.2022-07-07 + +JWT_EXPIRES_IN=10m +GDT_API_URL=https://gdt.gradido.net + +TYPEORM_LOGGING_RELATIVE_PATH=../deployment/bare_metal/log/typeorm.backend.log + +KLICKTIPP=false +KLICKTIPP_USER= +KLICKTIPP_PASSWORD= +KLICKTIPP_APIKEY_DE= +KLICKTIPP_APIKEY_EN= + +EMAIL=true +EMAIL_USERNAME=peter@lustig.de +EMAIL_SENDER=peter@lustig.de +EMAIL_PASSWORD=1234 +EMAIL_SMTP_URL=smtp.lustig.de +EMAIL_LINK_VERIFICATION=https://stage1.gradido.net/checkEmail/{optin}{code} +EMAIL_LINK_SETPASSWORD=https://stage1.gradido.net/reset-password/{optin} +EMAIL_LINK_FORGOTPASSWORD=https://stage1.gradido.net/forgot-password +EMAIL_LINK_OVERVIEW=https://stage1.gradido.net/overview +EMAIL_CODE_VALID_TIME=1440 +EMAIL_CODE_REQUEST_TIME=10 + +WEBHOOK_ELOPAGE_SECRET=secret + +# EventProtocol +EVENT_PROTOCOL_DISABLED=false + + +# database +DATABASE_CONFIG_VERSION=v1.2022-03-18 + +# frontend +FRONTEND_CONFIG_VERSION=v2.2022-04-07 + +GRAPHQL_URI=https://stage1.gradido.net/graphql +ADMIN_AUTH_URL=https://stage1.gradido.net/admin/authenticate?token={token} + +DEFAULT_PUBLISHER_ID=2896 + +META_URL=http://localhost +META_TITLE_DE="Gradido – Dein Dankbarkeitskonto" +META_TITLE_EN="Gradido - Your gratitude account" +META_DESCRIPTION_DE="Dankbarkeit ist die Währung der neuen Zeit. Immer mehr Menschen entfalten ihr Potenzial und gestalten eine gute Zukunft für alle." +META_DESCRIPTION_EN="Gratitude is the currency of the new age. More and more people are unleashing their potential and shaping a good future for all." +META_KEYWORDS_DE="Grundeinkommen, Währung, Dankbarkeit, Schenk-Ökonomie, Natürliche Ökonomie des Lebens, Ökonomie, Ökologie, Potenzialentfaltung, Schenken und Danken, Kreislauf des Lebens, Geldsystem" +META_KEYWORDS_EN="Basic Income, Currency, Gratitude, Gift Economy, Natural Economy of Life, Economy, Ecology, Potential Development, Giving and Thanking, Cycle of Life, Monetary System" +META_AUTHOR="Bernd Hückstädt - Gradido-Akademie" + +# admin +ADMIN_CONFIG_VERSION=v1.2022-03-18 + +WALLET_AUTH_URL=https://stage1.gradido.net/authenticate?token={token} WALLET_URL=https://stage1.gradido.net/login \ No newline at end of file From c8267cf77415fd48c5f9b79d3d890e09c5c4d5ab Mon Sep 17 00:00:00 2001 From: elweyn Date: Wed, 20 Jul 2022 10:42:24 +0200 Subject: [PATCH 114/114] Add contributionDate to the Contribution object. --- backend/src/graphql/model/Contribution.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/backend/src/graphql/model/Contribution.ts b/backend/src/graphql/model/Contribution.ts index 13c2d40d7..aa878990c 100644 --- a/backend/src/graphql/model/Contribution.ts +++ b/backend/src/graphql/model/Contribution.ts @@ -15,6 +15,7 @@ export class Contribution { this.deletedAt = contribution.deletedAt this.confirmedAt = contribution.confirmedAt this.confirmedBy = contribution.confirmedBy + this.contributionDate = contribution.contributionDate } @Field(() => Number) @@ -43,6 +44,9 @@ export class Contribution { @Field(() => Number, { nullable: true }) confirmedBy: number | null + + @Field(() => Date) + contributionDate: Date } @ObjectType()