From b63513e68ad1b9e49284c794d95e40c79b6e2612 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Fri, 24 Mar 2023 00:47:30 +0100 Subject: [PATCH 01/34] first draft of db-modell --- .../TechnicalRequirements/Federation.md | 4 ++++ ...ramm_communities-communities_federation.png | Bin 0 -> 115492 bytes 2 files changed, 4 insertions(+) create mode 100644 docu/Concepts/TechnicalRequirements/image/classdiagramm_communities-communities_federation.png diff --git a/docu/Concepts/TechnicalRequirements/Federation.md b/docu/Concepts/TechnicalRequirements/Federation.md index 8bbd74a3e..b559da115 100644 --- a/docu/Concepts/TechnicalRequirements/Federation.md +++ b/docu/Concepts/TechnicalRequirements/Federation.md @@ -50,6 +50,10 @@ Before starting in describing the details of the federation handshake, some prer With the federation additional data tables/entities have to be created. +The following diagramm shows the first draft of a possible database-model base on the migration 0063-event_link_fields.ts + +![img](./image/classdiagramm_communities-communities_federation.png) + ##### Community-Entity Create the new *Community* table to store attributes of the own community. This table is used more like a frame for own community data in the future like the list of federated foreign communities, own users, own futher accounts like AUF- and Welfare-account and the profile data of the own community: diff --git a/docu/Concepts/TechnicalRequirements/image/classdiagramm_communities-communities_federation.png b/docu/Concepts/TechnicalRequirements/image/classdiagramm_communities-communities_federation.png new file mode 100644 index 0000000000000000000000000000000000000000..a794f9e7529c94d10274dba5573dff661cde9218 GIT binary patch literal 115492 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 Date: Fri, 24 Mar 2023 08:52:27 +0100 Subject: [PATCH 02/34] feat(backend): add event for subscribe&unsubscribe --- backend/src/event/EventType.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backend/src/event/EventType.ts b/backend/src/event/EventType.ts index b219a49ba..7b1fc2dc9 100644 --- a/backend/src/event/EventType.ts +++ b/backend/src/event/EventType.ts @@ -18,8 +18,10 @@ export enum EventType { REDEEM_REGISTER = 'REDEEM_REGISTER', SEND_ACCOUNT_MULTIREGISTRATION_EMAIL = 'SEND_ACCOUNT_MULTIREGISTRATION_EMAIL', SEND_CONFIRMATION_EMAIL = 'SEND_CONFIRMATION_EMAIL', + SUBSCRIBE_NEWSLETTER = 'SUBSCRIBE_NEWSLETTER', TRANSACTION_SEND = 'TRANSACTION_SEND', TRANSACTION_RECEIVE = 'TRANSACTION_RECEIVE', + UNSUBSCRIBE_NEWSLETTER = 'UNSUBSCRIBE_NEWSLETTER', // VISIT_GRADIDO = 'VISIT_GRADIDO', // VERIFY_REDEEM = 'VERIFY_REDEEM', // INACTIVE_ACCOUNT = 'INACTIVE_ACCOUNT', From 7e838389a73a7a2726c238dbfc9d1ef5c8dcf51f Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 24 Mar 2023 08:56:33 +0100 Subject: [PATCH 03/34] Event for subscribe newsletter --- backend/src/event/EVENT_SUBSCRIBE_NEWSLETTER.ts | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 backend/src/event/EVENT_SUBSCRIBE_NEWSLETTER.ts diff --git a/backend/src/event/EVENT_SUBSCRIBE_NEWSLETTER.ts b/backend/src/event/EVENT_SUBSCRIBE_NEWSLETTER.ts new file mode 100644 index 000000000..f4207d059 --- /dev/null +++ b/backend/src/event/EVENT_SUBSCRIBE_NEWSLETTER.ts @@ -0,0 +1,6 @@ +import { User as DbUser } from '@entity/User' +import { Event as DbEvent } from '@entity/Event' +import { Event, EventType } from './Event' + +export const EVENT_SUBSCRIBE_NEWSLETTER = async (user: DbUser): Promise => + Event(EventType.SUBSCRIBE_NEWSLETTER, user, user).save() From f8549ba208c3257fe7ecb19bd26d01ebc956f8f4 Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 24 Mar 2023 08:56:53 +0100 Subject: [PATCH 04/34] Event for unsubscribe newsletter --- backend/src/event/EVENT_UNSUBSCRIBE_NEWSLETTER.ts | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 backend/src/event/EVENT_UNSUBSCRIBE_NEWSLETTER.ts diff --git a/backend/src/event/EVENT_UNSUBSCRIBE_NEWSLETTER.ts b/backend/src/event/EVENT_UNSUBSCRIBE_NEWSLETTER.ts new file mode 100644 index 000000000..6a6946e3f --- /dev/null +++ b/backend/src/event/EVENT_UNSUBSCRIBE_NEWSLETTER.ts @@ -0,0 +1,6 @@ +import { User as DbUser } from '@entity/User' +import { Event as DbEvent } from '@entity/Event' +import { Event, EventType } from './Event' + +export const EVENT_UNSUBSCRIBE_NEWSLETTER = async (user: DbUser): Promise => + Event(EventType.UNSUBSCRIBE_NEWSLETTER, user, user).save() From 04e6d7abeb6e3f56b741e72dfcc405664aad49b4 Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 24 Mar 2023 08:58:02 +0100 Subject: [PATCH 05/34] Add new defined events to Event --- backend/src/event/Event.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/backend/src/event/Event.ts b/backend/src/event/Event.ts index 2e7cca6af..4d6f47674 100644 --- a/backend/src/event/Event.ts +++ b/backend/src/event/Event.ts @@ -53,5 +53,7 @@ export { EVENT_LOGIN } from './EVENT_LOGIN' export { EVENT_REGISTER } from './EVENT_REGISTER' export { EVENT_SEND_ACCOUNT_MULTIREGISTRATION_EMAIL } from './EVENT_SEND_ACCOUNT_MULTIREGISTRATION_EMAIL' export { EVENT_SEND_CONFIRMATION_EMAIL } from './EVENT_SEND_CONFIRMATION_EMAIL' +export { EVENT_SUBSCRIBE_NEWSLETTER } from './EVENT_SUBSCRIBE_NEWSLETTER' export { EVENT_TRANSACTION_SEND } from './EVENT_TRANSACTION_SEND' export { EVENT_TRANSACTION_RECEIVE } from './EVENT_TRANSACTION_RECEIVE' +export { EVENT_UNSUBSCRIBE_NEWSLETTER } from './EVENT_UNSUBSCRIBE_NEWSLETTER' From 1945570146609c4e41c77db8d0fbbadd97db2cb4 Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 24 Mar 2023 08:58:32 +0100 Subject: [PATCH 06/34] Call new Events --- backend/src/graphql/resolver/KlicktippResolver.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/backend/src/graphql/resolver/KlicktippResolver.ts b/backend/src/graphql/resolver/KlicktippResolver.ts index 661aeb4a6..10be59363 100644 --- a/backend/src/graphql/resolver/KlicktippResolver.ts +++ b/backend/src/graphql/resolver/KlicktippResolver.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-return */ import { Resolver, Query, Authorized, Arg, Mutation, Ctx } from 'type-graphql' @@ -7,6 +8,7 @@ import { unsubscribe, klicktippSignIn, } from '@/apis/KlicktippController' +import { EVENT_UNSUBSCRIBE_NEWSLETTER, EVENT_SUBSCRIBE_NEWSLETTER } from '@/event/Event' import { RIGHTS } from '@/auth/RIGHTS' import { Context, getUser } from '@/server/context' @@ -28,6 +30,7 @@ export class KlicktippResolver { @Mutation(() => Boolean) async unsubscribeNewsletter(@Ctx() context: Context): Promise { const user = getUser(context) + await EVENT_UNSUBSCRIBE_NEWSLETTER(user) return await unsubscribe(user.emailContact.email) } @@ -38,6 +41,7 @@ export class KlicktippResolver { @Ctx() context: Context, ): Promise { const user = getUser(context) + await EVENT_SUBSCRIBE_NEWSLETTER(user) return await klicktippSignIn(user.emailContact.email, language) } } From 595503b9707a59ac6833f8aaa85b34b2428f9308 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Fri, 24 Mar 2023 17:26:13 +0100 Subject: [PATCH 07/34] divide the database migration in three steps --- .../TechnicalRequirements/Federation.md | 19 ++++++++- ...classdiagramm_x-community-readyness.drawio | 40 +++++++++++++++++++ ...ssdiagramm_x-community-readyness_step1.svg | 1 + ...ssdiagramm_x-community-readyness_step2.svg | 1 + ...ssdiagramm_x-community-readyness_step3.svg | 1 + 5 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 docu/Concepts/TechnicalRequirements/graphics/classdiagramm_x-community-readyness.drawio create mode 100644 docu/Concepts/TechnicalRequirements/image/classdiagramm_x-community-readyness_step1.svg create mode 100644 docu/Concepts/TechnicalRequirements/image/classdiagramm_x-community-readyness_step2.svg create mode 100644 docu/Concepts/TechnicalRequirements/image/classdiagramm_x-community-readyness_step3.svg diff --git a/docu/Concepts/TechnicalRequirements/Federation.md b/docu/Concepts/TechnicalRequirements/Federation.md index b559da115..95b37c7a1 100644 --- a/docu/Concepts/TechnicalRequirements/Federation.md +++ b/docu/Concepts/TechnicalRequirements/Federation.md @@ -50,7 +50,24 @@ Before starting in describing the details of the federation handshake, some prer With the federation additional data tables/entities have to be created. -The following diagramm shows the first draft of a possible database-model base on the migration 0063-event_link_fields.ts +The following diagramms shows the first draft of the possible database-model base on the migration 0063-event_link_fields.ts with 3 steps of migration to reach the required entities. All three diagramms are not exhaustive and are still a base for discussions: + +![img](./image/classdiagramm_x-community-readyness_step1.svg) + +In the first step the current communities table will be renamed to communities_federation. A new table communities is created. Because of the dynamic in the communities_federation data during dht-federation the relation between both entities will be on the collumn communities.communities_federation_public_key. This relation will allow to read a community-entry including its relation to the multi federation entries per api-version with the public key as identifier. + + +![img](./image/classdiagramm_x-community-readyness_step2.svg) + +The 2nd step is an introduction of the entity accounts between the users and the transactions table. This will cause a separation of the transactions from the users, to avoid possible conflicts or dependencies between local users of the community and remote users of foreign users, who will be part of x-communitiy-transactions. + + +![img](./image/classdiagramm_x-community-readyness_step3.svg) + +The 3rd step will introduce an additional foreign-users and a users_favorites table. A foreign_user could be stored in the existing users-table, but he will not need all the attributes of a home-user, especially he will never gets an AGE-account in this community. The user_favorites entity is designed to buildup the relations between users and foreign_users or in general between all users. This is simply a first idea for a future discussion. + + + ![img](./image/classdiagramm_communities-communities_federation.png) diff --git a/docu/Concepts/TechnicalRequirements/graphics/classdiagramm_x-community-readyness.drawio b/docu/Concepts/TechnicalRequirements/graphics/classdiagramm_x-community-readyness.drawio new file mode 100644 index 000000000..bb6f896c0 --- /dev/null +++ b/docu/Concepts/TechnicalRequirements/graphics/classdiagramm_x-community-readyness.drawio @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docu/Concepts/TechnicalRequirements/image/classdiagramm_x-community-readyness_step1.svg b/docu/Concepts/TechnicalRequirements/image/classdiagramm_x-community-readyness_step1.svg new file mode 100644 index 000000000..28bf0d314 --- /dev/null +++ b/docu/Concepts/TechnicalRequirements/image/classdiagramm_x-community-readyness_step1.svg @@ -0,0 +1 @@ +
X-Community-Readyness
Step 1
X-Community-Read...
Text is not SVG - cannot display
\ No newline at end of file diff --git a/docu/Concepts/TechnicalRequirements/image/classdiagramm_x-community-readyness_step2.svg b/docu/Concepts/TechnicalRequirements/image/classdiagramm_x-community-readyness_step2.svg new file mode 100644 index 000000000..41300d046 --- /dev/null +++ b/docu/Concepts/TechnicalRequirements/image/classdiagramm_x-community-readyness_step2.svg @@ -0,0 +1 @@ +
X-Community-Readyness
Step 2
X-Community-Read...
Text is not SVG - cannot display
\ No newline at end of file diff --git a/docu/Concepts/TechnicalRequirements/image/classdiagramm_x-community-readyness_step3.svg b/docu/Concepts/TechnicalRequirements/image/classdiagramm_x-community-readyness_step3.svg new file mode 100644 index 000000000..382c9d728 --- /dev/null +++ b/docu/Concepts/TechnicalRequirements/image/classdiagramm_x-community-readyness_step3.svg @@ -0,0 +1 @@ +
X-Community-Readyness
Step 3
X-Community-Read...
Text is not SVG - cannot display
\ No newline at end of file From bf9831a03f4cb08bb1d7712a47cd36dc799a61c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Tue, 28 Mar 2023 23:11:53 +0200 Subject: [PATCH 08/34] second vision draft of db-migration --- .../TechnicalRequirements/Federation.md | 18 +++++++-- ...classdiagramm_x-community-readyness.drawio | 36 +++++++++--------- .../image/class-diagramm_vision-draft2.png | Bin 0 -> 79299 bytes .../image/class-diagramm_vision-draft2.svg | 1 + 4 files changed, 34 insertions(+), 21 deletions(-) create mode 100644 docu/Concepts/TechnicalRequirements/image/class-diagramm_vision-draft2.png create mode 100644 docu/Concepts/TechnicalRequirements/image/class-diagramm_vision-draft2.svg diff --git a/docu/Concepts/TechnicalRequirements/Federation.md b/docu/Concepts/TechnicalRequirements/Federation.md index 95b37c7a1..2ab4272f2 100644 --- a/docu/Concepts/TechnicalRequirements/Federation.md +++ b/docu/Concepts/TechnicalRequirements/Federation.md @@ -56,20 +56,32 @@ The following diagramms shows the first draft of the possible database-model bas In the first step the current communities table will be renamed to communities_federation. A new table communities is created. Because of the dynamic in the communities_federation data during dht-federation the relation between both entities will be on the collumn communities.communities_federation_public_key. This relation will allow to read a community-entry including its relation to the multi federation entries per api-version with the public key as identifier. - ![img](./image/classdiagramm_x-community-readyness_step2.svg) The 2nd step is an introduction of the entity accounts between the users and the transactions table. This will cause a separation of the transactions from the users, to avoid possible conflicts or dependencies between local users of the community and remote users of foreign users, who will be part of x-communitiy-transactions. - ![img](./image/classdiagramm_x-community-readyness_step3.svg) The 3rd step will introduce an additional foreign-users and a users_favorites table. A foreign_user could be stored in the existing users-table, but he will not need all the attributes of a home-user, especially he will never gets an AGE-account in this community. The user_favorites entity is designed to buildup the relations between users and foreign_users or in general between all users. This is simply a first idea for a future discussion. +After team discussion in architecture meeting a second vision draft for database migration is shown in the following picture. Only the concerned tables of the database migration are presented. The three elliptical surroundings shows the different steps, which should be done in separate issues. The model, table namings and columns are not exhaustive and are still a base for further discussions. + + +![img](./image/class-diagramm_vision-draft2.svg) + +**The first step** with renaming the current `communities` table in `communities_federation` and creating a new `communities` table is not changed. More details about motivation and arguments are described above. + +**The second step** is changed to migrate the `users `table by creating a new `users_settings` table and shift the most existing attributes from `users `table to it. The criterium for shifting a column to `user_settings` is to keep only those columns in the `users `table, which will be used for "home-users" and "foreign-users". A foreign-user at this point of time is a user of an other community, who is involved in a x-community-transaction as `linked_user`. He will not have the possibility to login to the home-community, because after a x-community-tx only the attributes of the `users `table will be exchanged during the handshake of transaction processing of both communities. Even the `transactions `table will be ready for x-community-tx with this `users `and `user_settings` migration, because it contains a reference to both participants of the transaction. For easier displaying and because of historical reasons it will be a good idea to add the columns `linked_user `and `user `(not shown in diagramm) to the `transactions `table with type varchar(512) to store the valid firstname and lastname of the participants at transaction-date. If one of the participants will change his names, there will be no migration of the transaction data necessary and a transaction-list will present always the currect names even over a long distance. + +**The third step** contains a migration for handling accounts and user_correlations. With the new table `gdd_accounts `a new entity will be introduced to support the different types of gradido accounts AGE, GMW and AUF. The second new table `user_correlations `is to buildup the different correlations a user will have: + +* user to user correlation like favorites, trustee, etc +* user to account correlation for cashier of a GMW and AUF community account, trustee of children or seniors, etc. + +The previous idea to replace the `user_id `with an `account_id` in the `transactions `table will be not necessary with this draft, because it will not cause a benefit and saves a lot refactoring efforts. -![img](./image/classdiagramm_communities-communities_federation.png) ##### Community-Entity diff --git a/docu/Concepts/TechnicalRequirements/graphics/classdiagramm_x-community-readyness.drawio b/docu/Concepts/TechnicalRequirements/graphics/classdiagramm_x-community-readyness.drawio index bb6f896c0..becba0b1f 100644 --- a/docu/Concepts/TechnicalRequirements/graphics/classdiagramm_x-community-readyness.drawio +++ b/docu/Concepts/TechnicalRequirements/graphics/classdiagramm_x-community-readyness.drawio @@ -1,38 +1,38 @@ - + - - + + - + - - + + - - + + - + - - + + - - + + - + - - + + - - + + diff --git a/docu/Concepts/TechnicalRequirements/image/class-diagramm_vision-draft2.png b/docu/Concepts/TechnicalRequirements/image/class-diagramm_vision-draft2.png new file mode 100644 index 0000000000000000000000000000000000000000..cd12f1fdde53a69444d34960a6ef8a1cb3ca4c27 GIT binary patch literal 79299 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
X-Community-Readyness
Step 3
X-Community-Read...
X-Community-Readyness
Step 1
X-Community-Read...
X-Community-Readyness
Step 2
X-Community-Read...
Text is not SVG - cannot display \ No newline at end of file From b2f0bf37d2d80e0d714fd97451a1621621d6ca1f Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 30 Mar 2023 16:28:18 +0200 Subject: [PATCH 09/34] Refactor klicktippcontroller to not call function --- backend/src/apis/KlicktippController.ts | 27 +++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/backend/src/apis/KlicktippController.ts b/backend/src/apis/KlicktippController.ts index a291bb945..3646b174d 100644 --- a/backend/src/apis/KlicktippController.ts +++ b/backend/src/apis/KlicktippController.ts @@ -15,6 +15,9 @@ export const klicktippSignIn = async ( firstName?: string, lastName?: string, ): Promise => { + if (!CONFIG.KLICKTIPP) { + return true + } const fields = { fieldFirstName: firstName, fieldLastName: lastName, @@ -25,12 +28,18 @@ export const klicktippSignIn = async ( } export const signout = async (email: string, language: string): Promise => { + if (!CONFIG.KLICKTIPP) { + return true + } const apiKey = language === 'de' ? CONFIG.KLICKTIPP_APIKEY_DE : CONFIG.KLICKTIPP_APIKEY_EN const result = await klicktippConnector.signoff(apiKey, email) return result } export const unsubscribe = async (email: string): Promise => { + if (!CONFIG.KLICKTIPP) { + return true + } const isLogin = await loginKlicktippUser() if (isLogin) { return await klicktippConnector.unsubscribe(email) @@ -39,6 +48,9 @@ export const unsubscribe = async (email: string): Promise => { } export const getKlickTippUser = async (email: string): Promise => { + if (!CONFIG.KLICKTIPP) { + return true + } const isLogin = await loginKlicktippUser() if (isLogin) { const subscriberId = await klicktippConnector.subscriberSearch(email) @@ -49,14 +61,23 @@ export const getKlickTippUser = async (email: string): Promise => { } export const loginKlicktippUser = async (): Promise => { + if (!CONFIG.KLICKTIPP) { + return true + } return await klicktippConnector.login(CONFIG.KLICKTIPP_USER, CONFIG.KLICKTIPP_PASSWORD) } export const logoutKlicktippUser = async (): Promise => { + if (!CONFIG.KLICKTIPP) { + return true + } return await klicktippConnector.logout() } export const untagUser = async (email: string, tagId: string): Promise => { + if (!CONFIG.KLICKTIPP) { + return true + } const isLogin = await loginKlicktippUser() if (isLogin) { return await klicktippConnector.untag(email, tagId) @@ -65,6 +86,9 @@ export const untagUser = async (email: string, tagId: string): Promise } export const tagUser = async (email: string, tagIds: string): Promise => { + if (!CONFIG.KLICKTIPP) { + return true + } const isLogin = await loginKlicktippUser() if (isLogin) { return await klicktippConnector.tag(email, tagIds) @@ -73,6 +97,9 @@ export const tagUser = async (email: string, tagIds: string): Promise = } export const getKlicktippTagMap = async () => { + if (!CONFIG.KLICKTIPP) { + return '' + } const isLogin = await loginKlicktippUser() if (isLogin) { return await klicktippConnector.tagIndex() From ada9f9a056d15bcbfa99b0adcffd60954c647754 Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 30 Mar 2023 16:28:38 +0200 Subject: [PATCH 10/34] Remove not used function rights. --- backend/src/auth/RIGHTS.ts | 2 -- backend/src/auth/ROLES.ts | 2 -- 2 files changed, 4 deletions(-) diff --git a/backend/src/auth/RIGHTS.ts b/backend/src/auth/RIGHTS.ts index f643295de..e373a1097 100644 --- a/backend/src/auth/RIGHTS.ts +++ b/backend/src/auth/RIGHTS.ts @@ -5,8 +5,6 @@ export enum RIGHTS { COMMUNITIES = 'COMMUNITIES', LIST_GDT_ENTRIES = 'LIST_GDT_ENTRIES', EXIST_PID = 'EXIST_PID', - GET_KLICKTIPP_USER = 'GET_KLICKTIPP_USER', - GET_KLICKTIPP_TAG_MAP = 'GET_KLICKTIPP_TAG_MAP', UNSUBSCRIBE_NEWSLETTER = 'UNSUBSCRIBE_NEWSLETTER', SUBSCRIBE_NEWSLETTER = 'SUBSCRIBE_NEWSLETTER', TRANSACTION_LIST = 'TRANSACTION_LIST', diff --git a/backend/src/auth/ROLES.ts b/backend/src/auth/ROLES.ts index 2f3b4e081..d576385e1 100644 --- a/backend/src/auth/ROLES.ts +++ b/backend/src/auth/ROLES.ts @@ -9,8 +9,6 @@ export const ROLE_USER = new Role('user', [ RIGHTS.BALANCE, RIGHTS.LIST_GDT_ENTRIES, RIGHTS.EXIST_PID, - RIGHTS.GET_KLICKTIPP_USER, - RIGHTS.GET_KLICKTIPP_TAG_MAP, RIGHTS.UNSUBSCRIBE_NEWSLETTER, RIGHTS.SUBSCRIBE_NEWSLETTER, RIGHTS.TRANSACTION_LIST, From 04c6756ef473ba978b838d2bbe826589ea4f8c77 Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 30 Mar 2023 16:29:05 +0200 Subject: [PATCH 11/34] Remove check on CONFIG.KLICKTIPP --- backend/src/middleware/klicktippMiddleware.ts | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/backend/src/middleware/klicktippMiddleware.ts b/backend/src/middleware/klicktippMiddleware.ts index 0469b4ccc..bc11f6ad7 100644 --- a/backend/src/middleware/klicktippMiddleware.ts +++ b/backend/src/middleware/klicktippMiddleware.ts @@ -3,9 +3,8 @@ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/restrict-template-expressions */ import { MiddlewareFn } from 'type-graphql' -import { /* klicktippSignIn, */ getKlickTippUser } from '@/apis/KlicktippController' +import { getKlickTippUser } from '@/apis/KlicktippController' import { KlickTipp } from '@model/KlickTipp' -import CONFIG from '@/config' import { klickTippLogger as logger } from '@/server/logger' // export const klicktippRegistrationMiddleware: MiddlewareFn = async ( @@ -28,15 +27,13 @@ export const klicktippNewsletterStateMiddleware: MiddlewareFn = async ( ) => { const result = await next() let klickTipp = new KlickTipp({ status: 'Unsubscribed' }) - if (CONFIG.KLICKTIPP) { - try { - const klickTippUser = await getKlickTippUser(result.email) - if (klickTippUser) { - klickTipp = new KlickTipp(klickTippUser) - } - } catch (err) { - logger.error(`There is no user for (email='${result.email}') ${err}`) + try { + const klickTippUser = await getKlickTippUser(result.email) + if (klickTippUser) { + klickTipp = new KlickTipp(klickTippUser) } + } catch (err) { + logger.error(`There is no user for (email='${result.email}') ${err}`) } result.klickTipp = klickTipp return result From ff7a73048cc84882aea31c85f42b28efa5c7cd8c Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 30 Mar 2023 16:29:35 +0200 Subject: [PATCH 12/34] Correct mutations in testing --- backend/src/seeds/graphql/mutations.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/src/seeds/graphql/mutations.ts b/backend/src/seeds/graphql/mutations.ts index 1aa12a32f..1523f9621 100644 --- a/backend/src/seeds/graphql/mutations.ts +++ b/backend/src/seeds/graphql/mutations.ts @@ -1,14 +1,14 @@ import gql from 'graphql-tag' export const subscribeNewsletter = gql` - mutation ($email: String!, $language: String!) { - subscribeNewsletter(email: $email, language: $language) + mutation { + subscribeNewsletter } ` export const unsubscribeNewsletter = gql` - mutation ($email: String!) { - unsubscribeNewsletter(email: $email) + mutation { + unsubscribeNewsletter } ` From e1c6764978c010f7cd58a4de807c22c5178464c6 Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 30 Mar 2023 16:30:11 +0200 Subject: [PATCH 13/34] Remove unused queries --- .../src/graphql/resolver/KlicktippResolver.ts | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/backend/src/graphql/resolver/KlicktippResolver.ts b/backend/src/graphql/resolver/KlicktippResolver.ts index 19720cc09..1c3438bde 100644 --- a/backend/src/graphql/resolver/KlicktippResolver.ts +++ b/backend/src/graphql/resolver/KlicktippResolver.ts @@ -1,10 +1,6 @@ -/* eslint-disable @typescript-eslint/no-unsafe-call */ -/* eslint-disable @typescript-eslint/no-unsafe-return */ -import { Resolver, Query, Authorized, Arg, Mutation, Ctx } from 'type-graphql' +import { Resolver, Authorized, Mutation, Ctx } from 'type-graphql' import { - getKlickTippUser, - getKlicktippTagMap, unsubscribe, klicktippSignIn, } from '@/apis/KlicktippController' @@ -14,18 +10,6 @@ import { Context, getUser } from '@/server/context' @Resolver() export class KlicktippResolver { - @Authorized([RIGHTS.GET_KLICKTIPP_USER]) - @Query(() => String) - async getKlicktippUser(@Arg('email') email: string): Promise { - return await getKlickTippUser(email) - } - - @Authorized([RIGHTS.GET_KLICKTIPP_TAG_MAP]) - @Query(() => String) - async getKlicktippTagMap(): Promise { - return await getKlicktippTagMap() - } - @Authorized([RIGHTS.UNSUBSCRIBE_NEWSLETTER]) @Mutation(() => Boolean) async unsubscribeNewsletter(@Ctx() context: Context): Promise { From 54e912f028faaad20bfb01cb4b712245989059c4 Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 30 Mar 2023 16:30:44 +0200 Subject: [PATCH 14/34] Add unit tests for KlicktippResolver --- .../resolver/KlicktippResolver.test.ts | 134 ++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 backend/src/graphql/resolver/KlicktippResolver.test.ts diff --git a/backend/src/graphql/resolver/KlicktippResolver.test.ts b/backend/src/graphql/resolver/KlicktippResolver.test.ts new file mode 100644 index 000000000..860444b88 --- /dev/null +++ b/backend/src/graphql/resolver/KlicktippResolver.test.ts @@ -0,0 +1,134 @@ +import { cleanDB, resetToken, testEnvironment } from '@test/helpers' +import { userFactory } from '@/seeds/factory/user' +import { logger, i18n as localization } from '@test/testSetup' +import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' +import { login, subscribeNewsletter, unsubscribeNewsletter } from '@/seeds/graphql/mutations' +import { GraphQLError } from 'graphql' +import { UserContact } from '@entity/UserContact' +import { Event as DbEvent } from '@entity/Event' +import { EventType } from '@/event/Event' + +let testEnv: any, mutate: any, query: any, con: any + +beforeAll(async () => { + testEnv = await testEnvironment(logger, localization) + mutate = testEnv.mutate + query = testEnv.query + con = testEnv.con + await cleanDB() +}) + +afterAll(async () => { + await cleanDB() + await con.close() +}) + +describe('KlicktippResolver', () => { + let bibi + + beforeAll(async () => { + bibi = await userFactory(testEnv, bibiBloxberg) + }) + + afterAll(async () => { + await cleanDB() + }) + + describe('subscribeNewsletter', () => { + describe('unauthenticated', () => { + it('returns an error', async () => { + const { errors: errorObjects }: { errors: [GraphQLError] } = await mutate({ + mutation: subscribeNewsletter, + }) + + expect(errorObjects).toEqual([new GraphQLError('401 Unauthorized')]) + }) + }) + + describe('authenticated', () => { + beforeAll(async () => { + await mutate({ + mutation: login, + variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, + }) + }) + + afterAll(() => { + resetToken() + }) + + it('calls API', async () => { + const { + data: { subscribeNewsletter: isSubscribed }, + }: { data: { subscribeNewsletter: boolean } } = await mutate({ + mutation: subscribeNewsletter, + }) + + expect(isSubscribed).toEqual(true) + }) + + it('stores the SUBSCRIBE_NEWSLETTER event in the database', async () => { + const userConatct = await UserContact.findOneOrFail( + { email: 'bibi@bloxberg.de' }, + { relations: ['user'] }, + ) + await expect(DbEvent.find()).resolves.toContainEqual( + expect.objectContaining({ + type: EventType.SUBSCRIBE_NEWSLETTER, + affectedUserId: userConatct.user.id, + actingUserId: userConatct.user.id, + }), + ) + }) + }) + }) + + describe('unsubscribeNewsletter', () => { + describe('unauthenticated', () => { + it('returns an error', async () => { + const { errors: errorObjects }: { errors: [GraphQLError] } = await mutate({ + mutation: unsubscribeNewsletter, + }) + + expect(errorObjects).toEqual([new GraphQLError('401 Unauthorized')]) + }) + }) + + describe('authenticated', () => { + beforeAll(async () => { + await mutate({ + mutation: login, + variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, + }) + }) + + afterAll(() => { + resetToken() + }) + + it('calls API', async () => { + const { + data: { unsubscribeNewsletter: isUnsubscribed }, + }: { data: { unsubscribeNewsletter: boolean } } = await mutate({ + mutation: unsubscribeNewsletter, + }) + + expect(isUnsubscribed).toEqual(true) + }) + + it('stores the UNSUBSCRIBE_NEWSLETTER event in the database', async () => { + const userConatct = await UserContact.findOneOrFail( + { email: 'bibi@bloxberg.de' }, + { relations: ['user'] }, + ) + await expect(DbEvent.find()).resolves.toContainEqual( + expect.objectContaining({ + type: EventType.UNSUBSCRIBE_NEWSLETTER, + affectedUserId: userConatct.user.id, + actingUserId: userConatct.user.id, + }), + ) + }) + }) + }) +}) From 8c3a847af6bf84a471def4f579fc404e189a50de Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 30 Mar 2023 16:31:02 +0200 Subject: [PATCH 15/34] Linting --- backend/src/graphql/resolver/KlicktippResolver.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/backend/src/graphql/resolver/KlicktippResolver.ts b/backend/src/graphql/resolver/KlicktippResolver.ts index 1c3438bde..e03e81440 100644 --- a/backend/src/graphql/resolver/KlicktippResolver.ts +++ b/backend/src/graphql/resolver/KlicktippResolver.ts @@ -1,9 +1,6 @@ import { Resolver, Authorized, Mutation, Ctx } from 'type-graphql' -import { - unsubscribe, - klicktippSignIn, -} from '@/apis/KlicktippController' +import { unsubscribe, klicktippSignIn } from '@/apis/KlicktippController' import { EVENT_UNSUBSCRIBE_NEWSLETTER, EVENT_SUBSCRIBE_NEWSLETTER } from '@/event/Event' import { RIGHTS } from '@/auth/RIGHTS' import { Context, getUser } from '@/server/context' From c07582d5a1a55518433a313716fb965f148e305b Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 30 Mar 2023 16:44:17 +0200 Subject: [PATCH 16/34] Merge & linting --- .../src/emails/sendEmailTranslated.test.ts | 2 +- backend/src/emails/sendEmailVariants.test.ts | 4 ++-- backend/src/event/Event.ts | 2 +- .../federation/validateCommunities.test.ts | 2 +- backend/src/graphql/model/Transaction.ts | 2 +- .../src/graphql/resolver/BalanceResolver.ts | 5 ++-- .../resolver/CommunityResolver.test.ts | 2 +- .../resolver/ContributionLinkResolver.test.ts | 2 +- .../resolver/ContributionLinkResolver.ts | 14 +++++------ .../resolver/ContributionResolver.test.ts | 24 +++++++++---------- .../graphql/resolver/ContributionResolver.ts | 20 ++++++++-------- .../resolver/KlicktippResolver.test.ts | 6 ++--- .../resolver/TransactionLinkResolver.test.ts | 6 ++--- .../resolver/TransactionLinkResolver.ts | 10 ++++---- .../resolver/TransactionResolver.test.ts | 4 ++-- .../graphql/resolver/TransactionResolver.ts | 10 ++++---- .../src/graphql/resolver/UserResolver.test.ts | 4 ++-- backend/src/graphql/resolver/UserResolver.ts | 17 +++++++------ .../src/graphql/resolver/semaphore.test.ts | 2 +- .../graphql/resolver/util/creations.test.ts | 2 +- .../src/graphql/resolver/util/creations.ts | 2 +- backend/src/middleware/klicktippMiddleware.ts | 2 +- backend/src/password/EncryptorUtils.ts | 2 +- backend/src/seeds/factory/contributionLink.ts | 2 +- backend/src/server/LogError.test.ts | 2 +- backend/src/util/communityUser.ts | 2 +- backend/src/util/decay.ts | 2 +- backend/src/util/validate.ts | 4 ++-- backend/src/util/virtualTransactions.ts | 2 +- e2e-tests/yarn.lock | 10 ++++---- 30 files changed, 84 insertions(+), 86 deletions(-) diff --git a/backend/src/emails/sendEmailTranslated.test.ts b/backend/src/emails/sendEmailTranslated.test.ts index 762b88cf0..f2fae2746 100644 --- a/backend/src/emails/sendEmailTranslated.test.ts +++ b/backend/src/emails/sendEmailTranslated.test.ts @@ -1,8 +1,8 @@ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/unbound-method */ import { createTransport } from 'nodemailer' -import { sendEmailTranslated } from './sendEmailTranslated' import { logger, i18n } from '@test/testSetup' +import { sendEmailTranslated } from './sendEmailTranslated' import CONFIG from '@/config' CONFIG.EMAIL = false diff --git a/backend/src/emails/sendEmailVariants.test.ts b/backend/src/emails/sendEmailVariants.test.ts index 399ed89ac..3c8d22f95 100644 --- a/backend/src/emails/sendEmailVariants.test.ts +++ b/backend/src/emails/sendEmailVariants.test.ts @@ -4,6 +4,8 @@ /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ import { Decimal } from 'decimal.js-light' +import { testEnvironment } from '@test/helpers' +import { logger, i18n as localization } from '@test/testSetup' import { sendAddedContributionMessageEmail, sendAccountActivationEmail, @@ -16,8 +18,6 @@ import { sendTransactionReceivedEmail, } from './sendEmailVariants' import { sendEmailTranslated } from './sendEmailTranslated' -import { testEnvironment } from '@test/helpers' -import { logger, i18n as localization } from '@test/testSetup' import CONFIG from '@/config' let con: any diff --git a/backend/src/event/Event.ts b/backend/src/event/Event.ts index bfeba6d50..e2a5c0090 100644 --- a/backend/src/event/Event.ts +++ b/backend/src/event/Event.ts @@ -57,7 +57,7 @@ export { EVENT_EMAIL_ACCOUNT_MULTIREGISTRATION } from './EVENT_EMAIL_ACCOUNT_MUL export { EVENT_EMAIL_ADMIN_CONFIRMATION } from './EVENT_EMAIL_ADMIN_CONFIRMATION' export { EVENT_EMAIL_CONFIRMATION } from './EVENT_EMAIL_CONFIRMATION' export { EVENT_EMAIL_FORGOT_PASSWORD } from './EVENT_EMAIL_FORGOT_PASSWORD' -export { EVENT_SEND_CONFIRMATION_EMAIL } from './EVENT_SEND_CONFIRMATION_EMAIL' +export { EVENT_SUBSCRIBE_NEWSLETTER } from './EVENT_SUBSCRIBE_NEWSLETTER' export { EVENT_TRANSACTION_SEND } from './EVENT_TRANSACTION_SEND' export { EVENT_TRANSACTION_RECEIVE } from './EVENT_TRANSACTION_RECEIVE' export { EVENT_TRANSACTION_LINK_CREATE } from './EVENT_TRANSACTION_LINK_CREATE' diff --git a/backend/src/federation/validateCommunities.test.ts b/backend/src/federation/validateCommunities.test.ts index a99bb3274..57d9bd65f 100644 --- a/backend/src/federation/validateCommunities.test.ts +++ b/backend/src/federation/validateCommunities.test.ts @@ -6,9 +6,9 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { Community as DbCommunity } from '@entity/Community' -import { validateCommunities } from './validateCommunities' import { logger } from '@test/testSetup' import { testEnvironment, cleanDB } from '@test/helpers' +import { validateCommunities } from './validateCommunities' let con: any let testEnv: any diff --git a/backend/src/graphql/model/Transaction.ts b/backend/src/graphql/model/Transaction.ts index 8f0d1eadc..9e2be85dd 100644 --- a/backend/src/graphql/model/Transaction.ts +++ b/backend/src/graphql/model/Transaction.ts @@ -1,9 +1,9 @@ import { ObjectType, Field, Int } from 'type-graphql' import { Transaction as dbTransaction } from '@entity/Transaction' import { Decimal } from 'decimal.js-light' +import { TransactionTypeId } from '@enum/TransactionTypeId' import { Decay } from './Decay' import { User } from './User' -import { TransactionTypeId } from '@enum/TransactionTypeId' @ObjectType() export class Transaction { diff --git a/backend/src/graphql/resolver/BalanceResolver.ts b/backend/src/graphql/resolver/BalanceResolver.ts index 7600f12b9..520b8c094 100644 --- a/backend/src/graphql/resolver/BalanceResolver.ts +++ b/backend/src/graphql/resolver/BalanceResolver.ts @@ -6,11 +6,10 @@ import { getCustomRepository } from '@dbTools/typeorm' import { Transaction as dbTransaction } from '@entity/Transaction' import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink' +import { TransactionLinkRepository } from '@repository/TransactionLink' +import { Balance } from '@model/Balance' import { GdtResolver } from './GdtResolver' import { getLastTransaction } from './util/getLastTransaction' -import { TransactionLinkRepository } from '@repository/TransactionLink' - -import { Balance } from '@model/Balance' import { backendLogger as logger } from '@/server/logger' import { Context, getUser } from '@/server/context' diff --git a/backend/src/graphql/resolver/CommunityResolver.test.ts b/backend/src/graphql/resolver/CommunityResolver.test.ts index f4352c095..5513a73b8 100644 --- a/backend/src/graphql/resolver/CommunityResolver.test.ts +++ b/backend/src/graphql/resolver/CommunityResolver.test.ts @@ -6,8 +6,8 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { Community as DbCommunity } from '@entity/Community' -import { getCommunities } from '@/seeds/graphql/queries' import { testEnvironment } from '@test/helpers' +import { getCommunities } from '@/seeds/graphql/queries' let query: any diff --git a/backend/src/graphql/resolver/ContributionLinkResolver.test.ts b/backend/src/graphql/resolver/ContributionLinkResolver.test.ts index 6a69e257e..7dfb44e55 100644 --- a/backend/src/graphql/resolver/ContributionLinkResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionLinkResolver.test.ts @@ -9,6 +9,7 @@ import { GraphQLError } from 'graphql' import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' import { Event as DbEvent } from '@entity/Event' import { logger } from '@test/testSetup' +import { cleanDB, testEnvironment, resetToken } from '@test/helpers' import { login, createContributionLink, @@ -16,7 +17,6 @@ import { updateContributionLink, } from '@/seeds/graphql/mutations' import { listContributionLinks } from '@/seeds/graphql/queries' -import { cleanDB, testEnvironment, resetToken } from '@test/helpers' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { peterLustig } from '@/seeds/users/peter-lustig' import { userFactory } from '@/seeds/factory/user' diff --git a/backend/src/graphql/resolver/ContributionLinkResolver.ts b/backend/src/graphql/resolver/ContributionLinkResolver.ts index 55a23187f..dc88bea07 100644 --- a/backend/src/graphql/resolver/ContributionLinkResolver.ts +++ b/backend/src/graphql/resolver/ContributionLinkResolver.ts @@ -3,20 +3,20 @@ import { Resolver, Args, Arg, Authorized, Mutation, Query, Int, Ctx } from 'type import { MoreThan, IsNull } from '@dbTools/typeorm' import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' +import { ContributionLinkList } from '@model/ContributionLinkList' +import { ContributionLink } from '@model/ContributionLink' +import ContributionLinkArgs from '@arg/ContributionLinkArgs' +import { Order } from '@enum/Order' +import Paginated from '@arg/Paginated' +import { transactionLinkCode as contributionLinkCode } from './TransactionLinkResolver' +import { isStartEndDateValid } from './util/creations' import { CONTRIBUTIONLINK_NAME_MAX_CHARS, CONTRIBUTIONLINK_NAME_MIN_CHARS, MEMO_MAX_CHARS, MEMO_MIN_CHARS, } from './const/const' -import { isStartEndDateValid } from './util/creations' -import { transactionLinkCode as contributionLinkCode } from './TransactionLinkResolver' -import { ContributionLinkList } from '@model/ContributionLinkList' -import { ContributionLink } from '@model/ContributionLink' -import ContributionLinkArgs from '@arg/ContributionLinkArgs' import { RIGHTS } from '@/auth/RIGHTS' -import { Order } from '@enum/Order' -import Paginated from '@arg/Paginated' // TODO: this is a strange construct import LogError from '@/server/LogError' diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index df8524a0c..1dfb6567c 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -13,6 +13,18 @@ import { Transaction as DbTransaction } from '@entity/Transaction' import { User } from '@entity/User' import { UserInputError } from 'apollo-server-express' import { Event as DbEvent } from '@entity/Event' +import { + cleanDB, + resetToken, + testEnvironment, + contributionDateFormatter, + resetEntity, +} from '@test/helpers' +import { logger, i18n as localization } from '@test/testSetup' +import { UnconfirmedContribution } from '@model/UnconfirmedContribution' +import { ContributionListResult } from '@model/Contribution' +import { ContributionStatus } from '@enum/ContributionStatus' +import { Order } from '@enum/Order' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { bobBaumeister } from '@/seeds/users/bob-baumeister' import { stephenHawking } from '@/seeds/users/stephen-hawking' @@ -40,24 +52,12 @@ import { sendContributionDeletedEmail, sendContributionDeniedEmail, } from '@/emails/sendEmailVariants' -import { - cleanDB, - resetToken, - testEnvironment, - contributionDateFormatter, - resetEntity, -} from '@test/helpers' 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 { EventType } from '@/event/Event' -import { logger, i18n as localization } from '@test/testSetup' import { raeuberHotzenplotz } from '@/seeds/users/raeuber-hotzenplotz' -import { UnconfirmedContribution } from '@model/UnconfirmedContribution' -import { ContributionListResult } from '@model/Contribution' -import { ContributionStatus } from '@enum/ContributionStatus' -import { Order } from '@enum/Order' jest.mock('@/emails/sendEmailVariants') diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 83cf29fc7..6e412fc72 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -9,16 +9,6 @@ import { UserContact } from '@entity/UserContact' import { User as DbUser } from '@entity/User' import { Transaction as DbTransaction } from '@entity/Transaction' -import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const' -import { getLastTransaction } from './util/getLastTransaction' -import { findContributions } from './util/findContributions' -import { - getUserCreation, - validateContribution, - updateCreations, - isValidDateString, - getOpenCreations, -} from './util/creations' import { AdminUpdateContribution } from '@model/AdminUpdateContribution' import { Contribution, ContributionListResult } from '@model/Contribution' import { Decay } from '@model/Decay' @@ -33,6 +23,16 @@ import ContributionArgs from '@arg/ContributionArgs' import Paginated from '@arg/Paginated' import AdminCreateContributionArgs from '@arg/AdminCreateContributionArgs' import AdminUpdateContributionArgs from '@arg/AdminUpdateContributionArgs' +import { + getUserCreation, + validateContribution, + updateCreations, + isValidDateString, + getOpenCreations, +} from './util/creations' +import { findContributions } from './util/findContributions' +import { getLastTransaction } from './util/getLastTransaction' +import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const' import { RIGHTS } from '@/auth/RIGHTS' import { Context, getUser, getClientTimezoneOffset } from '@/server/context' diff --git a/backend/src/graphql/resolver/KlicktippResolver.test.ts b/backend/src/graphql/resolver/KlicktippResolver.test.ts index 860444b88..0e64a779f 100644 --- a/backend/src/graphql/resolver/KlicktippResolver.test.ts +++ b/backend/src/graphql/resolver/KlicktippResolver.test.ts @@ -1,11 +1,11 @@ import { cleanDB, resetToken, testEnvironment } from '@test/helpers' -import { userFactory } from '@/seeds/factory/user' import { logger, i18n as localization } from '@test/testSetup' -import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' -import { login, subscribeNewsletter, unsubscribeNewsletter } from '@/seeds/graphql/mutations' import { GraphQLError } from 'graphql' import { UserContact } from '@entity/UserContact' import { Event as DbEvent } from '@entity/Event' +import { login, subscribeNewsletter, unsubscribeNewsletter } from '@/seeds/graphql/mutations' +import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' +import { userFactory } from '@/seeds/factory/user' import { EventType } from '@/event/Event' let testEnv: any, mutate: any, query: any, con: any diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.test.ts b/backend/src/graphql/resolver/TransactionLinkResolver.test.ts index fd2a44b4b..96eb99ea7 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.test.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.test.ts @@ -13,10 +13,12 @@ import { GraphQLError } from 'graphql' import { Transaction } from '@entity/Transaction' import { Event as DbEvent } from '@entity/Event' import { UserContact } from '@entity/UserContact' +import { cleanDB, testEnvironment, resetToken, resetEntity } from '@test/helpers' +import { UnconfirmedContribution } from '@model/UnconfirmedContribution' +import { logger } from '@test/testSetup' import { transactionLinkCode } from './TransactionLinkResolver' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { peterLustig } from '@/seeds/users/peter-lustig' -import { cleanDB, testEnvironment, resetToken, resetEntity } from '@test/helpers' import { creationFactory } from '@/seeds/factory/creation' import { creations } from '@/seeds/creation/index' import { userFactory } from '@/seeds/factory/user' @@ -33,9 +35,7 @@ import { confirmContribution, } from '@/seeds/graphql/mutations' import { listTransactionLinksAdmin } from '@/seeds/graphql/queries' -import { UnconfirmedContribution } from '@model/UnconfirmedContribution' import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK' -import { logger } from '@test/testSetup' import { EventType } from '@/event/Event' // mock semaphore to allow use fake timers diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.ts b/backend/src/graphql/resolver/TransactionLinkResolver.ts index 6aa829ac1..534db02c1 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.ts @@ -10,10 +10,6 @@ import { Contribution as DbContribution } from '@entity/Contribution' import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' import { Resolver, Args, Arg, Authorized, Ctx, Mutation, Query, Int } from 'type-graphql' -import { getUserCreation, validateContribution } from './util/creations' -import { executeTransaction } from './TransactionResolver' -import { getLastTransaction } from './util/getLastTransaction' -import transactionLinkList from './util/transactionLinkList' import { User } from '@model/User' import { ContributionLink } from '@model/ContributionLink' import { Decay } from '@model/Decay' @@ -25,12 +21,16 @@ import { ContributionCycleType } from '@enum/ContributionCycleType' import TransactionLinkArgs from '@arg/TransactionLinkArgs' import Paginated from '@arg/Paginated' import TransactionLinkFilters from '@arg/TransactionLinkFilters' +import QueryLinkResult from '@union/QueryLinkResult' +import transactionLinkList from './util/transactionLinkList' +import { getLastTransaction } from './util/getLastTransaction' +import { executeTransaction } from './TransactionResolver' +import { getUserCreation, validateContribution } from './util/creations' import { backendLogger as logger } from '@/server/logger' import { Context, getUser, getClientTimezoneOffset } from '@/server/context' import { calculateBalance } from '@/util/validate' import { RIGHTS } from '@/auth/RIGHTS' import { calculateDecay } from '@/util/decay' -import QueryLinkResult from '@union/QueryLinkResult' import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK' import LogError from '@/server/LogError' import { diff --git a/backend/src/graphql/resolver/TransactionResolver.test.ts b/backend/src/graphql/resolver/TransactionResolver.test.ts index f26234363..17ed81676 100644 --- a/backend/src/graphql/resolver/TransactionResolver.test.ts +++ b/backend/src/graphql/resolver/TransactionResolver.test.ts @@ -10,6 +10,8 @@ import { Transaction } from '@entity/Transaction' import { User } from '@entity/User' import { GraphQLError } from 'graphql' import { Event as DbEvent } from '@entity/Event' +import { cleanDB, testEnvironment } from '@test/helpers' +import { logger } from '@test/testSetup' import { findUserByEmail } from './UserResolver' import { EventType } from '@/event/Event' import { userFactory } from '@/seeds/factory/user' @@ -23,8 +25,6 @@ import { bobBaumeister } from '@/seeds/users/bob-baumeister' import { garrickOllivander } from '@/seeds/users/garrick-ollivander' import { peterLustig } from '@/seeds/users/peter-lustig' import { stephenHawking } from '@/seeds/users/stephen-hawking' -import { cleanDB, testEnvironment } from '@test/helpers' -import { logger } from '@test/testSetup' let mutate: any, query: any, con: any let testEnv: any diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index f38a4a07b..e0ac5d435 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -9,10 +9,6 @@ import { getCustomRepository, getConnection, In } from '@dbTools/typeorm' import { User as dbUser } from '@entity/User' import { Transaction as dbTransaction } from '@entity/Transaction' import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink' -import { BalanceResolver } from './BalanceResolver' -import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const' -import { findUserByEmail } from './UserResolver' -import { getLastTransaction } from './util/getLastTransaction' import { TransactionRepository } from '@repository/Transaction' import { TransactionLinkRepository } from '@repository/TransactionLink' @@ -21,9 +17,13 @@ import { Transaction } from '@model/Transaction' import { TransactionList } from '@model/TransactionList' import { Order } from '@enum/Order' import { TransactionTypeId } from '@enum/TransactionTypeId' -import { calculateBalance } from '@/util/validate' import TransactionSendArgs from '@arg/TransactionSendArgs' import Paginated from '@arg/Paginated' +import { getLastTransaction } from './util/getLastTransaction' +import { findUserByEmail } from './UserResolver' +import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const' +import { BalanceResolver } from './BalanceResolver' +import { calculateBalance } from '@/util/validate' import { backendLogger as logger } from '@/server/logger' import { Context, getUser } from '@/server/context' diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index aebd0f0eb..1b6239fea 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -15,9 +15,10 @@ import { Event as DbEvent } from '@entity/Event' import { OptInType } from '@enum/OptInType' import { UserContactType } from '@enum/UserContactType' import { PasswordEncryptionType } from '@enum/PasswordEncryptionType' -import { objectValuesToArray } from '@/util/utilities' import { testEnvironment, headerPushMock, resetToken, cleanDB } from '@test/helpers' import { logger, i18n as localization } from '@test/testSetup' +import { ContributionLink } from '@model/ContributionLink' +import { objectValuesToArray } from '@/util/utilities' import { printTimeDuration } from '@/util/time' import { userFactory } from '@/seeds/factory/user' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' @@ -44,7 +45,6 @@ import { } from '@/emails/sendEmailVariants' import { contributionLinkFactory } from '@/seeds/factory/contributionLink' import { transactionLinkFactory } from '@/seeds/factory/transactionLink' -import { ContributionLink } from '@model/ContributionLink' import { EventType } from '@/event/Event' import { peterLustig } from '@/seeds/users/peter-lustig' import { bobBaumeister } from '@/seeds/users/bob-baumeister' diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 54d4f583f..aca72b5d0 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -21,8 +21,6 @@ import { User as DbUser } from '@entity/User' import { UserContact as DbUserContact } from '@entity/UserContact' import { TransactionLink as DbTransactionLink } from '@entity/TransactionLink' import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' -import { getUserCreations } from './util/creations' -import { FULL_CREATION_AVAILABLE } from './const/const' import { PasswordEncryptionType } from '@enum/PasswordEncryptionType' import { UserRepository } from '@repository/User' @@ -33,18 +31,19 @@ import { OptInType } from '@enum/OptInType' import { Order } from '@enum/Order' import { UserContactType } from '@enum/UserContactType' -import { - sendAccountActivationEmail, - sendAccountMultiRegistrationEmail, - sendResetPasswordEmail, -} from '@/emails/sendEmailVariants' - -import { getTimeDurationObject, printTimeDuration } from '@/util/time' import CreateUserArgs from '@arg/CreateUserArgs' import UnsecureLoginArgs from '@arg/UnsecureLoginArgs' import UpdateUserInfosArgs from '@arg/UpdateUserInfosArgs' import Paginated from '@arg/Paginated' import SearchUsersArgs from '@arg/SearchUsersArgs' +import { FULL_CREATION_AVAILABLE } from './const/const' +import { getUserCreations } from './util/creations' +import { getTimeDurationObject, printTimeDuration } from '@/util/time' +import { + sendAccountActivationEmail, + sendAccountMultiRegistrationEmail, + sendResetPasswordEmail, +} from '@/emails/sendEmailVariants' import { backendLogger as logger } from '@/server/logger' import { Context, getUser, getClientTimezoneOffset } from '@/server/context' diff --git a/backend/src/graphql/resolver/semaphore.test.ts b/backend/src/graphql/resolver/semaphore.test.ts index 6b1976021..cc4d589dc 100644 --- a/backend/src/graphql/resolver/semaphore.test.ts +++ b/backend/src/graphql/resolver/semaphore.test.ts @@ -5,12 +5,12 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import { Decimal } from 'decimal.js-light' +import { cleanDB, testEnvironment, contributionDateFormatter } from '@test/helpers' import { userFactory } from '@/seeds/factory/user' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { bobBaumeister } from '@/seeds/users/bob-baumeister' import { peterLustig } from '@/seeds/users/peter-lustig' import { creationFactory, nMonthsBefore } from '@/seeds/factory/creation' -import { cleanDB, testEnvironment, contributionDateFormatter } from '@test/helpers' import { confirmContribution, createContribution, diff --git a/backend/src/graphql/resolver/util/creations.test.ts b/backend/src/graphql/resolver/util/creations.test.ts index 7461401c8..5b6b40e2b 100644 --- a/backend/src/graphql/resolver/util/creations.test.ts +++ b/backend/src/graphql/resolver/util/creations.test.ts @@ -6,8 +6,8 @@ import { User } from '@entity/User' import { Contribution } from '@entity/Contribution' -import { getUserCreation } from './creations' import { testEnvironment, cleanDB, contributionDateFormatter } from '@test/helpers' +import { getUserCreation } from './creations' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { peterLustig } from '@/seeds/users/peter-lustig' import { userFactory } from '@/seeds/factory/user' diff --git a/backend/src/graphql/resolver/util/creations.ts b/backend/src/graphql/resolver/util/creations.ts index 6ebeae8b9..dba0c8c81 100644 --- a/backend/src/graphql/resolver/util/creations.ts +++ b/backend/src/graphql/resolver/util/creations.ts @@ -3,9 +3,9 @@ import { getConnection } from '@dbTools/typeorm' import { Contribution } from '@entity/Contribution' import { Decimal } from 'decimal.js-light' +import { OpenCreation } from '@model/OpenCreation' import { FULL_CREATION_AVAILABLE, MAX_CREATION_AMOUNT } from '@/graphql/resolver/const/const' import { backendLogger as logger } from '@/server/logger' -import { OpenCreation } from '@model/OpenCreation' import LogError from '@/server/LogError' interface CreationMap { diff --git a/backend/src/middleware/klicktippMiddleware.ts b/backend/src/middleware/klicktippMiddleware.ts index bc11f6ad7..369b29475 100644 --- a/backend/src/middleware/klicktippMiddleware.ts +++ b/backend/src/middleware/klicktippMiddleware.ts @@ -3,8 +3,8 @@ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/restrict-template-expressions */ import { MiddlewareFn } from 'type-graphql' -import { getKlickTippUser } from '@/apis/KlicktippController' import { KlickTipp } from '@model/KlickTipp' +import { getKlickTippUser } from '@/apis/KlicktippController' import { klickTippLogger as logger } from '@/server/logger' // export const klicktippRegistrationMiddleware: MiddlewareFn = async ( diff --git a/backend/src/password/EncryptorUtils.ts b/backend/src/password/EncryptorUtils.ts index b4531b3bb..ab8a333d2 100644 --- a/backend/src/password/EncryptorUtils.ts +++ b/backend/src/password/EncryptorUtils.ts @@ -2,10 +2,10 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ import { User } from '@entity/User' +import { PasswordEncryptionType } from '@enum/PasswordEncryptionType' import CONFIG from '@/config' import LogError from '@/server/LogError' import { backendLogger as logger } from '@/server/logger' -import { PasswordEncryptionType } from '@enum/PasswordEncryptionType' // eslint-disable-next-line @typescript-eslint/no-var-requires, import/no-commonjs const sodium = require('sodium-native') diff --git a/backend/src/seeds/factory/contributionLink.ts b/backend/src/seeds/factory/contributionLink.ts index 5925cdcfe..6e1d9bd50 100644 --- a/backend/src/seeds/factory/contributionLink.ts +++ b/backend/src/seeds/factory/contributionLink.ts @@ -2,8 +2,8 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/unbound-method */ import { ApolloServerTestClient } from 'apollo-server-testing' -import { login, createContributionLink } from '@/seeds/graphql/mutations' import { ContributionLink } from '@model/ContributionLink' +import { login, createContributionLink } from '@/seeds/graphql/mutations' import { ContributionLinkInterface } from '@/seeds/contributionLink/ContributionLinkInterface' export const contributionLinkFactory = async ( diff --git a/backend/src/server/LogError.test.ts b/backend/src/server/LogError.test.ts index 318a477ef..b7a067e28 100644 --- a/backend/src/server/LogError.test.ts +++ b/backend/src/server/LogError.test.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/unbound-method */ -import LogError from './LogError' import { logger } from '@test/testSetup' +import LogError from './LogError' describe('LogError', () => { it('logs an Error when created', () => { diff --git a/backend/src/util/communityUser.ts b/backend/src/util/communityUser.ts index dfa477da9..d086727bf 100644 --- a/backend/src/util/communityUser.ts +++ b/backend/src/util/communityUser.ts @@ -3,9 +3,9 @@ import { SaveOptions, RemoveOptions } from '@dbTools/typeorm' import { User as dbUser } from '@entity/User' import { UserContact } from '@entity/UserContact' +import { User } from '@model/User' import { PasswordEncryptionType } from '@/graphql/enum/PasswordEncryptionType' // import { UserContact as EmailContact } from '@entity/UserContact' -import { User } from '@model/User' const communityDbUser: dbUser = { id: -1, diff --git a/backend/src/util/decay.ts b/backend/src/util/decay.ts index d35eb83a4..3c76b0995 100644 --- a/backend/src/util/decay.ts +++ b/backend/src/util/decay.ts @@ -1,6 +1,6 @@ import { Decimal } from 'decimal.js-light' -import CONFIG from '@/config' import { Decay } from '@model/Decay' +import CONFIG from '@/config' import LogError from '@/server/LogError' // TODO: externalize all those definitions and functions into an external decay library diff --git a/backend/src/util/validate.ts b/backend/src/util/validate.ts index ec28dfa13..b70c90344 100644 --- a/backend/src/util/validate.ts +++ b/backend/src/util/validate.ts @@ -1,10 +1,10 @@ import { Decimal } from 'decimal.js-light' import { getCustomRepository } from '@dbTools/typeorm' import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink' -import { calculateDecay } from './decay' -import { getLastTransaction } from '@/graphql/resolver/util/getLastTransaction' import { TransactionLinkRepository } from '@repository/TransactionLink' import { Decay } from '@model/Decay' +import { calculateDecay } from './decay' +import { getLastTransaction } from '@/graphql/resolver/util/getLastTransaction' function isStringBoolean(value: string): boolean { const lowerValue = value.toLowerCase() diff --git a/backend/src/util/virtualTransactions.ts b/backend/src/util/virtualTransactions.ts index 7810ad871..aea4ebb66 100644 --- a/backend/src/util/virtualTransactions.ts +++ b/backend/src/util/virtualTransactions.ts @@ -2,10 +2,10 @@ import { SaveOptions, RemoveOptions } from '@dbTools/typeorm' import { Transaction as dbTransaction } from '@entity/Transaction' import { Decimal } from 'decimal.js-light' -import { calculateDecay } from './decay' import { Transaction } from '@model/Transaction' import { TransactionTypeId } from '@enum/TransactionTypeId' import { User } from '@model/User' +import { calculateDecay } from './decay' const defaultModelFunctions = { hasId: function (): boolean { diff --git a/e2e-tests/yarn.lock b/e2e-tests/yarn.lock index c0f623e47..20956c5d0 100644 --- a/e2e-tests/yarn.lock +++ b/e2e-tests/yarn.lock @@ -2193,10 +2193,10 @@ crypto-browserify@^3.0.0: randombytes "^2.0.0" randomfill "^1.0.3" -cypress@^10.4.0: - version "10.8.0" - resolved "https://registry.yarnpkg.com/cypress/-/cypress-10.8.0.tgz#12a681f2642b6f13d636bab65d5b71abdb1497a5" - integrity sha512-QVse0dnLm018hgti2enKMVZR9qbIO488YGX06nH5j3Dg1isL38DwrBtyrax02CANU6y8F4EJUuyW6HJKw1jsFA== +cypress@^12.7.0: + version "12.9.0" + resolved "https://registry.yarnpkg.com/cypress/-/cypress-12.9.0.tgz#e6ab43cf329fd7c821ef7645517649d72ccf0a12" + integrity sha512-Ofe09LbHKgSqX89Iy1xen2WvpgbvNxDzsWx3mgU1mfILouELeXYGwIib3ItCwoRrRifoQwcBFmY54Vs0zw7QCg== dependencies: "@cypress/request" "^2.88.10" "@cypress/xvfb" "^1.2.4" @@ -2215,7 +2215,7 @@ cypress@^10.4.0: commander "^5.1.0" common-tags "^1.8.0" dayjs "^1.10.4" - debug "^4.3.2" + debug "^4.3.4" enquirer "^2.3.6" eventemitter2 "6.4.7" execa "4.1.0" From 2435afcd7caaea9c039bcf313d2c810d5e685b2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Fri, 31 Mar 2023 00:31:55 +0200 Subject: [PATCH 17/34] 3rd draft of database modell --- .../TechnicalRequirements/Federation.md | 15 +++++++++- ...classdiagramm_x-community-readyness.drawio | 28 +++++++++++++----- .../image/class-diagramm_vision-draft3.png | Bin 0 -> 95513 bytes .../image/class-diagramm_vision-draft3.svg | 1 + 4 files changed, 35 insertions(+), 9 deletions(-) create mode 100644 docu/Concepts/TechnicalRequirements/image/class-diagramm_vision-draft3.png create mode 100644 docu/Concepts/TechnicalRequirements/image/class-diagramm_vision-draft3.svg diff --git a/docu/Concepts/TechnicalRequirements/Federation.md b/docu/Concepts/TechnicalRequirements/Federation.md index 2ab4272f2..84c4965af 100644 --- a/docu/Concepts/TechnicalRequirements/Federation.md +++ b/docu/Concepts/TechnicalRequirements/Federation.md @@ -50,6 +50,8 @@ Before starting in describing the details of the federation handshake, some prer With the federation additional data tables/entities have to be created. +##### 1st Draft + The following diagramms shows the first draft of the possible database-model base on the migration 0063-event_link_fields.ts with 3 steps of migration to reach the required entities. All three diagramms are not exhaustive and are still a base for discussions: ![img](./image/classdiagramm_x-community-readyness_step1.svg) @@ -64,10 +66,10 @@ The 2nd step is an introduction of the entity accounts between the users and the The 3rd step will introduce an additional foreign-users and a users_favorites table. A foreign_user could be stored in the existing users-table, but he will not need all the attributes of a home-user, especially he will never gets an AGE-account in this community. The user_favorites entity is designed to buildup the relations between users and foreign_users or in general between all users. This is simply a first idea for a future discussion. +##### 2nd Draft After team discussion in architecture meeting a second vision draft for database migration is shown in the following picture. Only the concerned tables of the database migration are presented. The three elliptical surroundings shows the different steps, which should be done in separate issues. The model, table namings and columns are not exhaustive and are still a base for further discussions. - ![img](./image/class-diagramm_vision-draft2.svg) **The first step** with renaming the current `communities` table in `communities_federation` and creating a new `communities` table is not changed. More details about motivation and arguments are described above. @@ -81,6 +83,17 @@ After team discussion in architecture meeting a second vision draft for database The previous idea to replace the `user_id `with an `account_id` in the `transactions `table will be not necessary with this draft, because it will not cause a benefit and saves a lot refactoring efforts. +##### 3rd Draft + +After further discussions about the database-model and the necessary migration steps the team decided to integrate an additional migration step for X-Community-Transaction. The decision base on keeping the goal focus on implementation of the x-community sendCoins feature as soon as possible. + +![img](./image/class-diagramm_vision-draft3.svg) + +The additional migration step 2 will simply concentrated on the `transactions `table by adding all necessary columns to handle a *x-community-tx* without a previous migration of the `users `table, shown as step 3 in the picture above. + +In concequence of these additional columns in the `transactions `table the database-model will be denormalized by containing redundanten columns. But this migration step will reduce the necessary efforts to reach the *x-community sendCoins* feature as soon as possible. On the other side it offers more possibilities to ensure data consitency, because of internal data checks in conjunction with the redundant columns. + +The feature *x-community-tx* per *sendCoins* will create several challenges, because there is no technical transaction bracket, which will ensure consistent data in both community databases after all write access are finished. The most favorite concept about handling a x-community-transaction and the upcoming handshake to ensure valid send- and receive-transaction entries in both databases is to follow the two-phase-commit protocol. To avoid blocking the transactions table or user dependent transactions-entries during the two-phase-commit processing the idea of pending_transactions is born. This additional pending_transactions table contains the same columns than the transactions table plus one column named `x_transactions_state`. ##### Community-Entity diff --git a/docu/Concepts/TechnicalRequirements/graphics/classdiagramm_x-community-readyness.drawio b/docu/Concepts/TechnicalRequirements/graphics/classdiagramm_x-community-readyness.drawio index becba0b1f..c618971f8 100644 --- a/docu/Concepts/TechnicalRequirements/graphics/classdiagramm_x-community-readyness.drawio +++ b/docu/Concepts/TechnicalRequirements/graphics/classdiagramm_x-community-readyness.drawio @@ -4,17 +4,17 @@ - - + + - + - - + + - - + + @@ -28,12 +28,24 @@ - + + + + + + + + + + + + +
diff --git a/docu/Concepts/TechnicalRequirements/image/class-diagramm_vision-draft3.png b/docu/Concepts/TechnicalRequirements/image/class-diagramm_vision-draft3.png new file mode 100644 index 0000000000000000000000000000000000000000..b6643fd32e573e3ba713bd54caaaf623334b4a63 GIT binary patch literal 95513 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

X-Community-Readyness
Step 4
X-Community-Read...
X-Community-Readyness
Step 1
X-Community-Read...
X-Community-Readyness
Step 3
X-Community-Read...
X-Community-Readyness
Step 2
X-Community-Read...
Text is not SVG - cannot display \ No newline at end of file From 989a3e30f28be4364f2631c767f05e8dabed06c5 Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 31 Mar 2023 07:16:04 +0200 Subject: [PATCH 18/34] Import order fixed by lint --- .../src/emails/sendEmailTranslated.test.ts | 2 +- backend/src/emails/sendEmailVariants.test.ts | 4 ++-- .../federation/validateCommunities.test.ts | 2 +- backend/src/graphql/model/Transaction.ts | 2 +- .../src/graphql/resolver/BalanceResolver.ts | 4 ++-- .../resolver/ContributionLinkResolver.ts | 10 +++++----- .../graphql/resolver/ContributionResolver.ts | 20 +++++++++---------- .../resolver/TransactionLinkResolver.test.ts | 2 +- .../resolver/TransactionLinkResolver.ts | 8 ++++---- .../resolver/TransactionResolver.test.ts | 2 +- .../graphql/resolver/TransactionResolver.ts | 8 ++++---- backend/src/graphql/resolver/UserResolver.ts | 4 ++-- .../graphql/resolver/util/creations.test.ts | 2 +- backend/src/server/LogError.test.ts | 2 +- backend/src/util/validate.ts | 2 +- backend/src/util/virtualTransactions.ts | 2 +- 16 files changed, 38 insertions(+), 38 deletions(-) diff --git a/backend/src/emails/sendEmailTranslated.test.ts b/backend/src/emails/sendEmailTranslated.test.ts index f2fae2746..762b88cf0 100644 --- a/backend/src/emails/sendEmailTranslated.test.ts +++ b/backend/src/emails/sendEmailTranslated.test.ts @@ -1,8 +1,8 @@ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/unbound-method */ import { createTransport } from 'nodemailer' -import { logger, i18n } from '@test/testSetup' import { sendEmailTranslated } from './sendEmailTranslated' +import { logger, i18n } from '@test/testSetup' import CONFIG from '@/config' CONFIG.EMAIL = false diff --git a/backend/src/emails/sendEmailVariants.test.ts b/backend/src/emails/sendEmailVariants.test.ts index 3c8d22f95..399ed89ac 100644 --- a/backend/src/emails/sendEmailVariants.test.ts +++ b/backend/src/emails/sendEmailVariants.test.ts @@ -4,8 +4,6 @@ /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ import { Decimal } from 'decimal.js-light' -import { testEnvironment } from '@test/helpers' -import { logger, i18n as localization } from '@test/testSetup' import { sendAddedContributionMessageEmail, sendAccountActivationEmail, @@ -18,6 +16,8 @@ import { sendTransactionReceivedEmail, } from './sendEmailVariants' import { sendEmailTranslated } from './sendEmailTranslated' +import { testEnvironment } from '@test/helpers' +import { logger, i18n as localization } from '@test/testSetup' import CONFIG from '@/config' let con: any diff --git a/backend/src/federation/validateCommunities.test.ts b/backend/src/federation/validateCommunities.test.ts index 57d9bd65f..a99bb3274 100644 --- a/backend/src/federation/validateCommunities.test.ts +++ b/backend/src/federation/validateCommunities.test.ts @@ -6,9 +6,9 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { Community as DbCommunity } from '@entity/Community' +import { validateCommunities } from './validateCommunities' import { logger } from '@test/testSetup' import { testEnvironment, cleanDB } from '@test/helpers' -import { validateCommunities } from './validateCommunities' let con: any let testEnv: any diff --git a/backend/src/graphql/model/Transaction.ts b/backend/src/graphql/model/Transaction.ts index 9e2be85dd..8f0d1eadc 100644 --- a/backend/src/graphql/model/Transaction.ts +++ b/backend/src/graphql/model/Transaction.ts @@ -1,9 +1,9 @@ import { ObjectType, Field, Int } from 'type-graphql' import { Transaction as dbTransaction } from '@entity/Transaction' import { Decimal } from 'decimal.js-light' -import { TransactionTypeId } from '@enum/TransactionTypeId' import { Decay } from './Decay' import { User } from './User' +import { TransactionTypeId } from '@enum/TransactionTypeId' @ObjectType() export class Transaction { diff --git a/backend/src/graphql/resolver/BalanceResolver.ts b/backend/src/graphql/resolver/BalanceResolver.ts index 520b8c094..31e2384d4 100644 --- a/backend/src/graphql/resolver/BalanceResolver.ts +++ b/backend/src/graphql/resolver/BalanceResolver.ts @@ -6,10 +6,10 @@ import { getCustomRepository } from '@dbTools/typeorm' import { Transaction as dbTransaction } from '@entity/Transaction' import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink' -import { TransactionLinkRepository } from '@repository/TransactionLink' -import { Balance } from '@model/Balance' import { GdtResolver } from './GdtResolver' import { getLastTransaction } from './util/getLastTransaction' +import { TransactionLinkRepository } from '@repository/TransactionLink' +import { Balance } from '@model/Balance' import { backendLogger as logger } from '@/server/logger' import { Context, getUser } from '@/server/context' diff --git a/backend/src/graphql/resolver/ContributionLinkResolver.ts b/backend/src/graphql/resolver/ContributionLinkResolver.ts index dc88bea07..4b19c36e1 100644 --- a/backend/src/graphql/resolver/ContributionLinkResolver.ts +++ b/backend/src/graphql/resolver/ContributionLinkResolver.ts @@ -3,11 +3,6 @@ import { Resolver, Args, Arg, Authorized, Mutation, Query, Int, Ctx } from 'type import { MoreThan, IsNull } from '@dbTools/typeorm' import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' -import { ContributionLinkList } from '@model/ContributionLinkList' -import { ContributionLink } from '@model/ContributionLink' -import ContributionLinkArgs from '@arg/ContributionLinkArgs' -import { Order } from '@enum/Order' -import Paginated from '@arg/Paginated' import { transactionLinkCode as contributionLinkCode } from './TransactionLinkResolver' import { isStartEndDateValid } from './util/creations' import { @@ -16,6 +11,11 @@ import { MEMO_MAX_CHARS, MEMO_MIN_CHARS, } from './const/const' +import { ContributionLinkList } from '@model/ContributionLinkList' +import { ContributionLink } from '@model/ContributionLink' +import ContributionLinkArgs from '@arg/ContributionLinkArgs' +import { Order } from '@enum/Order' +import Paginated from '@arg/Paginated' import { RIGHTS } from '@/auth/RIGHTS' // TODO: this is a strange construct diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 6e412fc72..c48b05920 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -9,6 +9,16 @@ import { UserContact } from '@entity/UserContact' import { User as DbUser } from '@entity/User' import { Transaction as DbTransaction } from '@entity/Transaction' +import { + getUserCreation, + validateContribution, + updateCreations, + isValidDateString, + getOpenCreations, +} from './util/creations' +import { findContributions } from './util/findContributions' +import { getLastTransaction } from './util/getLastTransaction' +import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const' import { AdminUpdateContribution } from '@model/AdminUpdateContribution' import { Contribution, ContributionListResult } from '@model/Contribution' import { Decay } from '@model/Decay' @@ -23,16 +33,6 @@ import ContributionArgs from '@arg/ContributionArgs' import Paginated from '@arg/Paginated' import AdminCreateContributionArgs from '@arg/AdminCreateContributionArgs' import AdminUpdateContributionArgs from '@arg/AdminUpdateContributionArgs' -import { - getUserCreation, - validateContribution, - updateCreations, - isValidDateString, - getOpenCreations, -} from './util/creations' -import { findContributions } from './util/findContributions' -import { getLastTransaction } from './util/getLastTransaction' -import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const' import { RIGHTS } from '@/auth/RIGHTS' import { Context, getUser, getClientTimezoneOffset } from '@/server/context' diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.test.ts b/backend/src/graphql/resolver/TransactionLinkResolver.test.ts index 96eb99ea7..4f72276d4 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.test.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.test.ts @@ -13,10 +13,10 @@ import { GraphQLError } from 'graphql' import { Transaction } from '@entity/Transaction' import { Event as DbEvent } from '@entity/Event' import { UserContact } from '@entity/UserContact' +import { transactionLinkCode } from './TransactionLinkResolver' import { cleanDB, testEnvironment, resetToken, resetEntity } from '@test/helpers' import { UnconfirmedContribution } from '@model/UnconfirmedContribution' import { logger } from '@test/testSetup' -import { transactionLinkCode } from './TransactionLinkResolver' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { peterLustig } from '@/seeds/users/peter-lustig' import { creationFactory } from '@/seeds/factory/creation' diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.ts b/backend/src/graphql/resolver/TransactionLinkResolver.ts index 534db02c1..3ff6fd36a 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.ts @@ -10,6 +10,10 @@ import { Contribution as DbContribution } from '@entity/Contribution' import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' import { Resolver, Args, Arg, Authorized, Ctx, Mutation, Query, Int } from 'type-graphql' +import transactionLinkList from './util/transactionLinkList' +import { getLastTransaction } from './util/getLastTransaction' +import { executeTransaction } from './TransactionResolver' +import { getUserCreation, validateContribution } from './util/creations' import { User } from '@model/User' import { ContributionLink } from '@model/ContributionLink' import { Decay } from '@model/Decay' @@ -22,10 +26,6 @@ import TransactionLinkArgs from '@arg/TransactionLinkArgs' import Paginated from '@arg/Paginated' import TransactionLinkFilters from '@arg/TransactionLinkFilters' import QueryLinkResult from '@union/QueryLinkResult' -import transactionLinkList from './util/transactionLinkList' -import { getLastTransaction } from './util/getLastTransaction' -import { executeTransaction } from './TransactionResolver' -import { getUserCreation, validateContribution } from './util/creations' import { backendLogger as logger } from '@/server/logger' import { Context, getUser, getClientTimezoneOffset } from '@/server/context' import { calculateBalance } from '@/util/validate' diff --git a/backend/src/graphql/resolver/TransactionResolver.test.ts b/backend/src/graphql/resolver/TransactionResolver.test.ts index 17ed81676..6d039784e 100644 --- a/backend/src/graphql/resolver/TransactionResolver.test.ts +++ b/backend/src/graphql/resolver/TransactionResolver.test.ts @@ -10,9 +10,9 @@ import { Transaction } from '@entity/Transaction' import { User } from '@entity/User' import { GraphQLError } from 'graphql' import { Event as DbEvent } from '@entity/Event' +import { findUserByEmail } from './UserResolver' import { cleanDB, testEnvironment } from '@test/helpers' import { logger } from '@test/testSetup' -import { findUserByEmail } from './UserResolver' import { EventType } from '@/event/Event' import { userFactory } from '@/seeds/factory/user' import { diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index e0ac5d435..a699e7291 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -9,6 +9,10 @@ import { getCustomRepository, getConnection, In } from '@dbTools/typeorm' import { User as dbUser } from '@entity/User' import { Transaction as dbTransaction } from '@entity/Transaction' import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink' +import { getLastTransaction } from './util/getLastTransaction' +import { findUserByEmail } from './UserResolver' +import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const' +import { BalanceResolver } from './BalanceResolver' import { TransactionRepository } from '@repository/Transaction' import { TransactionLinkRepository } from '@repository/TransactionLink' @@ -19,10 +23,6 @@ import { Order } from '@enum/Order' import { TransactionTypeId } from '@enum/TransactionTypeId' import TransactionSendArgs from '@arg/TransactionSendArgs' import Paginated from '@arg/Paginated' -import { getLastTransaction } from './util/getLastTransaction' -import { findUserByEmail } from './UserResolver' -import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const' -import { BalanceResolver } from './BalanceResolver' import { calculateBalance } from '@/util/validate' import { backendLogger as logger } from '@/server/logger' diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index aca72b5d0..0c1cefd12 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -21,6 +21,8 @@ import { User as DbUser } from '@entity/User' import { UserContact as DbUserContact } from '@entity/UserContact' import { TransactionLink as DbTransactionLink } from '@entity/TransactionLink' import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' +import { FULL_CREATION_AVAILABLE } from './const/const' +import { getUserCreations } from './util/creations' import { PasswordEncryptionType } from '@enum/PasswordEncryptionType' import { UserRepository } from '@repository/User' @@ -36,8 +38,6 @@ import UnsecureLoginArgs from '@arg/UnsecureLoginArgs' import UpdateUserInfosArgs from '@arg/UpdateUserInfosArgs' import Paginated from '@arg/Paginated' import SearchUsersArgs from '@arg/SearchUsersArgs' -import { FULL_CREATION_AVAILABLE } from './const/const' -import { getUserCreations } from './util/creations' import { getTimeDurationObject, printTimeDuration } from '@/util/time' import { sendAccountActivationEmail, diff --git a/backend/src/graphql/resolver/util/creations.test.ts b/backend/src/graphql/resolver/util/creations.test.ts index 5b6b40e2b..7461401c8 100644 --- a/backend/src/graphql/resolver/util/creations.test.ts +++ b/backend/src/graphql/resolver/util/creations.test.ts @@ -6,8 +6,8 @@ import { User } from '@entity/User' import { Contribution } from '@entity/Contribution' -import { testEnvironment, cleanDB, contributionDateFormatter } from '@test/helpers' import { getUserCreation } from './creations' +import { testEnvironment, cleanDB, contributionDateFormatter } from '@test/helpers' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { peterLustig } from '@/seeds/users/peter-lustig' import { userFactory } from '@/seeds/factory/user' diff --git a/backend/src/server/LogError.test.ts b/backend/src/server/LogError.test.ts index b7a067e28..318a477ef 100644 --- a/backend/src/server/LogError.test.ts +++ b/backend/src/server/LogError.test.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/unbound-method */ -import { logger } from '@test/testSetup' import LogError from './LogError' +import { logger } from '@test/testSetup' describe('LogError', () => { it('logs an Error when created', () => { diff --git a/backend/src/util/validate.ts b/backend/src/util/validate.ts index b70c90344..aaadbdd31 100644 --- a/backend/src/util/validate.ts +++ b/backend/src/util/validate.ts @@ -1,9 +1,9 @@ import { Decimal } from 'decimal.js-light' import { getCustomRepository } from '@dbTools/typeorm' import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink' +import { calculateDecay } from './decay' import { TransactionLinkRepository } from '@repository/TransactionLink' import { Decay } from '@model/Decay' -import { calculateDecay } from './decay' import { getLastTransaction } from '@/graphql/resolver/util/getLastTransaction' function isStringBoolean(value: string): boolean { diff --git a/backend/src/util/virtualTransactions.ts b/backend/src/util/virtualTransactions.ts index aea4ebb66..7810ad871 100644 --- a/backend/src/util/virtualTransactions.ts +++ b/backend/src/util/virtualTransactions.ts @@ -2,10 +2,10 @@ import { SaveOptions, RemoveOptions } from '@dbTools/typeorm' import { Transaction as dbTransaction } from '@entity/Transaction' import { Decimal } from 'decimal.js-light' +import { calculateDecay } from './decay' import { Transaction } from '@model/Transaction' import { TransactionTypeId } from '@enum/TransactionTypeId' import { User } from '@model/User' -import { calculateDecay } from './decay' const defaultModelFunctions = { hasId: function (): boolean { From 71266dcc2d3675f2fe6bac12d4a7c466e6493887 Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 31 Mar 2023 07:16:21 +0200 Subject: [PATCH 19/34] Fix linting rules --- .../graphql/resolver/KlicktippResolver.test.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/backend/src/graphql/resolver/KlicktippResolver.test.ts b/backend/src/graphql/resolver/KlicktippResolver.test.ts index 0e64a779f..d7a7e8255 100644 --- a/backend/src/graphql/resolver/KlicktippResolver.test.ts +++ b/backend/src/graphql/resolver/KlicktippResolver.test.ts @@ -1,19 +1,22 @@ -import { cleanDB, resetToken, testEnvironment } from '@test/helpers' -import { logger, i18n as localization } from '@test/testSetup' +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* eslint-disable @typescript-eslint/no-unsafe-call */ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ import { GraphQLError } from 'graphql' import { UserContact } from '@entity/UserContact' import { Event as DbEvent } from '@entity/Event' +import { logger, i18n as localization } from '@test/testSetup' +import { cleanDB, resetToken, testEnvironment } from '@test/helpers' import { login, subscribeNewsletter, unsubscribeNewsletter } from '@/seeds/graphql/mutations' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { userFactory } from '@/seeds/factory/user' import { EventType } from '@/event/Event' -let testEnv: any, mutate: any, query: any, con: any +let testEnv: any, mutate: any, con: any beforeAll(async () => { testEnv = await testEnvironment(logger, localization) mutate = testEnv.mutate - query = testEnv.query con = testEnv.con await cleanDB() }) @@ -24,10 +27,8 @@ afterAll(async () => { }) describe('KlicktippResolver', () => { - let bibi - beforeAll(async () => { - bibi = await userFactory(testEnv, bibiBloxberg) + await userFactory(testEnv, bibiBloxberg) }) afterAll(async () => { From d326f00c0bee44d5306ccbfd0677a3da05d78346 Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 31 Mar 2023 07:28:52 +0200 Subject: [PATCH 20/34] Fix linting --- backend/src/event/EVENT_SUBSCRIBE_NEWSLETTER.ts | 3 ++- backend/src/event/EVENT_UNSUBSCRIBE_NEWSLETTER.ts | 3 ++- .../src/graphql/resolver/CommunityResolver.test.ts | 1 + .../src/graphql/resolver/KlicktippResolver.test.ts | 12 +++++++----- backend/src/graphql/resolver/KlicktippResolver.ts | 2 +- backend/src/middleware/klicktippMiddleware.ts | 3 +-- 6 files changed, 14 insertions(+), 10 deletions(-) diff --git a/backend/src/event/EVENT_SUBSCRIBE_NEWSLETTER.ts b/backend/src/event/EVENT_SUBSCRIBE_NEWSLETTER.ts index f4207d059..a9656b6fa 100644 --- a/backend/src/event/EVENT_SUBSCRIBE_NEWSLETTER.ts +++ b/backend/src/event/EVENT_SUBSCRIBE_NEWSLETTER.ts @@ -1,5 +1,6 @@ -import { User as DbUser } from '@entity/User' import { Event as DbEvent } from '@entity/Event' +import { User as DbUser } from '@entity/User' + import { Event, EventType } from './Event' export const EVENT_SUBSCRIBE_NEWSLETTER = async (user: DbUser): Promise => diff --git a/backend/src/event/EVENT_UNSUBSCRIBE_NEWSLETTER.ts b/backend/src/event/EVENT_UNSUBSCRIBE_NEWSLETTER.ts index 6a6946e3f..1b2561894 100644 --- a/backend/src/event/EVENT_UNSUBSCRIBE_NEWSLETTER.ts +++ b/backend/src/event/EVENT_UNSUBSCRIBE_NEWSLETTER.ts @@ -1,5 +1,6 @@ -import { User as DbUser } from '@entity/User' import { Event as DbEvent } from '@entity/Event' +import { User as DbUser } from '@entity/User' + import { Event, EventType } from './Event' export const EVENT_UNSUBSCRIBE_NEWSLETTER = async (user: DbUser): Promise => diff --git a/backend/src/graphql/resolver/CommunityResolver.test.ts b/backend/src/graphql/resolver/CommunityResolver.test.ts index 2cb27de31..5b4b26cad 100644 --- a/backend/src/graphql/resolver/CommunityResolver.test.ts +++ b/backend/src/graphql/resolver/CommunityResolver.test.ts @@ -8,6 +8,7 @@ import { Community as DbCommunity } from '@entity/Community' import { testEnvironment } from '@test/helpers' + import { getCommunities } from '@/seeds/graphql/queries' let query: any diff --git a/backend/src/graphql/resolver/KlicktippResolver.test.ts b/backend/src/graphql/resolver/KlicktippResolver.test.ts index d7a7e8255..02b3e0492 100644 --- a/backend/src/graphql/resolver/KlicktippResolver.test.ts +++ b/backend/src/graphql/resolver/KlicktippResolver.test.ts @@ -2,15 +2,17 @@ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-call */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ -import { GraphQLError } from 'graphql' -import { UserContact } from '@entity/UserContact' import { Event as DbEvent } from '@entity/Event' -import { logger, i18n as localization } from '@test/testSetup' +import { UserContact } from '@entity/UserContact' +import { GraphQLError } from 'graphql' + import { cleanDB, resetToken, testEnvironment } from '@test/helpers' +import { logger, i18n as localization } from '@test/testSetup' + +import { EventType } from '@/event/Event' +import { userFactory } from '@/seeds/factory/user' import { login, subscribeNewsletter, unsubscribeNewsletter } from '@/seeds/graphql/mutations' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' -import { userFactory } from '@/seeds/factory/user' -import { EventType } from '@/event/Event' let testEnv: any, mutate: any, con: any diff --git a/backend/src/graphql/resolver/KlicktippResolver.ts b/backend/src/graphql/resolver/KlicktippResolver.ts index e03e81440..03b591c4d 100644 --- a/backend/src/graphql/resolver/KlicktippResolver.ts +++ b/backend/src/graphql/resolver/KlicktippResolver.ts @@ -1,8 +1,8 @@ import { Resolver, Authorized, Mutation, Ctx } from 'type-graphql' import { unsubscribe, klicktippSignIn } from '@/apis/KlicktippController' -import { EVENT_UNSUBSCRIBE_NEWSLETTER, EVENT_SUBSCRIBE_NEWSLETTER } from '@/event/Event' import { RIGHTS } from '@/auth/RIGHTS' +import { EVENT_UNSUBSCRIBE_NEWSLETTER, EVENT_SUBSCRIBE_NEWSLETTER } from '@/event/Event' import { Context, getUser } from '@/server/context' @Resolver() diff --git a/backend/src/middleware/klicktippMiddleware.ts b/backend/src/middleware/klicktippMiddleware.ts index 82391a614..cc0335c09 100644 --- a/backend/src/middleware/klicktippMiddleware.ts +++ b/backend/src/middleware/klicktippMiddleware.ts @@ -6,8 +6,7 @@ import { MiddlewareFn } from 'type-graphql' import { KlickTipp } from '@model/KlickTipp' -import { /* klicktippSignIn, */ getKlickTippUser } from '@/apis/KlicktippController' -import CONFIG from '@/config' +import { getKlickTippUser } from '@/apis/KlicktippController' import { klickTippLogger as logger } from '@/server/logger' // export const klicktippRegistrationMiddleware: MiddlewareFn = async ( From 51d572f0b795efa54f771a6d19db8675a1efa5cd Mon Sep 17 00:00:00 2001 From: elweyn Date: Mon, 3 Apr 2023 14:58:26 +0200 Subject: [PATCH 21/34] Implement callKlickTippAPI --- backend/src/apis/KlicktippController.ts | 178 ++++++++++++++---------- 1 file changed, 103 insertions(+), 75 deletions(-) diff --git a/backend/src/apis/KlicktippController.ts b/backend/src/apis/KlicktippController.ts index 1278b0d9c..d414bb9ec 100644 --- a/backend/src/apis/KlicktippController.ts +++ b/backend/src/apis/KlicktippController.ts @@ -4,107 +4,135 @@ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ +/* eslint-disable @typescript-eslint/restrict-template-expressions */ import CONFIG from '@/config' +import LogError from '@/server/LogError' // eslint-disable-next-line import/no-relative-parent-imports import KlicktippConnector from 'klicktipp-api' const klicktippConnector = new KlicktippConnector() -export const klicktippSignIn = async ( +const callKlickTippAPI = (callback: (arg0: any) => any, args: any) => { + if (!CONFIG.KLICKTIPP) { + return true + } + return callback(args) +} + +export const klicktippSignIn = ( email: string, language: string, firstName?: string, lastName?: string, ): Promise => { - if (!CONFIG.KLICKTIPP) { - return true - } - const fields = { - fieldFirstName: firstName, - fieldLastName: lastName, - } - const apiKey = language === 'de' ? CONFIG.KLICKTIPP_APIKEY_DE : CONFIG.KLICKTIPP_APIKEY_EN - const result = await klicktippConnector.signin(apiKey, email, fields) - return result + return callKlickTippAPI( + ({ fieldFirstName, fieldLastName, language, email }) => { + const fields = { + fieldFirstName, + fieldLastName, + } + const apiKey = language === 'de' ? CONFIG.KLICKTIPP_APIKEY_DE : CONFIG.KLICKTIPP_APIKEY_EN + return klicktippConnector.signin(apiKey, email, fields) + }, + { + fieldFirstName: firstName, + fieldLastName: lastName, + language, + email, + }, + ) } -export const signout = async (email: string, language: string): Promise => { - if (!CONFIG.KLICKTIPP) { - return true - } - const apiKey = language === 'de' ? CONFIG.KLICKTIPP_APIKEY_DE : CONFIG.KLICKTIPP_APIKEY_EN - const result = await klicktippConnector.signoff(apiKey, email) - return result +export const signout = (email: string, language: string): Promise => { + return callKlickTippAPI( + async ({ language, email }) => { + const apiKey = language === 'de' ? CONFIG.KLICKTIPP_APIKEY_DE : CONFIG.KLICKTIPP_APIKEY_EN + const result = await klicktippConnector.signoff(apiKey, email) + return result + }, + { + email, + language, + }, + ) } -export const unsubscribe = async (email: string): Promise => { - if (!CONFIG.KLICKTIPP) { - return true - } - const isLogin = await loginKlicktippUser() - if (isLogin) { - return await klicktippConnector.unsubscribe(email) - } - throw new Error(`Could not unsubscribe ${email}`) +export const unsubscribe = (email: string): Promise => { + return callKlickTippAPI( + async ({ email }) => { + const isLogin = await loginKlicktippUser() + if (isLogin) { + return klicktippConnector.unsubscribe(email) + } + throw new LogError(`Could not unsubscribe ${email}`) + }, + { + email, + }, + ) } -export const getKlickTippUser = async (email: string): Promise => { - if (!CONFIG.KLICKTIPP) { - return true - } - const isLogin = await loginKlicktippUser() - if (isLogin) { - const subscriberId = await klicktippConnector.subscriberSearch(email) - const result = await klicktippConnector.subscriberGet(subscriberId) - return result - } - return false +export const getKlickTippUser = (email: string): Promise => { + return callKlickTippAPI( + async ({ email }) => { + const isLogin = await loginKlicktippUser() + if (isLogin) { + const subscriberId = await klicktippConnector.subscriberSearch(email) + return klicktippConnector.subscriberGet(subscriberId) + } + throw new LogError(`Could not get subscriber ${email}`) + }, + { + email, + }, + ) } -export const loginKlicktippUser = async (): Promise => { - if (!CONFIG.KLICKTIPP) { - return true - } - return await klicktippConnector.login(CONFIG.KLICKTIPP_USER, CONFIG.KLICKTIPP_PASSWORD) +export const loginKlicktippUser = (): Promise => { + return callKlickTippAPI(() => { + return klicktippConnector.login(CONFIG.KLICKTIPP_USER, CONFIG.KLICKTIPP_PASSWORD) + }, {}) } -export const logoutKlicktippUser = async (): Promise => { - if (!CONFIG.KLICKTIPP) { - return true - } - return await klicktippConnector.logout() +export const logoutKlicktippUser = (): Promise => { + return callKlickTippAPI(() => { + return klicktippConnector.logout() + }, {}) } -export const untagUser = async (email: string, tagId: string): Promise => { - if (!CONFIG.KLICKTIPP) { - return true - } - const isLogin = await loginKlicktippUser() - if (isLogin) { - return await klicktippConnector.untag(email, tagId) - } - return false +export const untagUser = (email: string, tagId: string): Promise => { + return callKlickTippAPI( + async ({ email, tagId }) => { + const isLogin = await loginKlicktippUser() + if (isLogin) { + return await klicktippConnector.untag(email, tagId) + } + throw new LogError(`Could not untag ${email}`) + }, + { email, tagId }, + ) } -export const tagUser = async (email: string, tagIds: string): Promise => { - if (!CONFIG.KLICKTIPP) { - return true - } - const isLogin = await loginKlicktippUser() - if (isLogin) { - return await klicktippConnector.tag(email, tagIds) - } - return false +export const tagUser = (email: string, tagIds: string): Promise => { + return callKlickTippAPI( + async ({ email, tagIds }) => { + const isLogin = await loginKlicktippUser() + if (isLogin) { + return klicktippConnector.tag(email, tagIds) + } + throw new LogError(`Could not tag ${email}`) + }, + { email, tagIds }, + ) } -export const getKlicktippTagMap = async () => { - if (!CONFIG.KLICKTIPP) { - return '' - } - const isLogin = await loginKlicktippUser() - if (isLogin) { - return await klicktippConnector.tagIndex() - } - return '' +export const getKlicktippTagMap = (): Promise => { + return callKlickTippAPI(async () => { + const isLogin = await loginKlicktippUser() + if (isLogin) { + return klicktippConnector.tagIndex() + } + throw new LogError(`Could not get tagIndexes`) + }, {}) } From 7df35f057b792cc25ca95a3691b86527878096c0 Mon Sep 17 00:00:00 2001 From: elweyn Date: Tue, 4 Apr 2023 17:07:01 +0200 Subject: [PATCH 22/34] Revert "Implement callKlickTippAPI" This reverts commit 51d572f0b795efa54f771a6d19db8675a1efa5cd. --- backend/src/apis/KlicktippController.ts | 178 ++++++++++-------------- 1 file changed, 75 insertions(+), 103 deletions(-) diff --git a/backend/src/apis/KlicktippController.ts b/backend/src/apis/KlicktippController.ts index d414bb9ec..1278b0d9c 100644 --- a/backend/src/apis/KlicktippController.ts +++ b/backend/src/apis/KlicktippController.ts @@ -4,135 +4,107 @@ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -/* eslint-disable @typescript-eslint/restrict-template-expressions */ import CONFIG from '@/config' -import LogError from '@/server/LogError' // eslint-disable-next-line import/no-relative-parent-imports import KlicktippConnector from 'klicktipp-api' const klicktippConnector = new KlicktippConnector() -const callKlickTippAPI = (callback: (arg0: any) => any, args: any) => { - if (!CONFIG.KLICKTIPP) { - return true - } - return callback(args) -} - -export const klicktippSignIn = ( +export const klicktippSignIn = async ( email: string, language: string, firstName?: string, lastName?: string, ): Promise => { - return callKlickTippAPI( - ({ fieldFirstName, fieldLastName, language, email }) => { - const fields = { - fieldFirstName, - fieldLastName, - } - const apiKey = language === 'de' ? CONFIG.KLICKTIPP_APIKEY_DE : CONFIG.KLICKTIPP_APIKEY_EN - return klicktippConnector.signin(apiKey, email, fields) - }, - { - fieldFirstName: firstName, - fieldLastName: lastName, - language, - email, - }, - ) + if (!CONFIG.KLICKTIPP) { + return true + } + const fields = { + fieldFirstName: firstName, + fieldLastName: lastName, + } + const apiKey = language === 'de' ? CONFIG.KLICKTIPP_APIKEY_DE : CONFIG.KLICKTIPP_APIKEY_EN + const result = await klicktippConnector.signin(apiKey, email, fields) + return result } -export const signout = (email: string, language: string): Promise => { - return callKlickTippAPI( - async ({ language, email }) => { - const apiKey = language === 'de' ? CONFIG.KLICKTIPP_APIKEY_DE : CONFIG.KLICKTIPP_APIKEY_EN - const result = await klicktippConnector.signoff(apiKey, email) - return result - }, - { - email, - language, - }, - ) +export const signout = async (email: string, language: string): Promise => { + if (!CONFIG.KLICKTIPP) { + return true + } + const apiKey = language === 'de' ? CONFIG.KLICKTIPP_APIKEY_DE : CONFIG.KLICKTIPP_APIKEY_EN + const result = await klicktippConnector.signoff(apiKey, email) + return result } -export const unsubscribe = (email: string): Promise => { - return callKlickTippAPI( - async ({ email }) => { - const isLogin = await loginKlicktippUser() - if (isLogin) { - return klicktippConnector.unsubscribe(email) - } - throw new LogError(`Could not unsubscribe ${email}`) - }, - { - email, - }, - ) +export const unsubscribe = async (email: string): Promise => { + if (!CONFIG.KLICKTIPP) { + return true + } + const isLogin = await loginKlicktippUser() + if (isLogin) { + return await klicktippConnector.unsubscribe(email) + } + throw new Error(`Could not unsubscribe ${email}`) } -export const getKlickTippUser = (email: string): Promise => { - return callKlickTippAPI( - async ({ email }) => { - const isLogin = await loginKlicktippUser() - if (isLogin) { - const subscriberId = await klicktippConnector.subscriberSearch(email) - return klicktippConnector.subscriberGet(subscriberId) - } - throw new LogError(`Could not get subscriber ${email}`) - }, - { - email, - }, - ) +export const getKlickTippUser = async (email: string): Promise => { + if (!CONFIG.KLICKTIPP) { + return true + } + const isLogin = await loginKlicktippUser() + if (isLogin) { + const subscriberId = await klicktippConnector.subscriberSearch(email) + const result = await klicktippConnector.subscriberGet(subscriberId) + return result + } + return false } -export const loginKlicktippUser = (): Promise => { - return callKlickTippAPI(() => { - return klicktippConnector.login(CONFIG.KLICKTIPP_USER, CONFIG.KLICKTIPP_PASSWORD) - }, {}) +export const loginKlicktippUser = async (): Promise => { + if (!CONFIG.KLICKTIPP) { + return true + } + return await klicktippConnector.login(CONFIG.KLICKTIPP_USER, CONFIG.KLICKTIPP_PASSWORD) } -export const logoutKlicktippUser = (): Promise => { - return callKlickTippAPI(() => { - return klicktippConnector.logout() - }, {}) +export const logoutKlicktippUser = async (): Promise => { + if (!CONFIG.KLICKTIPP) { + return true + } + return await klicktippConnector.logout() } -export const untagUser = (email: string, tagId: string): Promise => { - return callKlickTippAPI( - async ({ email, tagId }) => { - const isLogin = await loginKlicktippUser() - if (isLogin) { - return await klicktippConnector.untag(email, tagId) - } - throw new LogError(`Could not untag ${email}`) - }, - { email, tagId }, - ) +export const untagUser = async (email: string, tagId: string): Promise => { + if (!CONFIG.KLICKTIPP) { + return true + } + const isLogin = await loginKlicktippUser() + if (isLogin) { + return await klicktippConnector.untag(email, tagId) + } + return false } -export const tagUser = (email: string, tagIds: string): Promise => { - return callKlickTippAPI( - async ({ email, tagIds }) => { - const isLogin = await loginKlicktippUser() - if (isLogin) { - return klicktippConnector.tag(email, tagIds) - } - throw new LogError(`Could not tag ${email}`) - }, - { email, tagIds }, - ) +export const tagUser = async (email: string, tagIds: string): Promise => { + if (!CONFIG.KLICKTIPP) { + return true + } + const isLogin = await loginKlicktippUser() + if (isLogin) { + return await klicktippConnector.tag(email, tagIds) + } + return false } -export const getKlicktippTagMap = (): Promise => { - return callKlickTippAPI(async () => { - const isLogin = await loginKlicktippUser() - if (isLogin) { - return klicktippConnector.tagIndex() - } - throw new LogError(`Could not get tagIndexes`) - }, {}) +export const getKlicktippTagMap = async () => { + if (!CONFIG.KLICKTIPP) { + return '' + } + const isLogin = await loginKlicktippUser() + if (isLogin) { + return await klicktippConnector.tagIndex() + } + return '' } From b00c518863e81e30291eaf10d285efacec1c4b65 Mon Sep 17 00:00:00 2001 From: elweyn Date: Tue, 4 Apr 2023 17:09:32 +0200 Subject: [PATCH 23/34] Implement callKlickTippAPI --- backend/src/apis/KlicktippController.ts | 36 +++++++------------------ 1 file changed, 9 insertions(+), 27 deletions(-) diff --git a/backend/src/apis/KlicktippController.ts b/backend/src/apis/KlicktippController.ts index 1278b0d9c..a0fc6e06f 100644 --- a/backend/src/apis/KlicktippController.ts +++ b/backend/src/apis/KlicktippController.ts @@ -17,9 +17,7 @@ export const klicktippSignIn = async ( firstName?: string, lastName?: string, ): Promise => { - if (!CONFIG.KLICKTIPP) { - return true - } + if (!CONFIG.KLICKTIPP) return true const fields = { fieldFirstName: firstName, fieldLastName: lastName, @@ -30,18 +28,14 @@ export const klicktippSignIn = async ( } export const signout = async (email: string, language: string): Promise => { - if (!CONFIG.KLICKTIPP) { - return true - } + if (!CONFIG.KLICKTIPP) return true const apiKey = language === 'de' ? CONFIG.KLICKTIPP_APIKEY_DE : CONFIG.KLICKTIPP_APIKEY_EN const result = await klicktippConnector.signoff(apiKey, email) return result } export const unsubscribe = async (email: string): Promise => { - if (!CONFIG.KLICKTIPP) { - return true - } + if (!CONFIG.KLICKTIPP) return true const isLogin = await loginKlicktippUser() if (isLogin) { return await klicktippConnector.unsubscribe(email) @@ -50,9 +44,7 @@ export const unsubscribe = async (email: string): Promise => { } export const getKlickTippUser = async (email: string): Promise => { - if (!CONFIG.KLICKTIPP) { - return true - } + if (!CONFIG.KLICKTIPP) return true const isLogin = await loginKlicktippUser() if (isLogin) { const subscriberId = await klicktippConnector.subscriberSearch(email) @@ -63,23 +55,17 @@ export const getKlickTippUser = async (email: string): Promise => { } export const loginKlicktippUser = async (): Promise => { - if (!CONFIG.KLICKTIPP) { - return true - } + if (!CONFIG.KLICKTIPP) return true return await klicktippConnector.login(CONFIG.KLICKTIPP_USER, CONFIG.KLICKTIPP_PASSWORD) } export const logoutKlicktippUser = async (): Promise => { - if (!CONFIG.KLICKTIPP) { - return true - } + if (!CONFIG.KLICKTIPP) return true return await klicktippConnector.logout() } export const untagUser = async (email: string, tagId: string): Promise => { - if (!CONFIG.KLICKTIPP) { - return true - } + if (!CONFIG.KLICKTIPP) return true const isLogin = await loginKlicktippUser() if (isLogin) { return await klicktippConnector.untag(email, tagId) @@ -88,9 +74,7 @@ export const untagUser = async (email: string, tagId: string): Promise } export const tagUser = async (email: string, tagIds: string): Promise => { - if (!CONFIG.KLICKTIPP) { - return true - } + if (!CONFIG.KLICKTIPP) return true const isLogin = await loginKlicktippUser() if (isLogin) { return await klicktippConnector.tag(email, tagIds) @@ -99,9 +83,7 @@ export const tagUser = async (email: string, tagIds: string): Promise = } export const getKlicktippTagMap = async () => { - if (!CONFIG.KLICKTIPP) { - return '' - } + if (!CONFIG.KLICKTIPP) return true const isLogin = await loginKlicktippUser() if (isLogin) { return await klicktippConnector.tagIndex() From 1505d9abf06163e3d3535c481148d9910e765bef Mon Sep 17 00:00:00 2001 From: elweyn Date: Wed, 5 Apr 2023 10:43:42 +0200 Subject: [PATCH 24/34] Change ACTION_NEWSLETTER to NEWSLETTER_ACTION --- ...UBSCRIBE_NEWSLETTER.ts => EVENT_NEWSLETTER_SUBSCRIBE.ts} | 4 ++-- ...SCRIBE_NEWSLETTER.ts => EVENT_NEWSLETTER_UNSUBSCRIBE.ts} | 4 ++-- backend/src/event/Event.ts | 4 ++-- backend/src/event/EventType.ts | 4 ++-- backend/src/graphql/resolver/KlicktippResolver.ts | 6 +++--- 5 files changed, 11 insertions(+), 11 deletions(-) rename backend/src/event/{EVENT_SUBSCRIBE_NEWSLETTER.ts => EVENT_NEWSLETTER_SUBSCRIBE.ts} (56%) rename backend/src/event/{EVENT_UNSUBSCRIBE_NEWSLETTER.ts => EVENT_NEWSLETTER_UNSUBSCRIBE.ts} (56%) diff --git a/backend/src/event/EVENT_SUBSCRIBE_NEWSLETTER.ts b/backend/src/event/EVENT_NEWSLETTER_SUBSCRIBE.ts similarity index 56% rename from backend/src/event/EVENT_SUBSCRIBE_NEWSLETTER.ts rename to backend/src/event/EVENT_NEWSLETTER_SUBSCRIBE.ts index a9656b6fa..51fb3d186 100644 --- a/backend/src/event/EVENT_SUBSCRIBE_NEWSLETTER.ts +++ b/backend/src/event/EVENT_NEWSLETTER_SUBSCRIBE.ts @@ -3,5 +3,5 @@ import { User as DbUser } from '@entity/User' import { Event, EventType } from './Event' -export const EVENT_SUBSCRIBE_NEWSLETTER = async (user: DbUser): Promise => - Event(EventType.SUBSCRIBE_NEWSLETTER, user, user).save() +export const EVENT_NEWSLETTER_SUBSCRIBE = async (user: DbUser): Promise => + Event(EventType.NEWSLETTER_SUBSCRIBE, user, user).save() diff --git a/backend/src/event/EVENT_UNSUBSCRIBE_NEWSLETTER.ts b/backend/src/event/EVENT_NEWSLETTER_UNSUBSCRIBE.ts similarity index 56% rename from backend/src/event/EVENT_UNSUBSCRIBE_NEWSLETTER.ts rename to backend/src/event/EVENT_NEWSLETTER_UNSUBSCRIBE.ts index 1b2561894..4e4d3e9e4 100644 --- a/backend/src/event/EVENT_UNSUBSCRIBE_NEWSLETTER.ts +++ b/backend/src/event/EVENT_NEWSLETTER_UNSUBSCRIBE.ts @@ -3,5 +3,5 @@ import { User as DbUser } from '@entity/User' import { Event, EventType } from './Event' -export const EVENT_UNSUBSCRIBE_NEWSLETTER = async (user: DbUser): Promise => - Event(EventType.UNSUBSCRIBE_NEWSLETTER, user, user).save() +export const EVENT_NEWSLETTER_UNSUBSCRIBE = async (user: DbUser): Promise => + Event(EventType.NEWSLETTER_UNSUBSCRIBE, user, user).save() diff --git a/backend/src/event/Event.ts b/backend/src/event/Event.ts index 05c0a78a9..2064a91f0 100644 --- a/backend/src/event/Event.ts +++ b/backend/src/event/Event.ts @@ -58,13 +58,13 @@ export { EVENT_EMAIL_ACCOUNT_MULTIREGISTRATION } from './EVENT_EMAIL_ACCOUNT_MUL export { EVENT_EMAIL_ADMIN_CONFIRMATION } from './EVENT_EMAIL_ADMIN_CONFIRMATION' export { EVENT_EMAIL_CONFIRMATION } from './EVENT_EMAIL_CONFIRMATION' export { EVENT_EMAIL_FORGOT_PASSWORD } from './EVENT_EMAIL_FORGOT_PASSWORD' -export { EVENT_SUBSCRIBE_NEWSLETTER } from './EVENT_SUBSCRIBE_NEWSLETTER' +export { EVENT_NEWSLETTER_SUBSCRIBE } from './EVENT_NEWSLETTER_SUBSCRIBE' export { EVENT_TRANSACTION_SEND } from './EVENT_TRANSACTION_SEND' export { EVENT_TRANSACTION_RECEIVE } from './EVENT_TRANSACTION_RECEIVE' export { EVENT_TRANSACTION_LINK_CREATE } from './EVENT_TRANSACTION_LINK_CREATE' export { EVENT_TRANSACTION_LINK_DELETE } from './EVENT_TRANSACTION_LINK_DELETE' export { EVENT_TRANSACTION_LINK_REDEEM } from './EVENT_TRANSACTION_LINK_REDEEM' -export { EVENT_UNSUBSCRIBE_NEWSLETTER } from './EVENT_UNSUBSCRIBE_NEWSLETTER' +export { EVENT_NEWSLETTER_UNSUBSCRIBE } from './EVENT_NEWSLETTER_UNSUBSCRIBE' export { EVENT_USER_ACTIVATE_ACCOUNT } from './EVENT_USER_ACTIVATE_ACCOUNT' export { EVENT_USER_INFO_UPDATE } from './EVENT_USER_INFO_UPDATE' export { EVENT_USER_LOGIN } from './EVENT_USER_LOGIN' diff --git a/backend/src/event/EventType.ts b/backend/src/event/EventType.ts index 137bbfa09..b2b6f9322 100644 --- a/backend/src/event/EventType.ts +++ b/backend/src/event/EventType.ts @@ -21,13 +21,13 @@ export enum EventType { EMAIL_ADMIN_CONFIRMATION = 'EMAIL_ADMIN_CONFIRMATION', EMAIL_CONFIRMATION = 'EMAIL_CONFIRMATION', EMAIL_FORGOT_PASSWORD = 'EMAIL_FORGOT_PASSWORD', - SUBSCRIBE_NEWSLETTER = 'SUBSCRIBE_NEWSLETTER', + NEWSLETTER_SUBSCRIBE = 'NEWSLETTER_SUBSCRIBE', + NEWSLETTER_UNSUBSCRIBE = 'NEWSLETTER_UNSUBSCRIBE', TRANSACTION_SEND = 'TRANSACTION_SEND', TRANSACTION_RECEIVE = 'TRANSACTION_RECEIVE', TRANSACTION_LINK_CREATE = 'TRANSACTION_LINK_CREATE', TRANSACTION_LINK_DELETE = 'TRANSACTION_LINK_DELETE', TRANSACTION_LINK_REDEEM = 'TRANSACTION_LINK_REDEEM', - UNSUBSCRIBE_NEWSLETTER = 'UNSUBSCRIBE_NEWSLETTER', USER_ACTIVATE_ACCOUNT = 'ACTIVATE_ACCOUNT', USER_INFO_UPDATE = 'USER_INFO_UPDATE', USER_LOGIN = 'USER_LOGIN', diff --git a/backend/src/graphql/resolver/KlicktippResolver.ts b/backend/src/graphql/resolver/KlicktippResolver.ts index 03b591c4d..cb09822cf 100644 --- a/backend/src/graphql/resolver/KlicktippResolver.ts +++ b/backend/src/graphql/resolver/KlicktippResolver.ts @@ -2,7 +2,7 @@ import { Resolver, Authorized, Mutation, Ctx } from 'type-graphql' import { unsubscribe, klicktippSignIn } from '@/apis/KlicktippController' import { RIGHTS } from '@/auth/RIGHTS' -import { EVENT_UNSUBSCRIBE_NEWSLETTER, EVENT_SUBSCRIBE_NEWSLETTER } from '@/event/Event' +import { EVENT_NEWSLETTER_SUBSCRIBE, EVENT_NEWSLETTER_UNSUBSCRIBE } from '@/event/Event' import { Context, getUser } from '@/server/context' @Resolver() @@ -11,7 +11,7 @@ export class KlicktippResolver { @Mutation(() => Boolean) async unsubscribeNewsletter(@Ctx() context: Context): Promise { const user = getUser(context) - await EVENT_UNSUBSCRIBE_NEWSLETTER(user) + await EVENT_NEWSLETTER_UNSUBSCRIBE(user) return unsubscribe(user.emailContact.email) } @@ -19,7 +19,7 @@ export class KlicktippResolver { @Mutation(() => Boolean) async subscribeNewsletter(@Ctx() context: Context): Promise { const user = getUser(context) - await EVENT_SUBSCRIBE_NEWSLETTER(user) + await EVENT_NEWSLETTER_SUBSCRIBE(user) return klicktippSignIn(user.emailContact.email, user.language) } } From 50574ece6b5c364185d8de89e363653a2ec52e5a Mon Sep 17 00:00:00 2001 From: Hannes Heine Date: Thu, 6 Apr 2023 14:52:58 +0200 Subject: [PATCH 25/34] Update backend/src/graphql/resolver/KlicktippResolver.test.ts Co-authored-by: Ulf Gebhardt --- backend/src/graphql/resolver/KlicktippResolver.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/KlicktippResolver.test.ts b/backend/src/graphql/resolver/KlicktippResolver.test.ts index 02b3e0492..79bc2f218 100644 --- a/backend/src/graphql/resolver/KlicktippResolver.test.ts +++ b/backend/src/graphql/resolver/KlicktippResolver.test.ts @@ -119,7 +119,7 @@ describe('KlicktippResolver', () => { expect(isUnsubscribed).toEqual(true) }) - it('stores the UNSUBSCRIBE_NEWSLETTER event in the database', async () => { + it('stores the NEWSLETTER_UNSUBSCRIBE event in the database', async () => { const userConatct = await UserContact.findOneOrFail( { email: 'bibi@bloxberg.de' }, { relations: ['user'] }, From 3990135c7a02dca9e9b6f7e27d4027f6fac92b35 Mon Sep 17 00:00:00 2001 From: Hannes Heine Date: Thu, 6 Apr 2023 14:53:09 +0200 Subject: [PATCH 26/34] Update backend/src/graphql/resolver/KlicktippResolver.test.ts Co-authored-by: Ulf Gebhardt --- backend/src/graphql/resolver/KlicktippResolver.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/KlicktippResolver.test.ts b/backend/src/graphql/resolver/KlicktippResolver.test.ts index 79bc2f218..62dee84b0 100644 --- a/backend/src/graphql/resolver/KlicktippResolver.test.ts +++ b/backend/src/graphql/resolver/KlicktippResolver.test.ts @@ -70,7 +70,7 @@ describe('KlicktippResolver', () => { expect(isSubscribed).toEqual(true) }) - it('stores the SUBSCRIBE_NEWSLETTER event in the database', async () => { + it('stores the NEWSLETTER_SUBSCRIBE event in the database', async () => { const userConatct = await UserContact.findOneOrFail( { email: 'bibi@bloxberg.de' }, { relations: ['user'] }, From f36bc61a7024b55bdc357b859a21d5fbc5a47009 Mon Sep 17 00:00:00 2001 From: Hannes Heine Date: Thu, 6 Apr 2023 14:53:24 +0200 Subject: [PATCH 27/34] Update backend/src/graphql/resolver/KlicktippResolver.test.ts Co-authored-by: Ulf Gebhardt --- backend/src/graphql/resolver/KlicktippResolver.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/KlicktippResolver.test.ts b/backend/src/graphql/resolver/KlicktippResolver.test.ts index 62dee84b0..322131480 100644 --- a/backend/src/graphql/resolver/KlicktippResolver.test.ts +++ b/backend/src/graphql/resolver/KlicktippResolver.test.ts @@ -126,7 +126,7 @@ describe('KlicktippResolver', () => { ) await expect(DbEvent.find()).resolves.toContainEqual( expect.objectContaining({ - type: EventType.UNSUBSCRIBE_NEWSLETTER, + type: EventType.NEWSLETTER_UNSUBSCRIBE, affectedUserId: userConatct.user.id, actingUserId: userConatct.user.id, }), From 7d12ecbe9845570e3f0f71360af65aad4cbd98a1 Mon Sep 17 00:00:00 2001 From: Hannes Heine Date: Thu, 6 Apr 2023 14:53:35 +0200 Subject: [PATCH 28/34] Update backend/src/graphql/resolver/KlicktippResolver.test.ts Co-authored-by: Ulf Gebhardt --- backend/src/graphql/resolver/KlicktippResolver.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/KlicktippResolver.test.ts b/backend/src/graphql/resolver/KlicktippResolver.test.ts index 322131480..20669d242 100644 --- a/backend/src/graphql/resolver/KlicktippResolver.test.ts +++ b/backend/src/graphql/resolver/KlicktippResolver.test.ts @@ -77,7 +77,7 @@ describe('KlicktippResolver', () => { ) await expect(DbEvent.find()).resolves.toContainEqual( expect.objectContaining({ - type: EventType.SUBSCRIBE_NEWSLETTER, + type: EventType.NEWSLETTER_SUBSCRIBE, affectedUserId: userConatct.user.id, actingUserId: userConatct.user.id, }), From 525a560832a3abf498a5e78adbbc19111950fb39 Mon Sep 17 00:00:00 2001 From: Hannes Heine Date: Thu, 6 Apr 2023 14:53:51 +0200 Subject: [PATCH 29/34] Update backend/src/event/Event.ts Co-authored-by: Ulf Gebhardt --- backend/src/event/Event.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/event/Event.ts b/backend/src/event/Event.ts index 2064a91f0..4bebac1c0 100644 --- a/backend/src/event/Event.ts +++ b/backend/src/event/Event.ts @@ -59,12 +59,12 @@ export { EVENT_EMAIL_ADMIN_CONFIRMATION } from './EVENT_EMAIL_ADMIN_CONFIRMATION export { EVENT_EMAIL_CONFIRMATION } from './EVENT_EMAIL_CONFIRMATION' export { EVENT_EMAIL_FORGOT_PASSWORD } from './EVENT_EMAIL_FORGOT_PASSWORD' export { EVENT_NEWSLETTER_SUBSCRIBE } from './EVENT_NEWSLETTER_SUBSCRIBE' +export { EVENT_NEWSLETTER_UNSUBSCRIBE } from './EVENT_NEWSLETTER_UNSUBSCRIBE' export { EVENT_TRANSACTION_SEND } from './EVENT_TRANSACTION_SEND' export { EVENT_TRANSACTION_RECEIVE } from './EVENT_TRANSACTION_RECEIVE' export { EVENT_TRANSACTION_LINK_CREATE } from './EVENT_TRANSACTION_LINK_CREATE' export { EVENT_TRANSACTION_LINK_DELETE } from './EVENT_TRANSACTION_LINK_DELETE' export { EVENT_TRANSACTION_LINK_REDEEM } from './EVENT_TRANSACTION_LINK_REDEEM' -export { EVENT_NEWSLETTER_UNSUBSCRIBE } from './EVENT_NEWSLETTER_UNSUBSCRIBE' export { EVENT_USER_ACTIVATE_ACCOUNT } from './EVENT_USER_ACTIVATE_ACCOUNT' export { EVENT_USER_INFO_UPDATE } from './EVENT_USER_INFO_UPDATE' export { EVENT_USER_LOGIN } from './EVENT_USER_LOGIN' From d9e8247b3c0d6249b9a307d30a29c2afafb441e0 Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 6 Apr 2023 15:12:08 +0200 Subject: [PATCH 30/34] Fix event no-cycle. --- backend/src/event/EVENT_NEWSLETTER_SUBSCRIBE.ts | 3 ++- backend/src/event/EVENT_NEWSLETTER_UNSUBSCRIBE.ts | 3 ++- backend/src/graphql/resolver/KlicktippResolver.test.ts | 3 ++- backend/src/graphql/resolver/KlicktippResolver.ts | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/backend/src/event/EVENT_NEWSLETTER_SUBSCRIBE.ts b/backend/src/event/EVENT_NEWSLETTER_SUBSCRIBE.ts index 51fb3d186..717bb8296 100644 --- a/backend/src/event/EVENT_NEWSLETTER_SUBSCRIBE.ts +++ b/backend/src/event/EVENT_NEWSLETTER_SUBSCRIBE.ts @@ -1,7 +1,8 @@ import { Event as DbEvent } from '@entity/Event' import { User as DbUser } from '@entity/User' -import { Event, EventType } from './Event' +import { Event } from './Event' +import { EventType } from './EventType' export const EVENT_NEWSLETTER_SUBSCRIBE = async (user: DbUser): Promise => Event(EventType.NEWSLETTER_SUBSCRIBE, user, user).save() diff --git a/backend/src/event/EVENT_NEWSLETTER_UNSUBSCRIBE.ts b/backend/src/event/EVENT_NEWSLETTER_UNSUBSCRIBE.ts index 4e4d3e9e4..f8adc69d1 100644 --- a/backend/src/event/EVENT_NEWSLETTER_UNSUBSCRIBE.ts +++ b/backend/src/event/EVENT_NEWSLETTER_UNSUBSCRIBE.ts @@ -1,7 +1,8 @@ import { Event as DbEvent } from '@entity/Event' import { User as DbUser } from '@entity/User' -import { Event, EventType } from './Event' +import { Event } from './Event' +import { EventType } from './EventType' export const EVENT_NEWSLETTER_UNSUBSCRIBE = async (user: DbUser): Promise => Event(EventType.NEWSLETTER_UNSUBSCRIBE, user, user).save() diff --git a/backend/src/graphql/resolver/KlicktippResolver.test.ts b/backend/src/graphql/resolver/KlicktippResolver.test.ts index 20669d242..6a2250bc9 100644 --- a/backend/src/graphql/resolver/KlicktippResolver.test.ts +++ b/backend/src/graphql/resolver/KlicktippResolver.test.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-unsafe-argument */ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-call */ @@ -9,7 +10,7 @@ import { GraphQLError } from 'graphql' import { cleanDB, resetToken, testEnvironment } from '@test/helpers' import { logger, i18n as localization } from '@test/testSetup' -import { EventType } from '@/event/Event' +import { EventType } from '@/event/Events' import { userFactory } from '@/seeds/factory/user' import { login, subscribeNewsletter, unsubscribeNewsletter } from '@/seeds/graphql/mutations' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' diff --git a/backend/src/graphql/resolver/KlicktippResolver.ts b/backend/src/graphql/resolver/KlicktippResolver.ts index cb09822cf..6875abcc5 100644 --- a/backend/src/graphql/resolver/KlicktippResolver.ts +++ b/backend/src/graphql/resolver/KlicktippResolver.ts @@ -2,7 +2,7 @@ import { Resolver, Authorized, Mutation, Ctx } from 'type-graphql' import { unsubscribe, klicktippSignIn } from '@/apis/KlicktippController' import { RIGHTS } from '@/auth/RIGHTS' -import { EVENT_NEWSLETTER_SUBSCRIBE, EVENT_NEWSLETTER_UNSUBSCRIBE } from '@/event/Event' +import { EVENT_NEWSLETTER_SUBSCRIBE, EVENT_NEWSLETTER_UNSUBSCRIBE } from '@/event/Events' import { Context, getUser } from '@/server/context' @Resolver() From 7fb7ff9e8cb542ca044c32c66227177a24510feb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Thu, 20 Apr 2023 02:28:29 +0200 Subject: [PATCH 31/34] rename communities to federated_communities --- backend/src/config/index.ts | 2 +- .../federation/client/1_0/FederationClient.ts | 6 +- .../federation/client/1_1/FederationClient.ts | 6 +- backend/src/federation/validateCommunities.ts | 23 ++++--- backend/src/graphql/model/Community.ts | 37 +++++------- .../src/graphql/model/FederatedCommunity.ts | 45 ++++++++++++++ .../resolver/CommunityResolver.test.ts | 40 ++++++------- .../src/graphql/resolver/CommunityResolver.ts | 24 ++++++-- .../Community.ts | 60 +++++++++++++++++++ .../FederatedCommunity.ts | 51 ++++++++++++++++ database/entity/Community.ts | 2 +- database/entity/FederatedCommunity.ts | 1 + database/entity/index.ts | 2 + .../0065-refactor_communities_table.ts | 37 ++++++++++++ dht-node/src/config/index.ts | 2 +- dht-node/src/dht_node/index.test.ts | 18 +++--- dht-node/src/dht_node/index.ts | 16 ++--- federation/src/config/index.ts | 2 +- .../1_0/resolver/PublicKeyResolver.test.ts | 8 +-- .../api/1_0/resolver/PublicKeyResolver.ts | 4 +- 20 files changed, 301 insertions(+), 85 deletions(-) create mode 100644 backend/src/graphql/model/FederatedCommunity.ts create mode 100644 database/entity/0065-refactor_communities_table/Community.ts create mode 100644 database/entity/0065-refactor_communities_table/FederatedCommunity.ts create mode 100644 database/entity/FederatedCommunity.ts create mode 100644 database/migrations/0065-refactor_communities_table.ts diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index 0c36e4d5a..fc88011ea 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -12,7 +12,7 @@ Decimal.set({ }) const constants = { - DB_VERSION: '0064-event_rename', + DB_VERSION: '0065-refactor_communities_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/federation/client/1_0/FederationClient.ts b/backend/src/federation/client/1_0/FederationClient.ts index 13f05e761..743d17348 100644 --- a/backend/src/federation/client/1_0/FederationClient.ts +++ b/backend/src/federation/client/1_0/FederationClient.ts @@ -1,14 +1,16 @@ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-unsafe-return */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ -import { Community as DbCommunity } from '@entity/Community' +import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' import { gql } from 'graphql-request' import { GraphQLGetClient } from '@/federation/client/GraphQLGetClient' import { LogError } from '@/server/LogError' import { backendLogger as logger } from '@/server/logger' -export async function requestGetPublicKey(dbCom: DbCommunity): Promise { +export async function requestGetPublicKey( + dbCom: DbFederatedCommunity, +): Promise { let endpoint = dbCom.endPoint.endsWith('/') ? dbCom.endPoint : dbCom.endPoint + '/' endpoint = `${endpoint}${dbCom.apiVersion}/` logger.info(`requestGetPublicKey with endpoint='${endpoint}'...`) diff --git a/backend/src/federation/client/1_1/FederationClient.ts b/backend/src/federation/client/1_1/FederationClient.ts index bda185fba..35c88bf3b 100644 --- a/backend/src/federation/client/1_1/FederationClient.ts +++ b/backend/src/federation/client/1_1/FederationClient.ts @@ -1,14 +1,16 @@ /* eslint-disable @typescript-eslint/no-unsafe-return */ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ -import { Community as DbCommunity } from '@entity/Community' +import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' import { gql } from 'graphql-request' import { GraphQLGetClient } from '@/federation/client/GraphQLGetClient' import { LogError } from '@/server/LogError' import { backendLogger as logger } from '@/server/logger' -export async function requestGetPublicKey(dbCom: DbCommunity): Promise { +export async function requestGetPublicKey( + dbCom: DbFederatedCommunity, +): Promise { let endpoint = dbCom.endPoint.endsWith('/') ? dbCom.endPoint : dbCom.endPoint + '/' endpoint = `${endpoint}${dbCom.apiVersion}/` logger.info(`requestGetPublicKey with endpoint='${endpoint}'...`) diff --git a/backend/src/federation/validateCommunities.ts b/backend/src/federation/validateCommunities.ts index 0e8c7cb12..b38f38ee9 100644 --- a/backend/src/federation/validateCommunities.ts +++ b/backend/src/federation/validateCommunities.ts @@ -1,5 +1,7 @@ +/** eslint-disable @typescript-eslint/no-unsafe-call */ +/** eslint-disable @typescript-eslint/no-unsafe-assignment */ import { IsNull } from '@dbTools/typeorm' -import { Community as DbCommunity } from '@entity/Community' +import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' import { LogError } from '@/server/LogError' import { backendLogger as logger } from '@/server/logger' @@ -23,13 +25,14 @@ export function startValidateCommunities(timerInterval: number): void { } export async function validateCommunities(): Promise { - const dbCommunities: DbCommunity[] = await DbCommunity.createQueryBuilder() - .where({ foreign: true, verifiedAt: IsNull() }) - .orWhere('verified_at < last_announced_at') - .getMany() + const dbFederatedCommunities: DbFederatedCommunity[] = + await DbFederatedCommunity.createQueryBuilder() + .where({ foreign: true, verifiedAt: IsNull() }) + .orWhere('verified_at < last_announced_at') + .getMany() - logger.debug(`Federation: found ${dbCommunities.length} dbCommunities`) - for (const dbCom of dbCommunities) { + logger.debug(`Federation: found ${dbFederatedCommunities.length} dbCommunities`) + for (const dbCom of dbFederatedCommunities) { logger.debug('Federation: dbCom', dbCom) const apiValueStrings: string[] = Object.values(ApiVersionType) logger.debug(`suppported ApiVersions=`, apiValueStrings) @@ -46,7 +49,7 @@ export async function validateCommunities(): Promise { ) if (pubKey && pubKey === dbCom.publicKey.toString()) { logger.info(`Federation: matching publicKey: ${pubKey}`) - await DbCommunity.update({ id: dbCom.id }, { verifiedAt: new Date() }) + await DbFederatedCommunity.update({ id: dbCom.id }, { verifiedAt: new Date() }) logger.debug(`Federation: updated dbCom: ${JSON.stringify(dbCom)}`) } else { logger.warn( @@ -74,7 +77,9 @@ function isLogError(err: unknown) { return err instanceof LogError } -async function invokeVersionedRequestGetPublicKey(dbCom: DbCommunity): Promise { +async function invokeVersionedRequestGetPublicKey( + dbCom: DbFederatedCommunity, +): Promise { switch (dbCom.apiVersion) { case ApiVersionType.V1_0: return v1_0_requestGetPublicKey(dbCom) diff --git a/backend/src/graphql/model/Community.ts b/backend/src/graphql/model/Community.ts index d79d40034..bc310a39f 100644 --- a/backend/src/graphql/model/Community.ts +++ b/backend/src/graphql/model/Community.ts @@ -6,14 +6,12 @@ export class Community { constructor(dbCom: DbCommunity) { this.id = dbCom.id this.foreign = dbCom.foreign - this.publicKey = dbCom.publicKey.toString() - this.url = - (dbCom.endPoint.endsWith('/') ? dbCom.endPoint : dbCom.endPoint + '/') + dbCom.apiVersion - this.lastAnnouncedAt = dbCom.lastAnnouncedAt - this.verifiedAt = dbCom.verifiedAt - this.lastErrorAt = dbCom.lastErrorAt - this.createdAt = dbCom.createdAt - this.updatedAt = dbCom.updatedAt + this.name = dbCom.name + this.description = dbCom.description + this.url = dbCom.url + this.creationDate = dbCom.creationDate + this.uuid = dbCom.communityUuid + this.authenticatedAt = dbCom.authenticatedAt } @Field(() => Int) @@ -22,24 +20,21 @@ export class Community { @Field(() => Boolean) foreign: boolean - @Field(() => String) - publicKey: string + @Field(() => String, { nullable: true }) + name: string | null + + @Field(() => String, { nullable: true }) + description: string | null @Field(() => String) url: string @Field(() => Date, { nullable: true }) - lastAnnouncedAt: Date | null + creationDate: Date | null + + @Field(() => String, { nullable: true }) + uuid: string | null @Field(() => Date, { nullable: true }) - verifiedAt: Date | null - - @Field(() => Date, { nullable: true }) - lastErrorAt: Date | null - - @Field(() => Date, { nullable: true }) - createdAt: Date | null - - @Field(() => Date, { nullable: true }) - updatedAt: Date | null + authenticatedAt: Date | null } diff --git a/backend/src/graphql/model/FederatedCommunity.ts b/backend/src/graphql/model/FederatedCommunity.ts new file mode 100644 index 000000000..856a10d23 --- /dev/null +++ b/backend/src/graphql/model/FederatedCommunity.ts @@ -0,0 +1,45 @@ +import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' +import { ObjectType, Field, Int } from 'type-graphql' + +@ObjectType() +export class FederatedCommunity { + constructor(dbCom: DbFederatedCommunity) { + this.id = dbCom.id + this.foreign = dbCom.foreign + this.publicKey = dbCom.publicKey.toString() + this.url = + (dbCom.endPoint.endsWith('/') ? dbCom.endPoint : dbCom.endPoint + '/') + dbCom.apiVersion + this.lastAnnouncedAt = dbCom.lastAnnouncedAt + this.verifiedAt = dbCom.verifiedAt + this.lastErrorAt = dbCom.lastErrorAt + this.createdAt = dbCom.createdAt + this.updatedAt = dbCom.updatedAt + } + + @Field(() => Int) + id: number + + @Field(() => Boolean) + foreign: boolean + + @Field(() => String) + publicKey: string + + @Field(() => String) + url: string + + @Field(() => Date, { nullable: true }) + lastAnnouncedAt: Date | null + + @Field(() => Date, { nullable: true }) + verifiedAt: Date | null + + @Field(() => Date, { nullable: true }) + lastErrorAt: Date | null + + @Field(() => Date, { nullable: true }) + createdAt: Date | null + + @Field(() => Date, { nullable: true }) + updatedAt: Date | null +} diff --git a/backend/src/graphql/resolver/CommunityResolver.test.ts b/backend/src/graphql/resolver/CommunityResolver.test.ts index 26f4a3390..0e08896c0 100644 --- a/backend/src/graphql/resolver/CommunityResolver.test.ts +++ b/backend/src/graphql/resolver/CommunityResolver.test.ts @@ -5,7 +5,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -import { Community as DbCommunity } from '@entity/Community' +import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' import { testEnvironment } from '@test/helpers' @@ -21,7 +21,7 @@ beforeAll(async () => { testEnv = await testEnvironment() query = testEnv.query con = testEnv.con - await DbCommunity.clear() + await DbFederatedCommunity.clear() }) afterAll(async () => { @@ -30,12 +30,12 @@ afterAll(async () => { describe('CommunityResolver', () => { describe('getCommunities', () => { - let homeCom1: DbCommunity - let homeCom2: DbCommunity - let homeCom3: DbCommunity - let foreignCom1: DbCommunity - let foreignCom2: DbCommunity - let foreignCom3: DbCommunity + let homeCom1: DbFederatedCommunity + let homeCom2: DbFederatedCommunity + let homeCom3: DbFederatedCommunity + let foreignCom1: DbFederatedCommunity + let foreignCom2: DbFederatedCommunity + let foreignCom3: DbFederatedCommunity describe('with empty list', () => { it('returns no community entry', async () => { @@ -53,29 +53,29 @@ describe('CommunityResolver', () => { beforeEach(async () => { jest.clearAllMocks() - homeCom1 = DbCommunity.create() + homeCom1 = DbFederatedCommunity.create() homeCom1.foreign = false homeCom1.publicKey = Buffer.from('publicKey-HomeCommunity') homeCom1.apiVersion = '1_0' homeCom1.endPoint = 'http://localhost/api' homeCom1.createdAt = new Date() - await DbCommunity.insert(homeCom1) + await DbFederatedCommunity.insert(homeCom1) - homeCom2 = DbCommunity.create() + homeCom2 = DbFederatedCommunity.create() homeCom2.foreign = false homeCom2.publicKey = Buffer.from('publicKey-HomeCommunity') homeCom2.apiVersion = '1_1' homeCom2.endPoint = 'http://localhost/api' homeCom2.createdAt = new Date() - await DbCommunity.insert(homeCom2) + await DbFederatedCommunity.insert(homeCom2) - homeCom3 = DbCommunity.create() + homeCom3 = DbFederatedCommunity.create() homeCom3.foreign = false homeCom3.publicKey = Buffer.from('publicKey-HomeCommunity') homeCom3.apiVersion = '2_0' homeCom3.endPoint = 'http://localhost/api' homeCom3.createdAt = new Date() - await DbCommunity.insert(homeCom3) + await DbFederatedCommunity.insert(homeCom3) }) it('returns 3 home-community entries', async () => { @@ -125,29 +125,29 @@ describe('CommunityResolver', () => { beforeEach(async () => { jest.clearAllMocks() - foreignCom1 = DbCommunity.create() + foreignCom1 = DbFederatedCommunity.create() foreignCom1.foreign = true foreignCom1.publicKey = Buffer.from('publicKey-ForeignCommunity') foreignCom1.apiVersion = '1_0' foreignCom1.endPoint = 'http://remotehost/api' foreignCom1.createdAt = new Date() - await DbCommunity.insert(foreignCom1) + await DbFederatedCommunity.insert(foreignCom1) - foreignCom2 = DbCommunity.create() + foreignCom2 = DbFederatedCommunity.create() foreignCom2.foreign = true foreignCom2.publicKey = Buffer.from('publicKey-ForeignCommunity') foreignCom2.apiVersion = '1_1' foreignCom2.endPoint = 'http://remotehost/api' foreignCom2.createdAt = new Date() - await DbCommunity.insert(foreignCom2) + await DbFederatedCommunity.insert(foreignCom2) - foreignCom3 = DbCommunity.create() + foreignCom3 = DbFederatedCommunity.create() foreignCom3.foreign = true foreignCom3.publicKey = Buffer.from('publicKey-ForeignCommunity') foreignCom3.apiVersion = '1_2' foreignCom3.endPoint = 'http://remotehost/api' foreignCom3.createdAt = new Date() - await DbCommunity.insert(foreignCom3) + await DbFederatedCommunity.insert(foreignCom3) }) it('returns 3 home community and 3 foreign community entries', async () => { diff --git a/backend/src/graphql/resolver/CommunityResolver.ts b/backend/src/graphql/resolver/CommunityResolver.ts index 19a499a9b..7306fdffb 100644 --- a/backend/src/graphql/resolver/CommunityResolver.ts +++ b/backend/src/graphql/resolver/CommunityResolver.ts @@ -1,22 +1,38 @@ import { Community as DbCommunity } from '@entity/Community' +import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' +import { Community } from '@model/Community' import { Resolver, Query, Authorized } from 'type-graphql' -import { Community } from '@model/Community' +import { FederatedCommunity } from '@model/FederatedCommunity' + import { RIGHTS } from '@/auth/RIGHTS' @Resolver() export class CommunityResolver { @Authorized([RIGHTS.COMMUNITIES]) - @Query(() => [Community]) - async getCommunities(): Promise { - const dbCommunities: DbCommunity[] = await DbCommunity.find({ + @Query(() => [FederatedCommunity]) + async getCommunities(): Promise { + const dbFederatedCommunities: DbFederatedCommunity[] = await DbFederatedCommunity.find({ order: { foreign: 'ASC', createdAt: 'DESC', lastAnnouncedAt: 'DESC', }, }) + return dbFederatedCommunities.map( + (dbCom: DbFederatedCommunity) => new FederatedCommunity(dbCom), + ) + } + + @Authorized([RIGHTS.COMMUNITIES]) + @Query(() => [Community]) + async getCommunitySelections(): Promise { + const dbCommunities: DbCommunity[] = await DbCommunity.find({ + order: { + name: 'ASC', + }, + }) return dbCommunities.map((dbCom: DbCommunity) => new Community(dbCom)) } } diff --git a/database/entity/0065-refactor_communities_table/Community.ts b/database/entity/0065-refactor_communities_table/Community.ts new file mode 100644 index 000000000..5857634a6 --- /dev/null +++ b/database/entity/0065-refactor_communities_table/Community.ts @@ -0,0 +1,60 @@ +import { + BaseEntity, + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, +} from 'typeorm' + +@Entity('communities') +export class Community extends BaseEntity { + @PrimaryGeneratedColumn('increment', { unsigned: true }) + id: number + + @Column({ name: 'foreign', type: 'bool', nullable: false, default: true }) + foreign: boolean + + @Column({ name: 'url', length: 255, nullable: false }) + url: string + + @Column({ name: 'public_key', type: 'binary', length: 64, nullable: false }) + publicKey: Buffer + + @Column({ + name: 'community_uuid', + type: 'char', + length: 36, + nullable: true, + collation: 'utf8mb4_unicode_ci', + }) + communityUuid: string | null + + @Column({ name: 'authenticated_at', type: 'datetime', nullable: true }) + authenticatedAt: Date | null + + @Column({ name: 'name', type: 'varchar', length: 40, nullable: true }) + name: string | null + + @Column({ name: 'description', type: 'varchar', length: 255, nullable: true }) + description: string | null + + @CreateDateColumn({ name: 'creation_date', type: 'datetime', nullable: true }) + creationDate: Date | null + + @CreateDateColumn({ + name: 'created_at', + type: 'datetime', + default: () => 'CURRENT_TIMESTAMP(3)', + nullable: false, + }) + createdAt: Date + + @UpdateDateColumn({ + name: 'updated_at', + type: 'datetime', + onUpdate: 'CURRENT_TIMESTAMP(3)', + nullable: true, + }) + updatedAt: Date | null +} diff --git a/database/entity/0065-refactor_communities_table/FederatedCommunity.ts b/database/entity/0065-refactor_communities_table/FederatedCommunity.ts new file mode 100644 index 000000000..0adbf4612 --- /dev/null +++ b/database/entity/0065-refactor_communities_table/FederatedCommunity.ts @@ -0,0 +1,51 @@ +import { + BaseEntity, + Entity, + PrimaryGeneratedColumn, + Column, + CreateDateColumn, + UpdateDateColumn, +} from 'typeorm' + +@Entity('federated_communities') +export class FederatedCommunity extends BaseEntity { + @PrimaryGeneratedColumn('increment', { unsigned: true }) + id: number + + @Column({ name: 'foreign', type: 'bool', nullable: false, default: true }) + foreign: boolean + + @Column({ name: 'public_key', type: 'binary', length: 64, default: null, nullable: true }) + publicKey: Buffer + + @Column({ name: 'api_version', length: 10, nullable: false }) + apiVersion: string + + @Column({ name: 'end_point', length: 255, nullable: false }) + endPoint: string + + @Column({ name: 'last_announced_at', type: 'datetime', nullable: true }) + lastAnnouncedAt: Date | null + + @Column({ name: 'verified_at', type: 'datetime', nullable: true }) + verifiedAt: Date | null + + @Column({ name: 'last_error_at', type: 'datetime', nullable: true }) + lastErrorAt: Date | null + + @CreateDateColumn({ + name: 'created_at', + type: 'datetime', + default: () => 'CURRENT_TIMESTAMP(3)', + nullable: false, + }) + createdAt: Date + + @UpdateDateColumn({ + name: 'updated_at', + type: 'datetime', + onUpdate: 'CURRENT_TIMESTAMP(3)', + nullable: true, + }) + updatedAt: Date | null +} diff --git a/database/entity/Community.ts b/database/entity/Community.ts index 80e5ace30..ee08323b6 100644 --- a/database/entity/Community.ts +++ b/database/entity/Community.ts @@ -1 +1 @@ -export { Community } from './0060-update_communities_table/Community' +export { Community } from './0065-refactor_communities_table/Community' diff --git a/database/entity/FederatedCommunity.ts b/database/entity/FederatedCommunity.ts new file mode 100644 index 000000000..cacaaff9c --- /dev/null +++ b/database/entity/FederatedCommunity.ts @@ -0,0 +1 @@ +export { FederatedCommunity } from './0065-refactor_communities_table/FederatedCommunity' diff --git a/database/entity/index.ts b/database/entity/index.ts index 2d9d04c3b..d44029754 100644 --- a/database/entity/index.ts +++ b/database/entity/index.ts @@ -10,6 +10,7 @@ import { Contribution } from './Contribution' import { Event } from './Event' import { ContributionMessage } from './ContributionMessage' import { Community } from './Community' +import { FederatedCommunity } from './FederatedCommunity' export const entities = [ Community, @@ -17,6 +18,7 @@ export const entities = [ ContributionLink, ContributionMessage, Event, + FederatedCommunity, LoginElopageBuys, LoginEmailOptIn, Migration, diff --git a/database/migrations/0065-refactor_communities_table.ts b/database/migrations/0065-refactor_communities_table.ts new file mode 100644 index 000000000..6cba8a174 --- /dev/null +++ b/database/migrations/0065-refactor_communities_table.ts @@ -0,0 +1,37 @@ +/* MIGRATION TO CREATE THE FEDERATION COMMUNITY TABLES + * + * This migration creates the `community` and 'communityfederation' tables in the `apollo` database (`gradido_community`). + */ + +/* 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(`RENAME TABLE communities TO federated_communities;`) + await queryFn(` + CREATE TABLE communities ( + \`id\` int unsigned NOT NULL AUTO_INCREMENT, + \`foreign\` tinyint(4) NOT NULL DEFAULT 1, + \`url\` varchar(255) NOT NULL, + \`public_key\` binary(64) NOT NULL, + \`community_uuid\` char(36) NULL, + \`authenticated_at\` datetime(3) NULL, + \`name\` varchar(40) NULL, + \`description\` varchar(255) NULL, + \`creation_date\` datetime(3) NULL, + \`created_at\` datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3), + \`updated_at\` datetime(3), + PRIMARY KEY (id), + UNIQUE KEY url_key (url), + UNIQUE KEY uuid_key (community_uuid), + UNIQUE KEY public_key_key (public_key) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + `) +} + +export async function downgrade(queryFn: (query: string, values?: any[]) => Promise>) { + // write downgrade logic as parameter of queryFn + await queryFn(`DROP TABLE communities;`) + await queryFn(`RENAME TABLE federated_communities TO communities;`) + +} diff --git a/dht-node/src/config/index.ts b/dht-node/src/config/index.ts index 078c0fbf3..5c4676337 100644 --- a/dht-node/src/config/index.ts +++ b/dht-node/src/config/index.ts @@ -3,7 +3,7 @@ import dotenv from 'dotenv' dotenv.config() const constants = { - DB_VERSION: '0064-event_rename', + DB_VERSION: '0065-refactor_communities_table', LOG4JS_CONFIG: 'log4js-config.json', // default log level on production should be info LOG_LEVEL: process.env.LOG_LEVEL || 'info', diff --git a/dht-node/src/dht_node/index.test.ts b/dht-node/src/dht_node/index.test.ts index ac5b1b21a..e76e6ac9f 100644 --- a/dht-node/src/dht_node/index.test.ts +++ b/dht-node/src/dht_node/index.test.ts @@ -5,7 +5,7 @@ import { startDHT } from './index' import DHT from '@hyperswarm/dht' import CONFIG from '@/config' import { logger } from '@test/testSetup' -import { Community as DbCommunity } from '@entity/Community' +import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' import { testEnvironment, cleanDB } from '@test/helpers' CONFIG.FEDERATION_DHT_SEED = '64ebcb0e3ad547848fef4197c6e2332f' @@ -261,7 +261,7 @@ describe('federation', () => { describe('with receiving wrong but tolerated property data', () => { let jsonArray: any[] - let result: DbCommunity[] = [] + let result: DbFederatedCommunity[] = [] beforeAll(async () => { jest.clearAllMocks() jsonArray = [ @@ -277,7 +277,7 @@ describe('federation', () => { }, ] await socketEventMocks.data(Buffer.from(JSON.stringify(jsonArray))) - result = await DbCommunity.find({ foreign: true }) + result = await DbFederatedCommunity.find({ foreign: true }) }) afterAll(async () => { @@ -523,7 +523,7 @@ describe('federation', () => { describe('with receiving data of exact max allowed properties length', () => { let jsonArray: any[] - let result: DbCommunity[] = [] + let result: DbFederatedCommunity[] = [] beforeAll(async () => { jest.clearAllMocks() jsonArray = [ @@ -538,7 +538,7 @@ describe('federation', () => { { api: 'toolong api', url: 'some valid url' }, ] await socketEventMocks.data(Buffer.from(JSON.stringify(jsonArray))) - result = await DbCommunity.find({ foreign: true }) + result = await DbFederatedCommunity.find({ foreign: true }) }) afterAll(async () => { @@ -570,7 +570,7 @@ describe('federation', () => { describe('with receiving data of exact max allowed buffer length', () => { let jsonArray: any[] - let result: DbCommunity[] = [] + let result: DbFederatedCommunity[] = [] beforeAll(async () => { jest.clearAllMocks() jsonArray = [ @@ -592,7 +592,7 @@ describe('federation', () => { }, ] await socketEventMocks.data(Buffer.from(JSON.stringify(jsonArray))) - result = await DbCommunity.find({ foreign: true }) + result = await DbFederatedCommunity.find({ foreign: true }) }) afterAll(async () => { @@ -711,7 +711,7 @@ describe('federation', () => { }) describe('with proper data', () => { - let result: DbCommunity[] = [] + let result: DbFederatedCommunity[] = [] beforeAll(async () => { jest.clearAllMocks() await socketEventMocks.data( @@ -728,7 +728,7 @@ describe('federation', () => { ]), ), ) - result = await DbCommunity.find({ foreign: true }) + result = await DbFederatedCommunity.find({ foreign: true }) }) afterAll(async () => { diff --git a/dht-node/src/dht_node/index.ts b/dht-node/src/dht_node/index.ts index d101037ae..0db7a28c2 100644 --- a/dht-node/src/dht_node/index.ts +++ b/dht-node/src/dht_node/index.ts @@ -3,7 +3,7 @@ import DHT from '@hyperswarm/dht' import { logger } from '@/server/logger' import CONFIG from '@/config' -import { Community as DbCommunity } from '@entity/Community' +import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' const KEY_SECRET_SEEDBYTES = 32 const getSeed = (): Buffer | null => @@ -31,7 +31,7 @@ export const startDHT = async (topic: string): Promise => { logger.info(`keyPairDHT: publicKey=${keyPair.publicKey.toString('hex')}`) logger.debug(`keyPairDHT: secretKey=${keyPair.secretKey.toString('hex')}`) - const ownApiVersions = await writeHomeCommunityEnries(keyPair.publicKey) + const ownApiVersions = await writeFederatedHomeCommunityEnries(keyPair.publicKey) logger.info(`ApiList: ${JSON.stringify(ownApiVersions)}`) const node = new DHT({ keyPair }) @@ -92,9 +92,9 @@ export const startDHT = async (topic: string): Promise => { } logger.debug(`upsert with variables=${JSON.stringify(variables)}`) // this will NOT update the updatedAt column, to distingue between a normal update and the last announcement - await DbCommunity.createQueryBuilder() + await DbFederatedCommunity.createQueryBuilder() .insert() - .into(DbCommunity) + .into(DbFederatedCommunity) .values(variables) .orUpdate({ conflict_target: ['id', 'publicKey', 'apiVersion'], @@ -179,7 +179,7 @@ export const startDHT = async (topic: string): Promise => { } } -async function writeHomeCommunityEnries(pubKey: any): Promise { +async function writeFederatedHomeCommunityEnries(pubKey: any): Promise { const homeApiVersions: CommunityApi[] = Object.values(ApiVersionType).map(function (apiEnum) { const comApi: CommunityApi = { api: apiEnum, @@ -189,17 +189,17 @@ async function writeHomeCommunityEnries(pubKey: any): Promise { }) try { // first remove privious existing homeCommunity entries - DbCommunity.createQueryBuilder().delete().where({ foreign: false }).execute() + DbFederatedCommunity.createQueryBuilder().delete().where({ foreign: false }).execute() homeApiVersions.forEach(async function (homeApi) { - const homeCom = new DbCommunity() + const homeCom = new DbFederatedCommunity() homeCom.foreign = false homeCom.apiVersion = homeApi.api homeCom.endPoint = homeApi.url homeCom.publicKey = pubKey.toString('hex') // this will NOT update the updatedAt column, to distingue between a normal update and the last announcement - await DbCommunity.insert(homeCom) + await DbFederatedCommunity.insert(homeCom) logger.info(`federation home-community inserted successfully: ${JSON.stringify(homeCom)}`) }) } catch (err) { diff --git a/federation/src/config/index.ts b/federation/src/config/index.ts index ce0c5a9a5..70a155d63 100644 --- a/federation/src/config/index.ts +++ b/federation/src/config/index.ts @@ -11,7 +11,7 @@ Decimal.set({ */ const constants = { - DB_VERSION: '0064-event_rename', + DB_VERSION: '0065-refactor_communities_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/federation/src/graphql/api/1_0/resolver/PublicKeyResolver.test.ts b/federation/src/graphql/api/1_0/resolver/PublicKeyResolver.test.ts index 20e6c8228..18d2a7599 100644 --- a/federation/src/graphql/api/1_0/resolver/PublicKeyResolver.test.ts +++ b/federation/src/graphql/api/1_0/resolver/PublicKeyResolver.test.ts @@ -2,7 +2,7 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import { createTestClient } from 'apollo-server-testing' import createServer from '@/server/createServer' -import { Community as DbCommunity } from '@entity/Community' +import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' let query: any @@ -13,7 +13,7 @@ beforeAll(async () => { const server = await createServer() con = server.con query = createTestClient(server.apollo).query - DbCommunity.clear() + DbFederatedCommunity.clear() }) afterAll(async () => { @@ -32,12 +32,12 @@ describe('PublicKeyResolver', () => { describe('getPublicKey', () => { beforeEach(async () => { - const homeCom = new DbCommunity() + const homeCom = new DbFederatedCommunity() homeCom.foreign = false homeCom.apiVersion = '1_0' homeCom.endPoint = 'endpoint-url' homeCom.publicKey = Buffer.from('homeCommunity-publicKey') - await DbCommunity.insert(homeCom) + await DbFederatedCommunity.insert(homeCom) }) it('returns homeCommunity-publicKey', async () => { diff --git a/federation/src/graphql/api/1_0/resolver/PublicKeyResolver.ts b/federation/src/graphql/api/1_0/resolver/PublicKeyResolver.ts index f96f20c58..0145324fc 100644 --- a/federation/src/graphql/api/1_0/resolver/PublicKeyResolver.ts +++ b/federation/src/graphql/api/1_0/resolver/PublicKeyResolver.ts @@ -1,7 +1,7 @@ // eslint-disable-next-line @typescript-eslint/no-unused-vars import { Query, Resolver } from 'type-graphql' import { federationLogger as logger } from '@/server/logger' -import { Community as DbCommunity } from '@entity/Community' +import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' import { GetPublicKeyResult } from '../model/GetPublicKeyResult' @Resolver() @@ -10,7 +10,7 @@ export class PublicKeyResolver { @Query(() => GetPublicKeyResult) async getPublicKey(): Promise { logger.debug(`getPublicKey() via apiVersion=1_0 ...`) - const homeCom = await DbCommunity.findOneOrFail({ + const homeCom = await DbFederatedCommunity.findOneOrFail({ foreign: false, apiVersion: '1_0', }) From 3fdeec0783a8e1c252b3aa2d5cd6900013a28aaa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Thu, 27 Apr 2023 21:35:18 +0200 Subject: [PATCH 32/34] linting --- backend/src/graphql/model/Community.ts | 2 +- backend/src/graphql/resolver/CommunityResolver.ts | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/backend/src/graphql/model/Community.ts b/backend/src/graphql/model/Community.ts index bc310a39f..43e0a7108 100644 --- a/backend/src/graphql/model/Community.ts +++ b/backend/src/graphql/model/Community.ts @@ -30,7 +30,7 @@ export class Community { url: string @Field(() => Date, { nullable: true }) - creationDate: Date | null + creationDate: Date | null @Field(() => String, { nullable: true }) uuid: string | null diff --git a/backend/src/graphql/resolver/CommunityResolver.ts b/backend/src/graphql/resolver/CommunityResolver.ts index 7306fdffb..4c6c8e785 100644 --- a/backend/src/graphql/resolver/CommunityResolver.ts +++ b/backend/src/graphql/resolver/CommunityResolver.ts @@ -1,11 +1,10 @@ import { Community as DbCommunity } from '@entity/Community' import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' -import { Community } from '@model/Community' import { Resolver, Query, Authorized } from 'type-graphql' +import { Community } from '@model/Community' import { FederatedCommunity } from '@model/FederatedCommunity' - import { RIGHTS } from '@/auth/RIGHTS' @Resolver() From f9f01f94ea11fc027102057b5e1d71347815d9f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Thu, 27 Apr 2023 21:44:42 +0200 Subject: [PATCH 33/34] linting --- database/migrations/0065-refactor_communities_table.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/database/migrations/0065-refactor_communities_table.ts b/database/migrations/0065-refactor_communities_table.ts index 6cba8a174..06f5b3990 100644 --- a/database/migrations/0065-refactor_communities_table.ts +++ b/database/migrations/0065-refactor_communities_table.ts @@ -33,5 +33,4 @@ export async function downgrade(queryFn: (query: string, values?: any[]) => Prom // write downgrade logic as parameter of queryFn await queryFn(`DROP TABLE communities;`) await queryFn(`RENAME TABLE federated_communities TO communities;`) - } From d562371cbc5bddfd26ef0882bd372634ccb3994e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Thu, 27 Apr 2023 22:10:53 +0200 Subject: [PATCH 34/34] use correct renamed entity in tests too --- .../src/federation/validateCommunities.test.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/backend/src/federation/validateCommunities.test.ts b/backend/src/federation/validateCommunities.test.ts index d90664b63..10df70489 100644 --- a/backend/src/federation/validateCommunities.test.ts +++ b/backend/src/federation/validateCommunities.test.ts @@ -5,7 +5,7 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -import { Community as DbCommunity } from '@entity/Community' +import { FederatedCommunity as DbFederatedCommunity } from '@entity/FederatedCommunity' import { testEnvironment, cleanDB } from '@test/helpers' import { logger } from '@test/testSetup' @@ -59,9 +59,9 @@ describe('validate Communities', () => { endPoint: 'http//localhost:5001/api/', lastAnnouncedAt: new Date(), } - await DbCommunity.createQueryBuilder() + await DbFederatedCommunity.createQueryBuilder() .insert() - .into(DbCommunity) + .into(DbFederatedCommunity) .values(variables1) .orUpdate({ conflict_target: ['id', 'publicKey', 'apiVersion'], @@ -90,9 +90,9 @@ describe('validate Communities', () => { endPoint: 'http//localhost:5001/api/', lastAnnouncedAt: new Date(), } - await DbCommunity.createQueryBuilder() + await DbFederatedCommunity.createQueryBuilder() .insert() - .into(DbCommunity) + .into(DbFederatedCommunity) .values(variables2) .orUpdate({ conflict_target: ['id', 'publicKey', 'apiVersion'], @@ -118,7 +118,7 @@ describe('validate Communities', () => { }) }) describe('with three Communities of api 1_0, 1_1 and 2_0', () => { - let dbCom: DbCommunity + let dbCom: DbFederatedCommunity beforeEach(async () => { const variables3 = { publicKey: Buffer.from('11111111111111111111111111111111'), @@ -126,16 +126,16 @@ describe('validate Communities', () => { endPoint: 'http//localhost:5001/api/', lastAnnouncedAt: new Date(), } - await DbCommunity.createQueryBuilder() + await DbFederatedCommunity.createQueryBuilder() .insert() - .into(DbCommunity) + .into(DbFederatedCommunity) .values(variables3) .orUpdate({ conflict_target: ['id', 'publicKey', 'apiVersion'], overwrite: ['end_point', 'last_announced_at'], }) .execute() - dbCom = await DbCommunity.findOneOrFail({ + dbCom = await DbFederatedCommunity.findOneOrFail({ where: { publicKey: variables3.publicKey, apiVersion: variables3.apiVersion }, }) jest.clearAllMocks()