From 6bcf81b7d3afe1c85787deca78906cdf2dd7ba1e Mon Sep 17 00:00:00 2001 From: elweyn Date: Tue, 13 Jun 2023 11:07:17 +0200 Subject: [PATCH 01/94] Add definition of cron-job for klicktipp export. --- deployment/bare_metal/setup.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/deployment/bare_metal/setup.md b/deployment/bare_metal/setup.md index 9cbc4e2e3..717dd8547 100644 --- a/deployment/bare_metal/setup.md +++ b/deployment/bare_metal/setup.md @@ -234,7 +234,8 @@ crontab -l This show all existing entries of the crontab for user `gradido` -To install/add the cronjob for a daily backup at 3:00am please +To install/add the cronjob for a daily backup at 3:00am please, +To install/add the cronjob for a daily klicktipp export at 4:00am please, Run: @@ -244,4 +245,5 @@ crontab -e and insert the following line ```bash 0 3 * * * ~/gradido/deployment/bare_metal/backup.sh +0 4 * * * cd ~/gradido/backend/ && yarn klicktipp && cd ``` From 33eda9501a045f5f9542d62ea742f50042330759 Mon Sep 17 00:00:00 2001 From: mahula Date: Tue, 13 Jun 2023 14:48:21 +0200 Subject: [PATCH 02/94] remove experimentalSessionAndOrigin from cypress config --- e2e-tests/cypress.config.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/e2e-tests/cypress.config.ts b/e2e-tests/cypress.config.ts index e26259626..e48810816 100644 --- a/e2e-tests/cypress.config.ts +++ b/e2e-tests/cypress.config.ts @@ -41,7 +41,6 @@ export default defineConfig({ e2e: { specPattern: '**/*.feature', excludeSpecPattern: '*.js', - experimentalSessionAndOrigin: true, baseUrl: 'http://localhost:3000', chromeWebSecurity: false, defaultCommandTimeout: 10000, From a837ce0a0da4e939b5b185eace0ddeaa5d4a3168 Mon Sep 17 00:00:00 2001 From: mahula Date: Fri, 16 Jun 2023 16:29:25 +0200 Subject: [PATCH 03/94] add send page obpejt for e2e tests --- e2e-tests/cypress/e2e/models/SendPage.ts | 33 ++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 e2e-tests/cypress/e2e/models/SendPage.ts diff --git a/e2e-tests/cypress/e2e/models/SendPage.ts b/e2e-tests/cypress/e2e/models/SendPage.ts new file mode 100644 index 000000000..ab2df6084 --- /dev/null +++ b/e2e-tests/cypress/e2e/models/SendPage.ts @@ -0,0 +1,33 @@ +/// + +export class SendPage { + submitBtn = '.btn-gradido' + + enterReceiverEmail(email: string) { + cy.get('[data-test="input-identifier"]').find('input') + .clear() + .type(email) + return this + } + + enterAmount(amount: string) { + cy.get('[data-test="input-amount"]') + .find('input') + .clear() + .type(amount) + return this + } + + enterMemoText(text: string) { + cy.get('[data-test="input-textarea"]') + .find('textarea') + .clear() + .type(text) + return this + } + + submit() { + cy.get(this.submitBtn) + .click() + } +} From e46ff56c1e6ac3ffd7c8efa3cb1eb950ff8f5971 Mon Sep 17 00:00:00 2001 From: mahula Date: Fri, 16 Jun 2023 16:32:19 +0200 Subject: [PATCH 04/94] add send test of e2e feature send coins --- e2e-tests/cypress/e2e/SendCoins.feature | 20 +++++++ .../step_definitions/send_coin_steps.ts | 60 +++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 e2e-tests/cypress/e2e/SendCoins.feature create mode 100644 e2e-tests/cypress/support/step_definitions/send_coin_steps.ts diff --git a/e2e-tests/cypress/e2e/SendCoins.feature b/e2e-tests/cypress/e2e/SendCoins.feature new file mode 100644 index 000000000..f04684afb --- /dev/null +++ b/e2e-tests/cypress/e2e/SendCoins.feature @@ -0,0 +1,20 @@ +Feature: Send coins + As a user + I want to send and receive GDD + I want to see transaction details on overview and transactions pages + + # Background: + # Given the following "users" are in the database: + # | email | password | name | + # | bob@baumeister.de | Aa12345_ | Bob Baumeister | + # | raeuber@hotzenplotz.de | Aa12345_ | Räuber Hotzenplotz | + + Scenario: Send GDD to other user + Given the user is logged in as "bob@baumeister.de" "Aa12345_" + And the user navigates to page "/send" + When the user fills the send form with "raeuber@hotzenplotz.de" "120,50" "Some memo text" + And the user submits the send form + Then the transaction details are presented for confirmation + When the user submits the transaction by confirming + Then the transaction details are displayed on the transcations page + diff --git a/e2e-tests/cypress/support/step_definitions/send_coin_steps.ts b/e2e-tests/cypress/support/step_definitions/send_coin_steps.ts new file mode 100644 index 000000000..f96da9768 --- /dev/null +++ b/e2e-tests/cypress/support/step_definitions/send_coin_steps.ts @@ -0,0 +1,60 @@ +import { And, Then, When } from '@badeball/cypress-cucumber-preprocessor' +import { SendPage } from '../../e2e/models/SendPage' + +const sendPage = new SendPage() + +When( + 'the user fills the send form with {string} {string} {string}', + (email: string, amount: string, memoText: string) => { + sendPage.enterReceiverEmail(email) + sendPage.enterAmount(amount) + sendPage.enterMemoText(memoText) + } +) + +And('the user submits the send form', () => { + sendPage.submit() + cy.get('.transaction-confirm-send').should('be.visible') +}) + + +Then('the transaction details are presented for confirmation', () => { + cy.get('.transaction-confirm-send').contains('raeuber@hotzenplotz.de') + cy.get('.transaction-confirm-send').contains('+ 120,50 GDD') + cy.get('.transaction-confirm-send').contains('Some memo text') + cy.get('.transaction-confirm-send').contains('+ 515,11 GDD') + cy.get('.transaction-confirm-send').contains('− 120,50 GDD') + cy.get('.transaction-confirm-send').contains('+ 394,61 GDD') +}) + +When('the user submits the transaction by confirming', () => { + cy.intercept({ + method: 'POST', + url: '/graphql', + hostname: 'localhost', + }).as('sendCoins') + + sendPage.submit() + + cy.wait('@sendCoins').then((interception) => { + cy.wrap(interception.response?.statusCode).should('eq', 200) + cy.wrap(interception.request.body) + .should('have.property', 'query', `mutation ($identifier: String!, $amount: Decimal!, $memo: String!) { + sendCoins(identifier: $identifier, amount: $amount, memo: $memo) +} +` ) + cy.wrap(interception.response?.body) + .should('have.nested.property', 'data.sendCoins') + .and('equal', true) + }) + cy.get('[data-test="send-transaction-success-text"]').should('be.visible') + cy.get('.rightside-last-transactions').should('be.visible') + cy.get('.align-items-center').contains('Räuber Hotzenplotz') + cy.get('.align-items-center').contains('− 120,50 GDD') +}) + +Then('the transaction details are displayed on the transcations page', () => { + cy.visit('/transactions') + cy.get('.test-list-group-item').contains('Räuber Hotzenplotz') + cy.get('.test-list-group-item').contains('− 120,50 GDD') +}) \ No newline at end of file From f80e8540ddd6b00a4db5f49daaf2c05f50184e66 Mon Sep 17 00:00:00 2001 From: mahula Date: Fri, 16 Jun 2023 16:32:19 +0200 Subject: [PATCH 05/94] add send test of e2e feature send coins --- .../support/step_definitions/send_coin_steps.ts | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/e2e-tests/cypress/support/step_definitions/send_coin_steps.ts b/e2e-tests/cypress/support/step_definitions/send_coin_steps.ts index f96da9768..b7c319c08 100644 --- a/e2e-tests/cypress/support/step_definitions/send_coin_steps.ts +++ b/e2e-tests/cypress/support/step_definitions/send_coin_steps.ts @@ -20,11 +20,11 @@ And('the user submits the send form', () => { Then('the transaction details are presented for confirmation', () => { cy.get('.transaction-confirm-send').contains('raeuber@hotzenplotz.de') - cy.get('.transaction-confirm-send').contains('+ 120,50 GDD') + cy.get('.transaction-confirm-send').contains('+ 120.50 GDD') cy.get('.transaction-confirm-send').contains('Some memo text') - cy.get('.transaction-confirm-send').contains('+ 515,11 GDD') - cy.get('.transaction-confirm-send').contains('− 120,50 GDD') - cy.get('.transaction-confirm-send').contains('+ 394,61 GDD') + cy.get('.transaction-confirm-send').contains('+ 515.11 GDD') + cy.get('.transaction-confirm-send').contains('− 120.50 GDD') + cy.get('.transaction-confirm-send').contains('+ 394.61 GDD') }) When('the user submits the transaction by confirming', () => { @@ -50,11 +50,5 @@ When('the user submits the transaction by confirming', () => { cy.get('[data-test="send-transaction-success-text"]').should('be.visible') cy.get('.rightside-last-transactions').should('be.visible') cy.get('.align-items-center').contains('Räuber Hotzenplotz') - cy.get('.align-items-center').contains('− 120,50 GDD') + cy.get('.align-items-center').contains('− 120.50 GDD') }) - -Then('the transaction details are displayed on the transcations page', () => { - cy.visit('/transactions') - cy.get('.test-list-group-item').contains('Räuber Hotzenplotz') - cy.get('.test-list-group-item').contains('− 120,50 GDD') -}) \ No newline at end of file From 5a86c10169853171ea1bc6ba135672207dedb2c8 Mon Sep 17 00:00:00 2001 From: mahula Date: Fri, 16 Jun 2023 16:32:19 +0200 Subject: [PATCH 06/94] add send test of e2e feature send coins --- e2e-tests/cypress/e2e/SendCoins.feature | 6 ++++-- e2e-tests/cypress/e2e/models/SendPage.ts | 1 + .../cypress/support/step_definitions/send_coin_steps.ts | 8 +++++++- frontend/src/components/Transactions/TransactionSend.vue | 2 +- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/e2e-tests/cypress/e2e/SendCoins.feature b/e2e-tests/cypress/e2e/SendCoins.feature index f04684afb..3ff332012 100644 --- a/e2e-tests/cypress/e2e/SendCoins.feature +++ b/e2e-tests/cypress/e2e/SendCoins.feature @@ -12,9 +12,11 @@ Feature: Send coins Scenario: Send GDD to other user Given the user is logged in as "bob@baumeister.de" "Aa12345_" And the user navigates to page "/send" - When the user fills the send form with "raeuber@hotzenplotz.de" "120,50" "Some memo text" + When the user fills the send form with "raeuber@hotzenplotz.de" "120.50" "Some memo text" And the user submits the send form Then the transaction details are presented for confirmation When the user submits the transaction by confirming - Then the transaction details are displayed on the transcations page + And the user navigates to page "/transactions" + Then the transaction details are displayed on the transactions page + diff --git a/e2e-tests/cypress/e2e/models/SendPage.ts b/e2e-tests/cypress/e2e/models/SendPage.ts index ab2df6084..07b531c4a 100644 --- a/e2e-tests/cypress/e2e/models/SendPage.ts +++ b/e2e-tests/cypress/e2e/models/SendPage.ts @@ -1,6 +1,7 @@ /// export class SendPage { + confirmationBox = '.transaction-confirm-send' submitBtn = '.btn-gradido' enterReceiverEmail(email: string) { diff --git a/e2e-tests/cypress/support/step_definitions/send_coin_steps.ts b/e2e-tests/cypress/support/step_definitions/send_coin_steps.ts index b7c319c08..267de7dd1 100644 --- a/e2e-tests/cypress/support/step_definitions/send_coin_steps.ts +++ b/e2e-tests/cypress/support/step_definitions/send_coin_steps.ts @@ -14,7 +14,7 @@ When( And('the user submits the send form', () => { sendPage.submit() - cy.get('.transaction-confirm-send').should('be.visible') + cy.get(sendPage.confirmationBox).should('be.visible') }) @@ -52,3 +52,9 @@ When('the user submits the transaction by confirming', () => { cy.get('.align-items-center').contains('Räuber Hotzenplotz') cy.get('.align-items-center').contains('− 120.50 GDD') }) + + +Then('the transaction details are displayed on the transactions page', () => { + cy.get('div.mt-3 > div > div.test-list-group-item').eq(0).contains('div.gdd-transaction-list-item-name', 'Räuber Hotzenplotz') + cy.get('div.mt-3 > div > div.test-list-group-item').eq(0).contains('[data-test="send-amount"]', '− 120.50 GDD') +}) \ No newline at end of file diff --git a/frontend/src/components/Transactions/TransactionSend.vue b/frontend/src/components/Transactions/TransactionSend.vue index 62ac41ded..93a8aa98e 100644 --- a/frontend/src/components/Transactions/TransactionSend.vue +++ b/frontend/src/components/Transactions/TransactionSend.vue @@ -25,7 +25,7 @@
{{ $t('decay.types.send') }}
-
{{ amount | GDD }}
+
{{ amount | GDD }}
{{ $t('via_link') }} Date: Tue, 20 Jun 2023 10:37:54 +0200 Subject: [PATCH 07/94] add receive test to e2e feature send coins --- e2e-tests/cypress/e2e/SendCoins.feature | 26 +++++++-- e2e-tests/cypress/e2e/models/OverviewPage.ts | 2 + .../support/step_definitions/email_steps.ts | 54 +++++++++++++++++-- .../step_definitions/send_coin_steps.ts | 19 +++++-- .../Transactions/TransactionReceive.vue | 2 +- .../Transactions/TransactionSend.vue | 2 +- 6 files changed, 91 insertions(+), 14 deletions(-) diff --git a/e2e-tests/cypress/e2e/SendCoins.feature b/e2e-tests/cypress/e2e/SendCoins.feature index 3ff332012..0329b10f7 100644 --- a/e2e-tests/cypress/e2e/SendCoins.feature +++ b/e2e-tests/cypress/e2e/SendCoins.feature @@ -8,15 +8,33 @@ Feature: Send coins # | email | password | name | # | bob@baumeister.de | Aa12345_ | Bob Baumeister | # | raeuber@hotzenplotz.de | Aa12345_ | Räuber Hotzenplotz | - + Scenario: Send GDD to other user Given the user is logged in as "bob@baumeister.de" "Aa12345_" And the user navigates to page "/send" - When the user fills the send form with "raeuber@hotzenplotz.de" "120.50" "Some memo text" + When the user fills the send form with "raeuber@hotzenplotz.de" "" "Some memo text" And the user submits the send form Then the transaction details are presented for confirmation When the user submits the transaction by confirming And the user navigates to page "/transactions" - Then the transaction details are displayed on the transactions page - + Then the "" and "" are displayed on the "transactions" page + + Examples: + | receiverName | amount | + # | Räuber Hotzenplotz | 120.50 | + | Räuber Hotzenplotz | 120,50 | + Scenario: Receive GDD from other user + Given the user is logged in as "raeuber@hotzenplotz.de" "Aa12345_" + And the user receives the transaction e-mail about "" GDD from "" + When the user opens the "transaction" link in the browser + Then the "" and "" are displayed on the "overview" page + When the user navigates to page "/transactions" + Then the "" and "" are displayed on the "transactions" page + + Examples: + | senderName | amount | + # | Bob der Baumeister | 120.50 | + | Bob der Baumeister | 120,50 | + + diff --git a/e2e-tests/cypress/e2e/models/OverviewPage.ts b/e2e-tests/cypress/e2e/models/OverviewPage.ts index 345124c66..e8f881eba 100644 --- a/e2e-tests/cypress/e2e/models/OverviewPage.ts +++ b/e2e-tests/cypress/e2e/models/OverviewPage.ts @@ -2,6 +2,8 @@ export class OverviewPage { navbarName = '[data-test="navbar-item-username"]' + rightLastTransactionsList = '.rightside-last-transactions' + goto() { cy.visit('/overview') diff --git a/e2e-tests/cypress/support/step_definitions/email_steps.ts b/e2e-tests/cypress/support/step_definitions/email_steps.ts index d31e2474e..b0d88e9a7 100644 --- a/e2e-tests/cypress/support/step_definitions/email_steps.ts +++ b/e2e-tests/cypress/support/step_definitions/email_steps.ts @@ -1,9 +1,9 @@ -import { Then, When } from '@badeball/cypress-cucumber-preprocessor' +import { And, Then, When } from '@badeball/cypress-cucumber-preprocessor' +import { OverviewPage } from '../../e2e/models/OverviewPage' import { ResetPasswordPage } from '../../e2e/models/ResetPasswordPage' import { UserEMailSite } from '../../e2e/models/UserEMailSite' const userEMailSite = new UserEMailSite() -const resetPasswordPage = new ResetPasswordPage() Then('the user receives an e-mail containing the {string} link', (linkName: string) => { let emailSubject: string @@ -18,6 +18,10 @@ Then('the user receives an e-mail containing the {string} link', (linkName: stri emailSubject = 'asswor' linkPattern = /\/reset-password\/[0-9]+\d/ break + case 'transaction': + emailSubject = 'has sent you' + linkPattern = /\/overview/ + break default: throw new Error(`Error in "Then the user receives an e-mail containing the {string} link" step: incorrect linkname string "${linkName}"`) } @@ -51,9 +55,53 @@ Then('the user receives an e-mail containing the {string} link', (linkName: stri ) }) +And('the user receives the transaction e-mail about {string} GDD from {string}', (amount: string, senderName:string) => { + cy.origin( + Cypress.env('mailserverURL'), + { args: { amount, senderName, userEMailSite } }, + ({ amount, senderName, userEMailSite }) => { + const subject = `Gradido: ${senderName} has sent you ${amount} Gradido` + const linkPattern = /\/overview/ + cy.visit('/') + cy.get(userEMailSite.emailInbox).should('be.visible') + + cy.get(userEMailSite.emailList) + .find('.email-item') + .filter(`:contains(${subject})`) + .first() + .click() + + cy.get(userEMailSite.emailMeta) + .find(userEMailSite.emailSubject) + .contains(subject) + + cy.get('.email-content', { timeout: 2000}) + .find('.plain-text') + .contains(linkPattern) + .invoke('text') + .then((text) => { + const emailLink = text.match(linkPattern)[0] + cy.task('setEmailLink', emailLink) + }) + } + ) +}) + When('the user opens the {string} link in the browser', (linkName: string) => { cy.task('getEmailLink').then((emailLink) => { cy.visit(emailLink) }) - cy.get(resetPasswordPage.newPasswordInput).should('be.visible') + + switch (linkName) { + case 'activation': + const resetPasswordPage = new ResetPasswordPage() + cy.get(resetPasswordPage.newPasswordInput).should('be.visible') + break + case 'transaction': + const overviewPage = new OverviewPage() + cy.get(overviewPage.rightLastTransactionsList).should('be.visible') + break + default: + throw new Error(`Error in "Then the user receives an e-mail containing the {string} link" step: incorrect link name string "${linkName}"`) + } }) diff --git a/e2e-tests/cypress/support/step_definitions/send_coin_steps.ts b/e2e-tests/cypress/support/step_definitions/send_coin_steps.ts index 267de7dd1..2baf5968e 100644 --- a/e2e-tests/cypress/support/step_definitions/send_coin_steps.ts +++ b/e2e-tests/cypress/support/step_definitions/send_coin_steps.ts @@ -7,7 +7,7 @@ When( 'the user fills the send form with {string} {string} {string}', (email: string, amount: string, memoText: string) => { sendPage.enterReceiverEmail(email) - sendPage.enterAmount(amount) + sendPage.enterAmount(`${amount}`) sendPage.enterMemoText(memoText) } ) @@ -53,8 +53,17 @@ When('the user submits the transaction by confirming', () => { cy.get('.align-items-center').contains('− 120.50 GDD') }) - -Then('the transaction details are displayed on the transactions page', () => { - cy.get('div.mt-3 > div > div.test-list-group-item').eq(0).contains('div.gdd-transaction-list-item-name', 'Räuber Hotzenplotz') - cy.get('div.mt-3 > div > div.test-list-group-item').eq(0).contains('[data-test="send-amount"]', '− 120.50 GDD') +Then('the {string} and {string} are displayed on the {string} page', (name: string, amount: string, page: string) => { + switch (page) { + case 'overview': + cy.get('.align-items-center').contains(`${name}`) + cy.get('.align-items-center').contains(`${amount} GDD`) + break + case 'transactions': + cy.get('div.mt-3 > div > div.test-list-group-item').eq(0).contains('div.gdd-transaction-list-item-name', `${name}`) + cy.get('div.mt-3 > div > div.test-list-group-item').eq(0).contains('[data-test="transaction-amount"]', `${amount} GDD`) + break + default: + throw new Error(`Error in "Then the {string} and {string} are displayed on the {string}} page" step: incorrect page name string "${page}"`) + } }) \ No newline at end of file diff --git a/frontend/src/components/Transactions/TransactionReceive.vue b/frontend/src/components/Transactions/TransactionReceive.vue index 7778c6c6e..f9d776800 100644 --- a/frontend/src/components/Transactions/TransactionReceive.vue +++ b/frontend/src/components/Transactions/TransactionReceive.vue @@ -26,7 +26,7 @@
{{ $t('decay.types.receive') }}
-
{{ amount | GDD }}
+
{{ amount | GDD }}
{{ $t('via_link') }} {{ $t('decay.types.send') }}
-
{{ amount | GDD }}
+
{{ amount | GDD }}
{{ $t('via_link') }} Date: Tue, 20 Jun 2023 10:51:34 +0200 Subject: [PATCH 08/94] linting --- frontend/src/components/Transactions/TransactionReceive.vue | 4 +++- frontend/src/components/Transactions/TransactionSend.vue | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/Transactions/TransactionReceive.vue b/frontend/src/components/Transactions/TransactionReceive.vue index f9d776800..d6985ba16 100644 --- a/frontend/src/components/Transactions/TransactionReceive.vue +++ b/frontend/src/components/Transactions/TransactionReceive.vue @@ -26,7 +26,9 @@
{{ $t('decay.types.receive') }}
-
{{ amount | GDD }}
+
+ {{ amount | GDD }} +
{{ $t('via_link') }} {{ $t('decay.types.send') }}
-
{{ amount | GDD }}
+
+ {{ amount | GDD }} +
{{ $t('via_link') }} Date: Tue, 20 Jun 2023 11:09:45 +0200 Subject: [PATCH 09/94] fix send coin feature file --- e2e-tests/cypress/e2e/SendCoins.feature | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/e2e-tests/cypress/e2e/SendCoins.feature b/e2e-tests/cypress/e2e/SendCoins.feature index 0329b10f7..9abb68295 100644 --- a/e2e-tests/cypress/e2e/SendCoins.feature +++ b/e2e-tests/cypress/e2e/SendCoins.feature @@ -21,8 +21,7 @@ Feature: Send coins Examples: | receiverName | amount | - # | Räuber Hotzenplotz | 120.50 | - | Räuber Hotzenplotz | 120,50 | + | Räuber Hotzenplotz | 120.50 | Scenario: Receive GDD from other user Given the user is logged in as "raeuber@hotzenplotz.de" "Aa12345_" @@ -34,7 +33,5 @@ Feature: Send coins Examples: | senderName | amount | - # | Bob der Baumeister | 120.50 | - | Bob der Baumeister | 120,50 | - + | Bob der Baumeister | 120.50 | From 5345efed4eaef5aecbab288d26aefded2602a0d5 Mon Sep 17 00:00:00 2001 From: mahula Date: Tue, 20 Jun 2023 11:26:07 +0200 Subject: [PATCH 10/94] fix passwordreset e2e test --- e2e-tests/cypress/support/step_definitions/email_steps.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/e2e-tests/cypress/support/step_definitions/email_steps.ts b/e2e-tests/cypress/support/step_definitions/email_steps.ts index b0d88e9a7..9c994b7b8 100644 --- a/e2e-tests/cypress/support/step_definitions/email_steps.ts +++ b/e2e-tests/cypress/support/step_definitions/email_steps.ts @@ -88,13 +88,16 @@ And('the user receives the transaction e-mail about {string} GDD from {string}', }) When('the user opens the {string} link in the browser', (linkName: string) => { + const resetPasswordPage = new ResetPasswordPage() cy.task('getEmailLink').then((emailLink) => { cy.visit(emailLink) }) switch (linkName) { case 'activation': - const resetPasswordPage = new ResetPasswordPage() + cy.get(resetPasswordPage.newPasswordInput).should('be.visible') + break + case 'password reset': cy.get(resetPasswordPage.newPasswordInput).should('be.visible') break case 'transaction': From 39ee78467562075f50168cfc5996a45d39fb90cd Mon Sep 17 00:00:00 2001 From: mahula Date: Tue, 20 Jun 2023 11:32:36 +0200 Subject: [PATCH 11/94] fix send coins e2e test --- e2e-tests/cypress/e2e/SendCoins.feature | 2 +- e2e-tests/cypress/support/step_definitions/email_steps.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/e2e-tests/cypress/e2e/SendCoins.feature b/e2e-tests/cypress/e2e/SendCoins.feature index 9abb68295..169a120b9 100644 --- a/e2e-tests/cypress/e2e/SendCoins.feature +++ b/e2e-tests/cypress/e2e/SendCoins.feature @@ -33,5 +33,5 @@ Feature: Send coins Examples: | senderName | amount | - | Bob der Baumeister | 120.50 | + | Bob der Baumeister | 120,50 | diff --git a/e2e-tests/cypress/support/step_definitions/email_steps.ts b/e2e-tests/cypress/support/step_definitions/email_steps.ts index 9c994b7b8..12954fe86 100644 --- a/e2e-tests/cypress/support/step_definitions/email_steps.ts +++ b/e2e-tests/cypress/support/step_definitions/email_steps.ts @@ -19,7 +19,7 @@ Then('the user receives an e-mail containing the {string} link', (linkName: stri linkPattern = /\/reset-password\/[0-9]+\d/ break case 'transaction': - emailSubject = 'has sent you' + emailSubject = 'Gradido gesendet' linkPattern = /\/overview/ break default: From 65965a2ffd40c7f07b734de8cd0844b0ab8f46b8 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 20 Jun 2023 11:34:48 +0200 Subject: [PATCH 12/94] add MODERATOR contribution message type --- backend/src/graphql/arg/ContributionMessageArgs.ts | 5 +++++ .../enum/{MessageType.ts => ContributionMessageType.ts} | 1 + backend/src/graphql/resolver/ContributionMessageResolver.ts | 2 +- backend/src/graphql/resolver/ContributionResolver.ts | 2 +- 4 files changed, 8 insertions(+), 2 deletions(-) rename backend/src/graphql/enum/{MessageType.ts => ContributionMessageType.ts} (73%) diff --git a/backend/src/graphql/arg/ContributionMessageArgs.ts b/backend/src/graphql/arg/ContributionMessageArgs.ts index d36e1832d..6482793aa 100644 --- a/backend/src/graphql/arg/ContributionMessageArgs.ts +++ b/backend/src/graphql/arg/ContributionMessageArgs.ts @@ -1,5 +1,7 @@ import { ArgsType, Field, Int, InputType } from 'type-graphql' +import { ContributionMessageType } from '@enum/ContributionMessageType' + @InputType() @ArgsType() export class ContributionMessageArgs { @@ -8,4 +10,7 @@ export class ContributionMessageArgs { @Field(() => String) message: string + + @Field(() => ContributionMessageType, { defaultValue: ContributionMessageType.DIALOG }) + messageType: ContributionMessageType } diff --git a/backend/src/graphql/enum/MessageType.ts b/backend/src/graphql/enum/ContributionMessageType.ts similarity index 73% rename from backend/src/graphql/enum/MessageType.ts rename to backend/src/graphql/enum/ContributionMessageType.ts index a4606e464..83b011a0b 100644 --- a/backend/src/graphql/enum/MessageType.ts +++ b/backend/src/graphql/enum/ContributionMessageType.ts @@ -3,6 +3,7 @@ import { registerEnumType } from 'type-graphql' export enum ContributionMessageType { HISTORY = 'HISTORY', DIALOG = 'DIALOG', + MODERATOR = 'MODERATOR', // messages for moderator communication, can only be seen by moderators } registerEnumType(ContributionMessageType, { diff --git a/backend/src/graphql/resolver/ContributionMessageResolver.ts b/backend/src/graphql/resolver/ContributionMessageResolver.ts index b7fd37787..56a7a1ec9 100644 --- a/backend/src/graphql/resolver/ContributionMessageResolver.ts +++ b/backend/src/graphql/resolver/ContributionMessageResolver.ts @@ -8,8 +8,8 @@ import { Arg, Args, Authorized, Ctx, Int, Mutation, Query, Resolver } from 'type import { ContributionMessageArgs } from '@arg/ContributionMessageArgs' import { Paginated } from '@arg/Paginated' +import { ContributionMessageType } from '@enum/ContributionMessageType' import { ContributionStatus } from '@enum/ContributionStatus' -import { ContributionMessageType } from '@enum/MessageType' import { Order } from '@enum/Order' import { ContributionMessage, ContributionMessageListResult } from '@model/ContributionMessage' diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index fa1590523..42ec2f371 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -11,9 +11,9 @@ import { AdminCreateContributionArgs } from '@arg/AdminCreateContributionArgs' import { AdminUpdateContributionArgs } from '@arg/AdminUpdateContributionArgs' import { ContributionArgs } from '@arg/ContributionArgs' import { Paginated } from '@arg/Paginated' +import { ContributionMessageType } from '@enum/ContributionMessageType' import { ContributionStatus } from '@enum/ContributionStatus' import { ContributionType } from '@enum/ContributionType' -import { ContributionMessageType } from '@enum/MessageType' import { Order } from '@enum/Order' import { TransactionTypeId } from '@enum/TransactionTypeId' import { AdminUpdateContribution } from '@model/AdminUpdateContribution' From 85751f43b65778939234cf0bfc6e28af5c69fc0c Mon Sep 17 00:00:00 2001 From: mahula Date: Tue, 20 Jun 2023 11:32:36 +0200 Subject: [PATCH 13/94] fix send coins e2e test --- e2e-tests/cypress/support/step_definitions/email_steps.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-tests/cypress/support/step_definitions/email_steps.ts b/e2e-tests/cypress/support/step_definitions/email_steps.ts index 12954fe86..55cafd600 100644 --- a/e2e-tests/cypress/support/step_definitions/email_steps.ts +++ b/e2e-tests/cypress/support/step_definitions/email_steps.ts @@ -60,7 +60,7 @@ And('the user receives the transaction e-mail about {string} GDD from {string}', Cypress.env('mailserverURL'), { args: { amount, senderName, userEMailSite } }, ({ amount, senderName, userEMailSite }) => { - const subject = `Gradido: ${senderName} has sent you ${amount} Gradido` + const subject = `Gradido: ${senderName} hat dir ${amount} Gradido gesendet` const linkPattern = /\/overview/ cy.visit('/') cy.get(userEMailSite.emailInbox).should('be.visible') From 732560aaac7e960ac606897c83cb9a51f9a9585f Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 20 Jun 2023 12:11:44 +0200 Subject: [PATCH 14/94] add message type arg to admin create contribution message --- .../ContributionMessageResolver.test.ts | 36 ++++++++++++++++++- .../resolver/ContributionMessageResolver.ts | 4 +-- backend/src/seeds/graphql/mutations.ts | 8 +++-- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionMessageResolver.test.ts b/backend/src/graphql/resolver/ContributionMessageResolver.test.ts index 1b6b034c4..f3b7a636e 100644 --- a/backend/src/graphql/resolver/ContributionMessageResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionMessageResolver.test.ts @@ -217,6 +217,33 @@ describe('ContributionMessageResolver', () => { ) }) }) + + describe('contribution message type MODERATOR', () => { + it('creates ContributionMessage', async () => { + await expect( + mutate({ + mutation: adminCreateContributionMessage, + variables: { + contributionId: result.data.createContribution.id, + message: 'Internal moderator communication', + messageType: 'MODERATOR', + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + data: { + adminCreateContributionMessage: expect.objectContaining({ + id: expect.any(Number), + message: 'Internal moderator communication', + type: 'MODERATOR', + userFirstName: 'Peter', + userLastName: 'Lustig', + }), + }, + }), + ) + }) + }) }) }) @@ -395,7 +422,7 @@ describe('ContributionMessageResolver', () => { expect.objectContaining({ data: { listContributionMessages: { - count: 2, + count: 3, messages: expect.arrayContaining([ expect.objectContaining({ id: expect.any(Number), @@ -411,6 +438,13 @@ describe('ContributionMessageResolver', () => { userFirstName: 'Bibi', userLastName: 'Bloxberg', }), + expect.objectContaining({ + id: expect.any(Number), + message: 'Internal moderator communication', + type: 'MODERATOR', + userFirstName: 'Peter', + userLastName: 'Lustig', + }), ]), }, }, diff --git a/backend/src/graphql/resolver/ContributionMessageResolver.ts b/backend/src/graphql/resolver/ContributionMessageResolver.ts index 56a7a1ec9..25f2a2560 100644 --- a/backend/src/graphql/resolver/ContributionMessageResolver.ts +++ b/backend/src/graphql/resolver/ContributionMessageResolver.ts @@ -104,7 +104,7 @@ export class ContributionMessageResolver { @Authorized([RIGHTS.ADMIN_CREATE_CONTRIBUTION_MESSAGE]) @Mutation(() => ContributionMessage) async adminCreateContributionMessage( - @Args() { contributionId, message }: ContributionMessageArgs, + @Args() { contributionId, message, messageType }: ContributionMessageArgs, @Ctx() context: Context, ): Promise { const moderator = getUser(context) @@ -133,7 +133,7 @@ export class ContributionMessageResolver { contributionMessage.createdAt = new Date() contributionMessage.message = message contributionMessage.userId = moderator.id - contributionMessage.type = ContributionMessageType.DIALOG + contributionMessage.type = messageType contributionMessage.isModerator = true await queryRunner.manager.insert(DbContributionMessage, contributionMessage) diff --git a/backend/src/seeds/graphql/mutations.ts b/backend/src/seeds/graphql/mutations.ts index 22e0b1b09..29d08b20a 100644 --- a/backend/src/seeds/graphql/mutations.ts +++ b/backend/src/seeds/graphql/mutations.ts @@ -284,8 +284,12 @@ export const createContributionMessage = gql` ` export const adminCreateContributionMessage = gql` - mutation ($contributionId: Int!, $message: String!) { - adminCreateContributionMessage(contributionId: $contributionId, message: $message) { + mutation ($contributionId: Int!, $message: String!, $messageType: ContributionMessageType) { + adminCreateContributionMessage( + contributionId: $contributionId + message: $message + messageType: $messageType + ) { id message createdAt From 4d119f8911d36fa863f58b7900e52feb3815cce8 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 20 Jun 2023 12:44:35 +0200 Subject: [PATCH 15/94] find contribution messages helper function --- .../resolver/ContributionMessageResolver.ts | 18 ++++++------- .../resolver/util/findContributionMessages.ts | 27 +++++++++++++++++++ 2 files changed, 35 insertions(+), 10 deletions(-) create mode 100644 backend/src/graphql/resolver/util/findContributionMessages.ts diff --git a/backend/src/graphql/resolver/ContributionMessageResolver.ts b/backend/src/graphql/resolver/ContributionMessageResolver.ts index 25f2a2560..69931467b 100644 --- a/backend/src/graphql/resolver/ContributionMessageResolver.ts +++ b/backend/src/graphql/resolver/ContributionMessageResolver.ts @@ -22,6 +22,8 @@ import { import { Context, getUser } from '@/server/context' import { LogError } from '@/server/LogError' +import { findContributionMessages } from './util/findContributionMessages' + @Resolver() export class ContributionMessageResolver { @Authorized([RIGHTS.CREATE_CONTRIBUTION_MESSAGE]) @@ -82,16 +84,12 @@ export class ContributionMessageResolver { @Args() { currentPage = 1, pageSize = 5, order = Order.DESC }: Paginated, ): Promise { - const [contributionMessages, count] = await getConnection() - .createQueryBuilder() - .select('cm') - .from(DbContributionMessage, 'cm') - .leftJoinAndSelect('cm.user', 'u') - .where({ contributionId }) - .orderBy('cm.createdAt', order) - .limit(pageSize) - .offset((currentPage - 1) * pageSize) - .getManyAndCount() + const [contributionMessages, count] = await findContributionMessages({ + contributionId, + currentPage, + pageSize, + order, + }) return { count, diff --git a/backend/src/graphql/resolver/util/findContributionMessages.ts b/backend/src/graphql/resolver/util/findContributionMessages.ts new file mode 100644 index 000000000..90555cca7 --- /dev/null +++ b/backend/src/graphql/resolver/util/findContributionMessages.ts @@ -0,0 +1,27 @@ +import { ContributionMessage as DbContributionMessage } from '@entity/ContributionMessage' + +import { Order } from '@enum/Order' + +interface FindContributionMessagesOptions { + contributionId: number + pageSize: number + currentPage: number + order: Order +} + +export const findContributionMessages = async ( + options: FindContributionMessagesOptions, +): Promise<[DbContributionMessage[], number]> => { + const { contributionId, pageSize, currentPage, order } = options + return DbContributionMessage.findAndCount({ + where: { + contributionId, + }, + relations: ['user'], + order: { + createdAt: order, + }, + skip: (currentPage - 1) * pageSize, + take: pageSize, + }) +} From 1e6d4cfe4b00d265c03f09da21752520f08f52d6 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 20 Jun 2023 13:11:36 +0200 Subject: [PATCH 16/94] add admin list contribution message query --- backend/src/auth/RIGHTS.ts | 1 + .../ContributionMessageResolver.test.ts | 82 ++++++++++++++++++- .../resolver/ContributionMessageResolver.ts | 23 ++++++ .../resolver/util/findContributionMessages.ts | 11 ++- backend/src/seeds/graphql/queries.ts | 23 ++++++ 5 files changed, 137 insertions(+), 3 deletions(-) diff --git a/backend/src/auth/RIGHTS.ts b/backend/src/auth/RIGHTS.ts index b3627ff7a..772c907cb 100644 --- a/backend/src/auth/RIGHTS.ts +++ b/backend/src/auth/RIGHTS.ts @@ -53,4 +53,5 @@ export enum RIGHTS { ADMIN_CREATE_CONTRIBUTION_MESSAGE = 'ADMIN_CREATE_CONTRIBUTION_MESSAGE', DENY_CONTRIBUTION = 'DENY_CONTRIBUTION', ADMIN_OPEN_CREATIONS = 'ADMIN_OPEN_CREATIONS', + ADMIN_LIST_ALL_CONTRIBUTION_MESSAGES = 'ADMIN_LIST_ALL_CONTRIBUTION_MESSAGES', } diff --git a/backend/src/graphql/resolver/ContributionMessageResolver.test.ts b/backend/src/graphql/resolver/ContributionMessageResolver.test.ts index f3b7a636e..f80fce939 100644 --- a/backend/src/graphql/resolver/ContributionMessageResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionMessageResolver.test.ts @@ -20,7 +20,7 @@ import { createContributionMessage, login, } from '@/seeds/graphql/mutations' -import { listContributionMessages } from '@/seeds/graphql/queries' +import { listContributionMessages, adminListContributionMessages } from '@/seeds/graphql/queries' import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' import { peterLustig } from '@/seeds/users/peter-lustig' @@ -412,7 +412,7 @@ describe('ContributionMessageResolver', () => { resetToken() }) - it('returns a list of contributionmessages', async () => { + it('returns a list of contributionmessages without type MODERATOR', async () => { await expect( mutate({ mutation: listContributionMessages, @@ -422,6 +422,84 @@ describe('ContributionMessageResolver', () => { expect.objectContaining({ data: { listContributionMessages: { + count: 2, + messages: expect.arrayContaining([ + expect.objectContaining({ + id: expect.any(Number), + message: 'Admin Test', + type: 'DIALOG', + userFirstName: 'Peter', + userLastName: 'Lustig', + }), + expect.objectContaining({ + id: expect.any(Number), + message: 'User Test', + type: 'DIALOG', + userFirstName: 'Bibi', + userLastName: 'Bloxberg', + }), + ]), + }, + }, + }), + ) + }) + }) + }) + + describe('adminListContributionMessages', () => { + describe('unauthenticated', () => { + it('returns an error', async () => { + await expect( + mutate({ + mutation: adminListContributionMessages, + variables: { contributionId: 1 }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('401 Unauthorized')], + }), + ) + }) + }) + + describe('authenticated as user', () => { + it('returns an error', async () => { + await expect( + mutate({ + mutation: adminListContributionMessages, + variables: { contributionId: 1 }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('401 Unauthorized')], + }), + ) + }) + }) + + describe('authenticated', () => { + beforeAll(async () => { + await mutate({ + mutation: login, + variables: { email: 'peter@lustig.de', password: 'Aa12345_' }, + }) + }) + + afterAll(() => { + resetToken() + }) + + it('returns a list of contributionmessages with type MODERATOR', async () => { + await expect( + mutate({ + mutation: adminListContributionMessages, + variables: { contributionId: result.data.createContribution.id }, + }), + ).resolves.toEqual( + expect.objectContaining({ + data: { + adminListContributionMessages: { count: 3, messages: expect.arrayContaining([ expect.objectContaining({ diff --git a/backend/src/graphql/resolver/ContributionMessageResolver.ts b/backend/src/graphql/resolver/ContributionMessageResolver.ts index 69931467b..6e062fe6e 100644 --- a/backend/src/graphql/resolver/ContributionMessageResolver.ts +++ b/backend/src/graphql/resolver/ContributionMessageResolver.ts @@ -99,6 +99,29 @@ export class ContributionMessageResolver { } } + @Authorized([RIGHTS.ADMIN_LIST_ALL_CONTRIBUTION_MESSAGES]) + @Query(() => ContributionMessageListResult) + async adminListContributionMessages( + @Arg('contributionId', () => Int) contributionId: number, + @Args() + { currentPage = 1, pageSize = 5, order = Order.DESC }: Paginated, + ): Promise { + const [contributionMessages, count] = await findContributionMessages({ + contributionId, + currentPage, + pageSize, + order, + showModeratorType: true, + }) + + return { + count, + messages: contributionMessages.map( + (message) => new ContributionMessage(message, message.user), + ), + } + } + @Authorized([RIGHTS.ADMIN_CREATE_CONTRIBUTION_MESSAGE]) @Mutation(() => ContributionMessage) async adminCreateContributionMessage( diff --git a/backend/src/graphql/resolver/util/findContributionMessages.ts b/backend/src/graphql/resolver/util/findContributionMessages.ts index 90555cca7..06b896898 100644 --- a/backend/src/graphql/resolver/util/findContributionMessages.ts +++ b/backend/src/graphql/resolver/util/findContributionMessages.ts @@ -1,5 +1,7 @@ +import { In } from '@dbTools/typeorm' import { ContributionMessage as DbContributionMessage } from '@entity/ContributionMessage' +import { ContributionMessageType } from '@enum/ContributionMessageType' import { Order } from '@enum/Order' interface FindContributionMessagesOptions { @@ -7,15 +9,22 @@ interface FindContributionMessagesOptions { pageSize: number currentPage: number order: Order + showModeratorType?: boolean } export const findContributionMessages = async ( options: FindContributionMessagesOptions, ): Promise<[DbContributionMessage[], number]> => { - const { contributionId, pageSize, currentPage, order } = options + const { contributionId, pageSize, currentPage, order, showModeratorType } = options + + const messageTypes = [ContributionMessageType.DIALOG, ContributionMessageType.HISTORY] + + if (showModeratorType) messageTypes.push(ContributionMessageType.MODERATOR) + return DbContributionMessage.findAndCount({ where: { contributionId, + type: In(messageTypes), }, relations: ['user'], order: { diff --git a/backend/src/seeds/graphql/queries.ts b/backend/src/seeds/graphql/queries.ts index a964cdb3a..f82882f97 100644 --- a/backend/src/seeds/graphql/queries.ts +++ b/backend/src/seeds/graphql/queries.ts @@ -349,6 +349,29 @@ export const listContributionMessages = gql` } ` +export const adminListContributionMessages = gql` + query ($contributionId: Int!, $pageSize: Int = 25, $currentPage: Int = 1, $order: Order = ASC) { + adminListContributionMessages( + contributionId: $contributionId + pageSize: $pageSize + currentPage: $currentPage + order: $order + ) { + count + messages { + id + message + createdAt + updatedAt + type + userFirstName + userLastName + userId + } + } + } +` + export const user = gql` query ($identifier: String!) { user(identifier: $identifier) { From f0eae909b99118e78961f1c80751a28f356d9168 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 20 Jun 2023 13:16:35 +0200 Subject: [PATCH 17/94] fix authentication test --- .../graphql/resolver/ContributionMessageResolver.test.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/backend/src/graphql/resolver/ContributionMessageResolver.test.ts b/backend/src/graphql/resolver/ContributionMessageResolver.test.ts index f80fce939..2df996c64 100644 --- a/backend/src/graphql/resolver/ContributionMessageResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionMessageResolver.test.ts @@ -464,6 +464,13 @@ describe('ContributionMessageResolver', () => { }) describe('authenticated as user', () => { + beforeAll(async () => { + await mutate({ + mutation: login, + variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, + }) + }) + it('returns an error', async () => { await expect( mutate({ From ba7197b2e66920a96cffb49da25e381bb4dd7b1d Mon Sep 17 00:00:00 2001 From: mahula Date: Tue, 20 Jun 2023 16:35:52 +0200 Subject: [PATCH 18/94] adaptreceive coins test to language dependency --- e2e-tests/cypress/e2e/SendCoins.feature | 28 ++++++++++++------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/e2e-tests/cypress/e2e/SendCoins.feature b/e2e-tests/cypress/e2e/SendCoins.feature index 169a120b9..ae79c4a6e 100644 --- a/e2e-tests/cypress/e2e/SendCoins.feature +++ b/e2e-tests/cypress/e2e/SendCoins.feature @@ -9,27 +9,27 @@ Feature: Send coins # | bob@baumeister.de | Aa12345_ | Bob Baumeister | # | raeuber@hotzenplotz.de | Aa12345_ | Räuber Hotzenplotz | - Scenario: Send GDD to other user - Given the user is logged in as "bob@baumeister.de" "Aa12345_" - And the user navigates to page "/send" - When the user fills the send form with "raeuber@hotzenplotz.de" "" "Some memo text" - And the user submits the send form - Then the transaction details are presented for confirmation - When the user submits the transaction by confirming - And the user navigates to page "/transactions" - Then the "" and "" are displayed on the "transactions" page + # Scenario: Send GDD to other user + # Given the user is logged in as "bob@baumeister.de" "Aa12345_" + # And the user navigates to page "/send" + # When the user fills the send form with "raeuber@hotzenplotz.de" "" "Some memo text" + # And the user submits the send form + # Then the transaction details are presented for confirmation + # When the user submits the transaction by confirming + # And the user navigates to page "/transactions" + # Then the "" and "" are displayed on the "transactions" page - Examples: - | receiverName | amount | - | Räuber Hotzenplotz | 120.50 | + # Examples: + # | receiverName | amount | + # | Räuber Hotzenplotz | 120.50 | Scenario: Receive GDD from other user Given the user is logged in as "raeuber@hotzenplotz.de" "Aa12345_" And the user receives the transaction e-mail about "" GDD from "" When the user opens the "transaction" link in the browser - Then the "" and "" are displayed on the "overview" page + Then the "" and "120.50" are displayed on the "overview" page When the user navigates to page "/transactions" - Then the "" and "" are displayed on the "transactions" page + Then the "" and "120.50" are displayed on the "transactions" page Examples: | senderName | amount | From febc18a85da5b4f48233b086ab5fc56deefada56 Mon Sep 17 00:00:00 2001 From: mahula Date: Tue, 20 Jun 2023 16:35:52 +0200 Subject: [PATCH 19/94] adaptreceive coins test to language dependency --- e2e-tests/cypress/e2e/SendCoins.feature | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/e2e-tests/cypress/e2e/SendCoins.feature b/e2e-tests/cypress/e2e/SendCoins.feature index ae79c4a6e..f9762e825 100644 --- a/e2e-tests/cypress/e2e/SendCoins.feature +++ b/e2e-tests/cypress/e2e/SendCoins.feature @@ -3,11 +3,11 @@ Feature: Send coins I want to send and receive GDD I want to see transaction details on overview and transactions pages - # Background: - # Given the following "users" are in the database: - # | email | password | name | - # | bob@baumeister.de | Aa12345_ | Bob Baumeister | - # | raeuber@hotzenplotz.de | Aa12345_ | Räuber Hotzenplotz | + Background: + Given the following "users" are in the database: + | email | password | name | + | bob@baumeister.de | Aa12345_ | Bob Baumeister | + | raeuber@hotzenplotz.de | Aa12345_ | Räuber Hotzenplotz | # Scenario: Send GDD to other user # Given the user is logged in as "bob@baumeister.de" "Aa12345_" From aed4b26f3a41ced29694183fb8334389b5910e7e Mon Sep 17 00:00:00 2001 From: mahula Date: Tue, 20 Jun 2023 16:35:52 +0200 Subject: [PATCH 20/94] adaptreceive coins test to language dependency --- e2e-tests/cypress/e2e/SendCoins.feature | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/e2e-tests/cypress/e2e/SendCoins.feature b/e2e-tests/cypress/e2e/SendCoins.feature index f9762e825..4be341615 100644 --- a/e2e-tests/cypress/e2e/SendCoins.feature +++ b/e2e-tests/cypress/e2e/SendCoins.feature @@ -9,19 +9,19 @@ Feature: Send coins | bob@baumeister.de | Aa12345_ | Bob Baumeister | | raeuber@hotzenplotz.de | Aa12345_ | Räuber Hotzenplotz | - # Scenario: Send GDD to other user - # Given the user is logged in as "bob@baumeister.de" "Aa12345_" - # And the user navigates to page "/send" - # When the user fills the send form with "raeuber@hotzenplotz.de" "" "Some memo text" - # And the user submits the send form - # Then the transaction details are presented for confirmation - # When the user submits the transaction by confirming - # And the user navigates to page "/transactions" - # Then the "" and "" are displayed on the "transactions" page + Scenario: Send GDD to other user + Given the user is logged in as "bob@baumeister.de" "Aa12345_" + And the user navigates to page "/send" + When the user fills the send form with "raeuber@hotzenplotz.de" "" "Some memo text" + And the user submits the send form + Then the transaction details are presented for confirmation + When the user submits the transaction by confirming + And the user navigates to page "/transactions" + Then the "" and "" are displayed on the "transactions" page - # Examples: - # | receiverName | amount | - # | Räuber Hotzenplotz | 120.50 | + Examples: + | receiverName | amount | + | Räuber Hotzenplotz | 120.50 | Scenario: Receive GDD from other user Given the user is logged in as "raeuber@hotzenplotz.de" "Aa12345_" From 2879cd79df9b43345b758a0ae47d1ca318ab2a72 Mon Sep 17 00:00:00 2001 From: mahula Date: Tue, 20 Jun 2023 16:35:52 +0200 Subject: [PATCH 21/94] adaptreceive coins test to language dependency --- e2e-tests/cypress/e2e/SendCoins.feature | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/e2e-tests/cypress/e2e/SendCoins.feature b/e2e-tests/cypress/e2e/SendCoins.feature index 4be341615..75049c83f 100644 --- a/e2e-tests/cypress/e2e/SendCoins.feature +++ b/e2e-tests/cypress/e2e/SendCoins.feature @@ -3,11 +3,11 @@ Feature: Send coins I want to send and receive GDD I want to see transaction details on overview and transactions pages - Background: - Given the following "users" are in the database: - | email | password | name | - | bob@baumeister.de | Aa12345_ | Bob Baumeister | - | raeuber@hotzenplotz.de | Aa12345_ | Räuber Hotzenplotz | + # Background: + # Given the following "users" are in the database: + # | email | password | name | + # | bob@baumeister.de | Aa12345_ | Bob Baumeister | + # | raeuber@hotzenplotz.de | Aa12345_ | Räuber Hotzenplotz | Scenario: Send GDD to other user Given the user is logged in as "bob@baumeister.de" "Aa12345_" From d742697a34ee9bd579db6921fc48576c6d665c78 Mon Sep 17 00:00:00 2001 From: ogerly Date: Wed, 21 Jun 2023 12:24:00 +0200 Subject: [PATCH 22/94] add moderator messages message type, add mutation adminListContributionMessages --- .../ContributionMessagesFormular.spec.js | 10 ++++--- .../ContributionMessagesFormular.vue | 26 ++++++++++++++++--- .../ContributionMessagesList.vue | 7 ++--- .../graphql/adminListContributionMessages.js | 24 +++++++++++++++++ 4 files changed, 58 insertions(+), 9 deletions(-) create mode 100644 admin/src/graphql/adminListContributionMessages.js diff --git a/admin/src/components/ContributionMessages/ContributionMessagesFormular.spec.js b/admin/src/components/ContributionMessages/ContributionMessagesFormular.spec.js index a81009c09..c575ba01c 100644 --- a/admin/src/components/ContributionMessages/ContributionMessagesFormular.spec.js +++ b/admin/src/components/ContributionMessages/ContributionMessagesFormular.spec.js @@ -64,7 +64,7 @@ describe('ContributionMessagesFormular', () => { text: 'text form message', }, }) - await wrapper.find('form').trigger('submit') + await wrapper.find('[data-test="submit-dialog"]').trigger('click') }) it('emitted "get-list-contribution-messages" with data', async () => { @@ -84,7 +84,7 @@ describe('ContributionMessagesFormular', () => { beforeEach(async () => { apolloMutateMock.mockRejectedValue({ message: 'OUCH!' }) wrapper = Wrapper() - await wrapper.find('form').trigger('submit') + await wrapper.find('[data-test="submit-dialog"]').trigger('submit') }) it('toasts an error message', () => { @@ -100,7 +100,11 @@ describe('ContributionMessagesFormular', () => { }, }) wrapper = Wrapper() - await wrapper.find('form').trigger('submit') + await wrapper.find('data-test="submit-dialog').trigger('submit') + }) + + it('moderatorMesage has `DIALOG`', () => { + expect(wrapper.vm.messageType).toBeCalledWith('DIALOG') }) it('toasts an success message', () => { diff --git a/admin/src/components/ContributionMessages/ContributionMessagesFormular.vue b/admin/src/components/ContributionMessages/ContributionMessagesFormular.vue index 3a5d6e0b8..a13df5ef9 100644 --- a/admin/src/components/ContributionMessages/ContributionMessagesFormular.vue +++ b/admin/src/components/ContributionMessages/ContributionMessagesFormular.vue @@ -1,7 +1,7 @@ @@ -39,13 +47,14 @@ export default { type: Object, required: true, }, + contributionUserId: { + type: Number, + required: true, + }, }, computed: { isModerator() { - return ( - this.message.userFirstName === this.$store.state.moderator.firstName && - this.message.userLastName === this.$store.state.moderator.lastName - ) + return this.contributionUserId !== this.message.userId }, isModeratorMessage() { return this.message.type === 'MODERATOR' diff --git a/admin/src/components/Tables/OpenCreationsTable.vue b/admin/src/components/Tables/OpenCreationsTable.vue index 9d93eba60..33e9bb141 100644 --- a/admin/src/components/Tables/OpenCreationsTable.vue +++ b/admin/src/components/Tables/OpenCreationsTable.vue @@ -103,6 +103,7 @@
From 89a6305c4571f3c9b99c0ceafac828bf7c02ddc0 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 26 Jun 2023 13:12:42 +0200 Subject: [PATCH 32/94] feat(database): update typeorm --- backend/src/graphql/resolver/UserResolver.ts | 36 +-- backend/src/webhook/elopage.ts | 2 +- database/package.json | 2 +- database/yarn.lock | 258 ++++++++----------- 4 files changed, 130 insertions(+), 168 deletions(-) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 9df6b861b..19f59e1a3 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -270,7 +270,7 @@ export class UserResolver { if (redeemCode) { if (redeemCode.match(/^CL-/)) { const contributionLink = await DbContributionLink.findOne({ - code: redeemCode.replace('CL-', ''), + where: { code: redeemCode.replace('CL-', '') }, }) logger.info('redeemCode found contributionLink', contributionLink) if (contributionLink) { @@ -278,7 +278,7 @@ export class UserResolver { eventRegisterRedeem.involvedContributionLink = contributionLink } } else { - const transactionLink = await DbTransactionLink.findOne({ code: redeemCode }) + const transactionLink = await DbTransactionLink.findOne({ where: { code: redeemCode } }) logger.info('redeemCode found transactionLink', transactionLink) if (transactionLink) { dbUser.referrerId = transactionLink.userId @@ -403,10 +403,10 @@ export class UserResolver { } // load code - const userContact = await DbUserContact.findOneOrFail( - { emailVerificationCode: code }, - { relations: ['user'] }, - ).catch(() => { + const userContact = await DbUserContact.findOne({ + where: { emailVerificationCode: code }, + relations: ['user'], + }).catch(() => { throw new LogError('Could not login with emailVerificationCode') }) logger.debug('userContact loaded...') @@ -474,7 +474,7 @@ export class UserResolver { @Query(() => Boolean) async queryOptIn(@Arg('optIn') optIn: string): Promise { logger.info(`queryOptIn(${optIn})...`) - const userContact = await DbUserContact.findOneOrFail({ emailVerificationCode: optIn }) + const userContact = await DbUserContact.findOneOrFail({ where: { emailVerificationCode: optIn } }) logger.debug('found optInCode', userContact) // Code is only valid for `CONFIG.EMAIL_CODE_VALID_TIME` minutes if (!isEmailVerificationCodeValid(userContact.updatedAt || userContact.createdAt)) { @@ -705,7 +705,7 @@ export class UserResolver { @Ctx() context: Context, ): Promise { - const user = await DbUser.findOne({ id: userId }) + const user = await DbUser.findOne({ where: { id: userId } }) // user exists ? if (!user) { throw new LogError('Could not find user with given ID', userId) @@ -734,7 +734,7 @@ export class UserResolver { } await user.save() await EVENT_ADMIN_USER_ROLE_SET(user, moderator) - const newUser = await DbUser.findOne({ id: userId }) + const newUser = await DbUser.findOne({ where: { id: userId } }) return newUser ? newUser.isAdmin : null } @@ -757,7 +757,7 @@ export class UserResolver { // soft-delete user await user.softRemove() await EVENT_ADMIN_USER_DELETE(user, moderator) - const newUser = await DbUser.findOne({ id: userId }, { withDeleted: true }) + const newUser = await DbUser.findOne({ where: { id: userId }, withDeleted: true }) return newUser ? newUser.deletedAt : null } @@ -767,7 +767,7 @@ export class UserResolver { @Arg('userId', () => Int) userId: number, @Ctx() context: Context, ): Promise { - const user = await DbUser.findOne({ id: userId }, { withDeleted: true }) + const user = await DbUser.findOne({ where: { id: userId }, withDeleted: true }) if (!user) { throw new LogError('Could not find user with given ID', userId) } @@ -819,10 +819,11 @@ export class UserResolver { } export async function findUserByEmail(email: string): Promise { - const dbUserContact = await DbUserContact.findOneOrFail( - { email }, - { withDeleted: true, relations: ['user'] }, - ).catch(() => { + const dbUserContact = await DbUserContact.findOneOrFail({ + where: { email }, + withDeleted: true, + relations: ['user'] + }).catch(() => { throw new LogError('No user with this credentials', email) }) const dbUser = dbUserContact.user @@ -831,7 +832,10 @@ export async function findUserByEmail(email: string): Promise { } async function checkEmailExists(email: string): Promise { - const userContact = await DbUserContact.findOne({ email }, { withDeleted: true }) + const userContact = await DbUserContact.findOne({ + where: { email }, + withDeleted: true, + }) if (userContact) { return true } diff --git a/backend/src/webhook/elopage.ts b/backend/src/webhook/elopage.ts index 07e7d4ecf..940b80dd1 100644 --- a/backend/src/webhook/elopage.ts +++ b/backend/src/webhook/elopage.ts @@ -135,7 +135,7 @@ export const elopageWebhook = async (req: any, res: any): Promise => { // Do we already have such a user? // if ((await dbUser.count({ email })) !== 0) { - if ((await dbUserContact.count({ email })) !== 0) { + if ((await dbUserContact.count({ where: { email } })) !== 0) { // eslint-disable-next-line no-console console.log(`Did not create User - already exists with email: ${email}`) return diff --git a/database/package.json b/database/package.json index abc69d21d..c45783a7b 100644 --- a/database/package.json +++ b/database/package.json @@ -46,7 +46,7 @@ "mysql2": "^2.3.0", "reflect-metadata": "^0.1.13", "ts-mysql-migrate": "^1.0.2", - "typeorm": "^0.2.38", + "typeorm": "^0.3.16", "uuid": "^8.3.2" }, "engines": { diff --git a/database/yarn.lock b/database/yarn.lock index 8fab393c9..ac35e1eaa 100644 --- a/database/yarn.lock +++ b/database/yarn.lock @@ -2,6 +2,13 @@ # yarn lockfile v1 +"@babel/runtime@^7.21.0": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.5.tgz#8564dd588182ce0047d55d7a75e93921107b57ec" + integrity sha512-ecjvYlnAaZ/KVneE/OdKYBYfgXV3Ptu6zQWmgEF7vwKhQnvVS6bjMD2XYgj+SNvQ1GfK/pjgokfPkC/2CO8CuA== + dependencies: + regenerator-runtime "^0.13.11" + "@cspotcode/source-map-consumer@0.8.0": version "0.8.0" resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b" @@ -106,10 +113,10 @@ picocolors "^1.0.0" tslib "^2.5.0" -"@sqltools/formatter@^1.2.2": - version "1.2.3" - resolved "https://registry.yarnpkg.com/@sqltools/formatter/-/formatter-1.2.3.tgz#1185726610acc37317ddab11c3c7f9066966bd20" - integrity sha512-O3uyB/JbkAEMZaP3YqyHH7TMnex7tWyCbCI4EfJdOCoN6HIhqdJBWTM6aCCiWQ/5f5wxjgU735QAIpJbjDvmzg== +"@sqltools/formatter@^1.2.5": + version "1.2.5" + resolved "https://registry.yarnpkg.com/@sqltools/formatter/-/formatter-1.2.5.tgz#3abc203c79b8c3e90fd6c156a0c62d5403520e12" + integrity sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw== "@tsconfig/node10@^1.0.7": version "1.0.8" @@ -173,11 +180,6 @@ resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc" integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw== -"@types/zen-observable@0.8.3": - version "0.8.3" - resolved "https://registry.yarnpkg.com/@types/zen-observable/-/zen-observable-0.8.3.tgz#781d360c282436494b32fe7d9f7f8e64b3118aa3" - integrity sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw== - "@typescript-eslint/eslint-plugin@^5.57.1": version "5.59.9" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.59.9.tgz#2604cfaf2b306e120044f901e20c8ed926debf15" @@ -292,11 +294,6 @@ ajv@^6.10.0, ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ansi-regex@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" - integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= - ansi-regex@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" @@ -307,11 +304,6 @@ ansi-regex@^5.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4= - ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" @@ -324,10 +316,10 @@ any-promise@^1.0.0: resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= -app-root-path@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-3.0.0.tgz#210b6f43873227e18a4b810a032283311555d5ad" - integrity sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw== +app-root-path@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-3.1.0.tgz#5971a2fc12ba170369a7a1ef018c71e6e47c2e86" + integrity sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA== arg@^4.1.0: version "4.1.3" @@ -423,6 +415,13 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + braces@^3.0.1: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" @@ -465,18 +464,7 @@ callsites@^3.0.0: resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== -chalk@^1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg= - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - -chalk@^4.0.0, chalk@^4.1.0: +chalk@^4.0.0, chalk@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -505,6 +493,15 @@ cliui@^7.0.2: strip-ansi "^6.0.0" wrap-ansi "^7.0.0" +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + color-convert@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" @@ -553,6 +550,13 @@ crypto@^1.0.1: resolved "https://registry.yarnpkg.com/crypto/-/crypto-1.0.1.tgz#2af1b7cad8175d24c8a1b0778255794a21803037" integrity sha512-VxBKmeNcqQdiUQUW2Tzq0t377b54N2bMtXO/qiLa+6eRRmmC4qT3D4OnTGoT/U6O9aklQ/jTwbOtRMTTY8G0Ig== +date-fns@^2.29.3: + version "2.30.0" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.30.0.tgz#f367e644839ff57894ec6ac480de40cae4b0f4d0" + integrity sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw== + dependencies: + "@babel/runtime" "^7.21.0" + debug@^3.2.7: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" @@ -560,7 +564,7 @@ debug@^3.2.7: dependencies: ms "^2.1.1" -debug@^4.1.1, debug@^4.3.1: +debug@^4.1.1: version "4.3.2" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== @@ -658,10 +662,10 @@ dotenv@^10.0.0: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== -dotenv@^8.2.0: - version "8.6.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" - integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== +dotenv@^16.0.3: + version "16.3.1" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.3.1.tgz#369034de7d7e5b120972693352a3bf112172cc3e" + integrity sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ== emoji-regex@^8.0.0: version "8.0.0" @@ -746,7 +750,7 @@ escalade@^3.1.1: resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: +escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= @@ -1054,11 +1058,6 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" -figlet@^1.1.1: - version "1.5.2" - resolved "https://registry.yarnpkg.com/figlet/-/figlet-1.5.2.tgz#dda34ff233c9a48e36fcff6741aeb5bafe49b634" - integrity sha512-WOn21V8AhyE1QqVfPIVxe3tupJacq1xGkPTB4iagT6o+P2cAgEOOwIxMftr4+ZCTI6d551ij9j61DFr0nsP2uQ== - file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" @@ -1203,17 +1202,16 @@ glob@^7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.1.6: - version "7.2.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" - integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== +glob@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" + integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" inherits "2" - minimatch "^3.0.4" + minimatch "^5.0.1" once "^1.3.0" - path-is-absolute "^1.0.0" globals@^13.19.0: version "13.20.0" @@ -1274,13 +1272,6 @@ graphemer@^1.4.0: resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE= - dependencies: - ansi-regex "^2.0.0" - has-bigints@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.1.tgz#64fe6acb020673e3b78db035a5af69aa9d07b113" @@ -1594,7 +1585,7 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= -js-yaml@^4.0.0, js-yaml@^4.1.0: +js-yaml@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== @@ -1705,6 +1696,13 @@ minimatch@^3.0.5, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" +minimatch@^5.0.1: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + minimist@^1.2.0: version "1.2.5" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" @@ -1715,10 +1713,10 @@ minimist@^1.2.6: resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== -mkdirp@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" - integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== +mkdirp@^2.1.3: + version "2.1.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-2.1.6.tgz#964fbcb12b2d8c5d6fbc62a963ac95a273e2cc19" + integrity sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A== ms@2.1.2: version "2.1.2" @@ -1897,11 +1895,6 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" -parent-require@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/parent-require/-/parent-require-1.0.0.tgz#746a167638083a860b0eef6732cb27ed46c32977" - integrity sha1-dGoWdjgIOoYLDu9nMssn7UbDKXc= - parse5-htmlparser2-tree-adapter@^6.0.0: version "6.0.1" resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6" @@ -2014,6 +2007,11 @@ reflect-metadata@^0.1.13: resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08" integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg== +regenerator-runtime@^0.13.11: + version "0.13.11" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" + integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== + regexp-tree@~0.1.1: version "0.1.27" resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.27.tgz#2198f0ef54518ffa743fe74d983b56ffd631b6cd" @@ -2114,11 +2112,6 @@ safe-regex@^2.1.1: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sax@>=0.6.0: - version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" - integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== - semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" @@ -2199,6 +2192,15 @@ string-width@^4.1.0, string-width@^4.2.0: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.0" +string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + string.prototype.trim@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz#a68352740859f6893f14ce3ef1bb3037f7a90533" @@ -2233,13 +2235,6 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -strip-ansi@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" - integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= - dependencies: - ansi-regex "^2.0.0" - strip-ansi@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" @@ -2274,11 +2269,6 @@ strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc= - supports-color@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" @@ -2376,11 +2366,6 @@ tslib@^1.8.1: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.1.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" - integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== - tslib@^2.5.0: version "2.5.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.3.tgz#24944ba2d990940e6e982c4bea147aba80209913" @@ -2414,28 +2399,26 @@ typed-array-length@^1.0.4: for-each "^0.3.3" is-typed-array "^1.1.9" -typeorm@^0.2.38: - version "0.2.38" - resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.2.38.tgz#2af08079919f6ab04cd17017f9faa2c8d5cd566f" - integrity sha512-M6Y3KQcAREQcphOVJciywf4mv6+A0I/SeR+lWNjKsjnQ+a3XcMwGYMGL0Jonsx3H0Cqlf/3yYqVki1jIXSK/xg== +typeorm@^0.3.16: + version "0.3.17" + resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.3.17.tgz#a73c121a52e4fbe419b596b244777be4e4b57949" + integrity sha512-UDjUEwIQalO9tWw9O2A4GU+sT3oyoUXheHJy4ft+RFdnRdQctdQ34L9SqE2p7LdwzafHx1maxT+bqXON+Qnmig== dependencies: - "@sqltools/formatter" "^1.2.2" - app-root-path "^3.0.0" + "@sqltools/formatter" "^1.2.5" + app-root-path "^3.1.0" buffer "^6.0.3" - chalk "^4.1.0" + chalk "^4.1.2" cli-highlight "^2.1.11" - debug "^4.3.1" - dotenv "^8.2.0" - glob "^7.1.6" - js-yaml "^4.0.0" - mkdirp "^1.0.4" + date-fns "^2.29.3" + debug "^4.3.4" + dotenv "^16.0.3" + glob "^8.1.0" + mkdirp "^2.1.3" reflect-metadata "^0.1.13" sha.js "^2.4.11" - tslib "^2.1.0" - xml2js "^0.4.23" - yargonaut "^1.1.4" - yargs "^17.0.1" - zen-observable-ts "^1.0.0" + tslib "^2.5.0" + uuid "^9.0.0" + yargs "^17.6.2" typescript@^4.3.5: version "4.3.5" @@ -2474,6 +2457,11 @@ uuid@^8.3.2: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== +uuid@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5" + integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg== + which-boxed-primitive@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" @@ -2523,19 +2511,6 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -xml2js@^0.4.23: - version "0.4.23" - resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" - integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug== - dependencies: - sax ">=0.6.0" - xmlbuilder "~11.0.0" - -xmlbuilder@~11.0.0: - version "11.0.1" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" - integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== - y18n@^5.0.5: version "5.0.8" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" @@ -2551,20 +2526,16 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yargonaut@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/yargonaut/-/yargonaut-1.1.4.tgz#c64f56432c7465271221f53f5cc517890c3d6e0c" - integrity sha512-rHgFmbgXAAzl+1nngqOcwEljqHGG9uUZoPjsdZEs1w5JW9RXYzrSvH/u70C1JE5qFi0qjsdhnUX/dJRpWqitSA== - dependencies: - chalk "^1.1.1" - figlet "^1.1.1" - parent-require "^1.0.0" - yargs-parser@^20.2.2: version "20.2.9" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== +yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + yargs@^16.0.0: version "16.2.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" @@ -2578,18 +2549,18 @@ yargs@^16.0.0: y18n "^5.0.5" yargs-parser "^20.2.2" -yargs@^17.0.1: - version "17.2.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.2.1.tgz#e2c95b9796a0e1f7f3bf4427863b42e0418191ea" - integrity sha512-XfR8du6ua4K6uLGm5S6fA+FIJom/MdJcFNVY8geLlp2v8GYbOXD4EB1tPNZsRn4vBzKGMgb5DRZMeWuFc2GO8Q== +yargs@^17.6.2: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== dependencies: - cliui "^7.0.2" + cliui "^8.0.1" escalade "^3.1.1" get-caller-file "^2.0.5" require-directory "^2.1.1" - string-width "^4.2.0" + string-width "^4.2.3" y18n "^5.0.5" - yargs-parser "^20.2.2" + yargs-parser "^21.1.1" yn@3.1.1: version "3.1.1" @@ -2600,16 +2571,3 @@ yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== - -zen-observable-ts@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-1.1.0.tgz#2d1aa9d79b87058e9b75698b92791c1838551f83" - integrity sha512-1h4zlLSqI2cRLPJUHJFL8bCWHhkpuXkF+dbGkRaWjgDIG26DmzyshUMrdV/rL3UnR+mhaX4fRq8LPouq0MYYIA== - dependencies: - "@types/zen-observable" "0.8.3" - zen-observable "0.8.15" - -zen-observable@0.8.15: - version "0.8.15" - resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15" - integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ== From ba98797009719de6744ee901d6d1adf3317d251d Mon Sep 17 00:00:00 2001 From: mahula Date: Mon, 26 Jun 2023 13:55:45 +0200 Subject: [PATCH 33/94] add deleted user and not registered user scenarios to e2e password reset feature --- .../User.Authentication.ResetPassword.feature | 29 +++++++++++++++---- .../support/step_definitions/email_steps.ts | 15 ++++++++++ 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/e2e-tests/cypress/e2e/User.Authentication.ResetPassword.feature b/e2e-tests/cypress/e2e/User.Authentication.ResetPassword.feature index 50a29d320..ab9213cb9 100644 --- a/e2e-tests/cypress/e2e/User.Authentication.ResetPassword.feature +++ b/e2e-tests/cypress/e2e/User.Authentication.ResetPassword.feature @@ -2,13 +2,27 @@ Feature: User Authentication - reset password As a user I want to reset my password from the sign in page - # TODO for these pre-conditions utilize seeding or API check, if user exists in test system - # Background: - # Given the following "users" are in the database: - # | email | password | name | - # | raeuber@hotzenplotz.de | Aa12345_ | Räuber Hotzenplotz | - + Scenario: Reset password as not registered user + Given the user navigates to page "/login" + And the user navigates to the forgot password page + When the user enters the e-mail address "not@registered.com" + And the user submits the e-mail form + Then the user receives no password reset e-mail + + Scenario: Reset password as deleted user + # Given the following "users" are in the database: + # | email | password | name | + # | stephen@hawking.uk | Aa12345_ | Stephen Hawking | + Given the user navigates to page "/login" + And the user navigates to the forgot password page + When the user enters the e-mail address "stephen@hawking.uk" + And the user submits the e-mail form + Then the user receives no password reset e-mail + Scenario: Reset password from signin page successfully + # Given the following "users" are in the database: + # | email | password | name | + # | raeuber@hotzenplotz.de | Aa12345_ | Räuber Hotzenplotz | Given the user navigates to page "/login" And the user navigates to the forgot password page When the user enters the e-mail address "raeuber@hotzenplotz.de" @@ -23,3 +37,6 @@ Feature: User Authentication - reset password And the user cannot login But the user submits the credentials "raeuber@hotzenplotz.de" "12345Aa_" And the user is logged in with username "Räuber Hotzenplotz" + + + diff --git a/e2e-tests/cypress/support/step_definitions/email_steps.ts b/e2e-tests/cypress/support/step_definitions/email_steps.ts index d31e2474e..fdf273def 100644 --- a/e2e-tests/cypress/support/step_definitions/email_steps.ts +++ b/e2e-tests/cypress/support/step_definitions/email_steps.ts @@ -51,6 +51,21 @@ Then('the user receives an e-mail containing the {string} link', (linkName: stri ) }) +Then('the user receives no password reset e-mail', () { + cy.origin( + Cypress.env('mailserverURL'), + { args: { userEMailSite } }, + ({ userEMailSite }) => { + cy.visit('/') + cy.get(userEMailSite.emailInbox).should('be.visible') + + cy.get(userEMailSite.emailList) + .find('.email-item') + .should('have.length', 0) + } + ) +}) + When('the user opens the {string} link in the browser', (linkName: string) => { cy.task('getEmailLink').then((emailLink) => { cy.visit(emailLink) From e35104faa86c771bc5bdb0cd5426ccba108c7550 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 26 Jun 2023 13:59:42 +0200 Subject: [PATCH 34/94] get backend running with new typeorm version --- backend/.eslintrc.js | 2 +- .../src/graphql/resolver/BalanceResolver.ts | 4 +- .../resolver/ContributionLinkResolver.ts | 4 +- .../resolver/ContributionMessageResolver.ts | 4 +- .../resolver/ContributionResolver.test.ts | 58 +++++++++++++++++++ .../graphql/resolver/ContributionResolver.ts | 42 ++++++++------ .../resolver/TransactionLinkResolver.ts | 37 +++++++----- backend/src/graphql/resolver/UserResolver.ts | 20 ++++--- .../resolver/util/findContributions.ts | 33 +++++++++-- .../resolver/util/findUserByIdentifier.ts | 10 ++-- .../resolver/util/getLastTransaction.ts | 14 ++--- .../resolver/util/transactionLinkList.ts | 4 +- backend/src/seeds/graphql/queries.ts | 2 + backend/src/server/context.ts | 2 +- backend/src/typeorm/DBVersion.ts | 2 +- backend/src/util/hasElopageBuys.ts | 2 +- 16 files changed, 167 insertions(+), 73 deletions(-) diff --git a/backend/.eslintrc.js b/backend/.eslintrc.js index e853c8bf6..0df8aca46 100644 --- a/backend/.eslintrc.js +++ b/backend/.eslintrc.js @@ -40,7 +40,7 @@ module.exports = { ], // import 'import/export': 'error', - 'import/no-deprecated': 'error', + // 'import/no-deprecated': 'error', 'import/no-empty-named-blocks': 'error', 'import/no-extraneous-dependencies': 'error', 'import/no-mutable-exports': 'error', diff --git a/backend/src/graphql/resolver/BalanceResolver.ts b/backend/src/graphql/resolver/BalanceResolver.ts index c8fdacdcf..9cd133181 100644 --- a/backend/src/graphql/resolver/BalanceResolver.ts +++ b/backend/src/graphql/resolver/BalanceResolver.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/restrict-template-expressions */ -import { getCustomRepository } from '@dbTools/typeorm' +import { getCustomRepository, IsNull } from '@dbTools/typeorm' import { Transaction as dbTransaction } from '@entity/Transaction' import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink' import { Decimal } from 'decimal.js-light' @@ -57,7 +57,7 @@ export class BalanceResolver { const linkCount = await dbTransactionLink.count({ where: { userId: user.id, - redeemedAt: null, + redeemedAt: IsNull(), // validUntil: MoreThan(new Date()), }, }) diff --git a/backend/src/graphql/resolver/ContributionLinkResolver.ts b/backend/src/graphql/resolver/ContributionLinkResolver.ts index 1dcf6a3cb..808bd584e 100644 --- a/backend/src/graphql/resolver/ContributionLinkResolver.ts +++ b/backend/src/graphql/resolver/ContributionLinkResolver.ts @@ -103,7 +103,7 @@ export class ContributionLinkResolver { @Arg('id', () => Int) id: number, @Ctx() context: Context, ): Promise { - const dbContributionLink = await DbContributionLink.findOne(id) + const dbContributionLink = await DbContributionLink.findOne({ where: { id } }) if (!dbContributionLink) { throw new LogError('Contribution Link not found', id) } @@ -130,7 +130,7 @@ export class ContributionLinkResolver { @Arg('id', () => Int) id: number, @Ctx() context: Context, ): Promise { - const dbContributionLink = await DbContributionLink.findOne(id) + const dbContributionLink = await DbContributionLink.findOne({ where: { id } }) if (!dbContributionLink) { throw new LogError('Contribution Link not found', id) } diff --git a/backend/src/graphql/resolver/ContributionMessageResolver.ts b/backend/src/graphql/resolver/ContributionMessageResolver.ts index b7fd37787..cc21f6e91 100644 --- a/backend/src/graphql/resolver/ContributionMessageResolver.ts +++ b/backend/src/graphql/resolver/ContributionMessageResolver.ts @@ -36,7 +36,7 @@ export class ContributionMessageResolver { await queryRunner.startTransaction('REPEATABLE READ') const contributionMessage = DbContributionMessage.create() try { - const contribution = await DbContribution.findOne({ id: contributionId }) + const contribution = await DbContribution.findOne({ where: { id: contributionId } }) if (!contribution) { throw new LogError('Contribution not found', contributionId) } @@ -124,7 +124,7 @@ export class ContributionMessageResolver { if (contribution.userId === moderator.id) { throw new LogError('Admin can not answer on his own contribution', contributionId) } - if (!contribution.user.emailContact) { + if (!contribution.user.emailContact && contribution.user.emailId) { contribution.user.emailContact = await DbUserContact.findOneOrFail({ where: { id: contribution.user.emailId }, }) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index d4c84b4f3..81e913dde 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -2890,6 +2890,64 @@ describe('ContributionResolver', () => { ]), }) }) + + describe('with query', () => { + it('returns the creations of queried user', async () => { + const result = await query({ + query: adminListContributions, + variables: { + currentPage: 1, + pageSize: 2, + order: Order.DESC, + query: 'peter', + }, + }) + const { + data: { adminListContributions: contributionListObject }, + } = await query({ + query: adminListContributions, + variables: { + currentPage: 1, + pageSize: 2, + order: Order.DESC, + query: 'peter', + }, + }) + expect(contributionListObject.contributionList).toHaveLength(3) + expect(contributionListObject).toMatchObject({ + contributionCount: 3, + contributionList: expect.arrayContaining([ + expect.objectContaining({ + amount: expect.decimalEqual(400), + firstName: 'Peter', + id: expect.any(Number), + lastName: 'Lustig', + memo: 'Herzlich Willkommen bei Gradido!', + messagesCount: 0, + state: 'PENDING', + }), + expect.objectContaining({ + amount: expect.decimalEqual(100), + firstName: 'Peter', + id: expect.any(Number), + lastName: 'Lustig', + memo: 'Test env contribution', + messagesCount: 0, + state: 'PENDING', + }), + expect.objectContaining({ + amount: expect.decimalEqual(200), + firstName: 'Peter', + id: expect.any(Number), + lastName: 'Lustig', + memo: 'Das war leider zu Viel!', + messagesCount: 0, + state: 'DELETED', + }), + ]), + }) + }) + }) }) }) }) diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index fa1590523..9727d6015 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -101,7 +101,7 @@ export class ContributionResolver { @Ctx() context: Context, ): Promise { const user = getUser(context) - const contribution = await DbContribution.findOne(id) + const contribution = await DbContribution.findOne({ where: { id } }) if (!contribution) { throw new LogError('Contribution not found', id) } @@ -372,6 +372,8 @@ export class ContributionResolver { statusFilter?: ContributionStatus[] | null, @Arg('userId', () => Int, { nullable: true }) userId?: number | null, + @Arg('query', () => String, { nullable: true }) + query?: string | null, ): Promise { const [dbContributions, count] = await findContributions({ order, @@ -381,6 +383,7 @@ export class ContributionResolver { userId, relations: ['user', 'messages'], statusFilter, + query, }) return new ContributionListResult( @@ -395,7 +398,7 @@ export class ContributionResolver { @Arg('id', () => Int) id: number, @Ctx() context: Context, ): Promise { - const contribution = await DbContribution.findOne(id) + const contribution = await DbContribution.findOne({ where: { id } }) if (!contribution) { throw new LogError('Contribution not found', id) } @@ -409,10 +412,10 @@ export class ContributionResolver { ) { throw new LogError('Own contribution can not be deleted as admin') } - const user = await DbUser.findOneOrFail( - { id: contribution.userId }, - { relations: ['emailContact'] }, - ) + const user = await DbUser.findOneOrFail({ + where: { id: contribution.userId }, + relations: ['emailContact'], + }) contribution.contributionStatus = ContributionStatus.DELETED contribution.deletedBy = moderator.id await contribution.save() @@ -447,7 +450,7 @@ export class ContributionResolver { const releaseLock = await TRANSACTIONS_LOCK.acquire() try { const clientTimezoneOffset = getClientTimezoneOffset(context) - const contribution = await DbContribution.findOne(id) + const contribution = await DbContribution.findOne({ where: { id } }) if (!contribution) { throw new LogError('Contribution not found', id) } @@ -461,10 +464,11 @@ export class ContributionResolver { if (moderatorUser.id === contribution.userId) { throw new LogError('Moderator can not confirm own contribution') } - const user = await DbUser.findOneOrFail( - { id: contribution.userId }, - { withDeleted: true, relations: ['emailContact'] }, - ) + const user = await DbUser.findOneOrFail({ + where: { id: contribution.userId }, + withDeleted: true, + relations: ['emailContact'], + }) if (user.deletedAt) { throw new LogError('Can not confirm contribution since the user was deleted') } @@ -565,9 +569,11 @@ export class ContributionResolver { @Ctx() context: Context, ): Promise { const contributionToUpdate = await DbContribution.findOne({ - id, - confirmedAt: IsNull(), - deniedBy: IsNull(), + where: { + id, + confirmedAt: IsNull(), + deniedBy: IsNull(), + }, }) if (!contributionToUpdate) { throw new LogError('Contribution not found', id) @@ -582,10 +588,10 @@ export class ContributionResolver { ) } const moderator = getUser(context) - const user = await DbUser.findOne( - { id: contributionToUpdate.userId }, - { relations: ['emailContact'] }, - ) + const user = await DbUser.findOne({ + where: { id: contributionToUpdate.userId }, + relations: ['emailContact'], + }) if (!user) { throw new LogError('Could not find User of the Contribution', contributionToUpdate.userId) } diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.ts b/backend/src/graphql/resolver/TransactionLinkResolver.ts index d6649814a..0ff606fa5 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.ts @@ -108,7 +108,7 @@ export class TransactionLinkResolver { ): Promise { const user = getUser(context) - const transactionLink = await DbTransactionLink.findOne({ id }) + const transactionLink = await DbTransactionLink.findOne({ where: { id } }) if (!transactionLink) { throw new LogError('Transaction link not found', id) } @@ -138,17 +138,22 @@ export class TransactionLinkResolver { @Query(() => QueryLinkResult) async queryTransactionLink(@Arg('code') code: string): Promise { if (code.match(/^CL-/)) { - const contributionLink = await DbContributionLink.findOneOrFail( - { code: code.replace('CL-', '') }, - { withDeleted: true }, - ) + const contributionLink = await DbContributionLink.findOneOrFail({ + where: { code: code.replace('CL-', '') }, + withDeleted: true, + }) return new ContributionLink(contributionLink) } else { - const transactionLink = await DbTransactionLink.findOneOrFail({ code }, { withDeleted: true }) - const user = await DbUser.findOneOrFail({ id: transactionLink.userId }) + const transactionLink = await DbTransactionLink.findOneOrFail({ + where: { code }, + withDeleted: true, + }) + const user = await DbUser.findOneOrFail({ where: { id: transactionLink.userId } }) let redeemedBy: User | null = null if (transactionLink?.redeemedBy) { - redeemedBy = new User(await DbUser.findOneOrFail({ id: transactionLink.redeemedBy })) + redeemedBy = new User( + await DbUser.findOneOrFail({ where: { id: transactionLink.redeemedBy } }), + ) } return new TransactionLink(transactionLink, new User(user), redeemedBy) } @@ -191,7 +196,7 @@ export class TransactionLinkResolver { throw new LogError('Contribution link is no longer valid', contributionLink.validTo) } } - let alreadyRedeemed: DbContribution | undefined + let alreadyRedeemed: DbContribution | null switch (contributionLink.cycle) { case ContributionCycleType.ONCE: { alreadyRedeemed = await queryRunner.manager @@ -302,15 +307,17 @@ export class TransactionLinkResolver { return true } else { const now = new Date() - const transactionLink = await DbTransactionLink.findOne({ code }) + const transactionLink = await DbTransactionLink.findOne({ where: { code } }) if (!transactionLink) { throw new LogError('Transaction link not found', code) } - const linkedUser = await DbUser.findOne( - { id: transactionLink.userId }, - { relations: ['emailContact'] }, - ) + const linkedUser = await DbUser.findOne({ + where: { + id: transactionLink.userId, + }, + relations: ['emailContact'], + }) if (!linkedUser) { throw new LogError('Linked user not found for given link', transactionLink.userId) @@ -378,7 +385,7 @@ export class TransactionLinkResolver { @Arg('userId', () => Int) userId: number, ): Promise { - const user = await DbUser.findOne({ id: userId }) + const user = await DbUser.findOne({ where: { id: userId } }) if (!user) { throw new LogError('Could not find requested User', userId) } diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 19f59e1a3..840bb43c9 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -2,7 +2,7 @@ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/restrict-template-expressions */ -import { getConnection, getCustomRepository, IsNull, Not } from '@dbTools/typeorm' +import { getConnection, getCustomRepository, IsNull, Not, Equal } from '@dbTools/typeorm' import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' import { TransactionLink as DbTransactionLink } from '@entity/TransactionLink' import { User as DbUser } from '@entity/User' @@ -278,7 +278,7 @@ export class UserResolver { eventRegisterRedeem.involvedContributionLink = contributionLink } } else { - const transactionLink = await DbTransactionLink.findOne({ where: { code: redeemCode } }) + const transactionLink = await DbTransactionLink.findOne({ where: { code: redeemCode } }) logger.info('redeemCode found transactionLink', transactionLink) if (transactionLink) { dbUser.referrerId = transactionLink.userId @@ -403,8 +403,8 @@ export class UserResolver { } // load code - const userContact = await DbUserContact.findOne({ - where: { emailVerificationCode: code }, + const userContact = await DbUserContact.findOneOrFail({ + where: { emailVerificationCode: Equal(BigInt(code)) }, relations: ['user'], }).catch(() => { throw new LogError('Could not login with emailVerificationCode') @@ -474,7 +474,9 @@ export class UserResolver { @Query(() => Boolean) async queryOptIn(@Arg('optIn') optIn: string): Promise { logger.info(`queryOptIn(${optIn})...`) - const userContact = await DbUserContact.findOneOrFail({ where: { emailVerificationCode: optIn } }) + const userContact = await DbUserContact.findOneOrFail({ + where: { emailVerificationCode: Equal(BigInt(optIn)) }, + }) logger.debug('found optInCode', userContact) // Code is only valid for `CONFIG.EMAIL_CODE_VALID_TIME` minutes if (!isEmailVerificationCodeValid(userContact.updatedAt || userContact.createdAt)) { @@ -734,7 +736,7 @@ export class UserResolver { } await user.save() await EVENT_ADMIN_USER_ROLE_SET(user, moderator) - const newUser = await DbUser.findOne({ where: { id: userId } }) + const newUser = await DbUser.findOne({ where: { id: userId } }) return newUser ? newUser.isAdmin : null } @@ -744,7 +746,7 @@ export class UserResolver { @Arg('userId', () => Int) userId: number, @Ctx() context: Context, ): Promise { - const user = await DbUser.findOne({ id: userId }) + const user = await DbUser.findOne({ where: { id: userId } }) // user exists ? if (!user) { throw new LogError('Could not find user with given ID', userId) @@ -757,7 +759,7 @@ export class UserResolver { // soft-delete user await user.softRemove() await EVENT_ADMIN_USER_DELETE(user, moderator) - const newUser = await DbUser.findOne({ where: { id: userId }, withDeleted: true }) + const newUser = await DbUser.findOne({ where: { id: userId }, withDeleted: true }) return newUser ? newUser.deletedAt : null } @@ -822,7 +824,7 @@ export async function findUserByEmail(email: string): Promise { const dbUserContact = await DbUserContact.findOneOrFail({ where: { email }, withDeleted: true, - relations: ['user'] + relations: ['user'], }).catch(() => { throw new LogError('No user with this credentials', email) }) diff --git a/backend/src/graphql/resolver/util/findContributions.ts b/backend/src/graphql/resolver/util/findContributions.ts index 28984d5b1..66038538a 100644 --- a/backend/src/graphql/resolver/util/findContributions.ts +++ b/backend/src/graphql/resolver/util/findContributions.ts @@ -1,4 +1,4 @@ -import { In } from '@dbTools/typeorm' +import { In, Like, FindOperator } from '@dbTools/typeorm' import { Contribution as DbContribution } from '@entity/Contribution' import { ContributionStatus } from '@enum/ContributionStatus' @@ -12,27 +12,48 @@ interface FindContributionsOptions { relations?: string[] userId?: number | null statusFilter?: ContributionStatus[] | null + query?: string | null } export const findContributions = async ( options: FindContributionsOptions, ): Promise<[DbContribution[], number]> => { - const { order, currentPage, pageSize, withDeleted, relations, userId, statusFilter } = { + const { order, currentPage, pageSize, withDeleted, relations, userId, statusFilter, query } = { withDeleted: false, relations: [], + query: '', ...options, } + const where: { + userId?: number | undefined + contributionStatus?: FindOperator | undefined + user?: Record>[] | undefined + } = { + ...(statusFilter?.length && { contributionStatus: In(statusFilter) }), + ...(userId && { userId }), + } + + if (query) { + where.user = [ + { firstName: Like(`%${query}%`) }, + { lastName: Like(`%${query}%`) }, + // emailContact: { email: Like(`%${query}%`) }, + ] + } + return DbContribution.findAndCount({ - where: { - ...(statusFilter?.length && { contributionStatus: In(statusFilter) }), - ...(userId && { userId }), + relations: { + user: { + emailContact: true, + }, + messages: true, }, withDeleted, + where, order: { createdAt: order, id: order, }, - relations, skip: (currentPage - 1) * pageSize, take: pageSize, }) diff --git a/backend/src/graphql/resolver/util/findUserByIdentifier.ts b/backend/src/graphql/resolver/util/findUserByIdentifier.ts index bd9a25071..96c9eb458 100644 --- a/backend/src/graphql/resolver/util/findUserByIdentifier.ts +++ b/backend/src/graphql/resolver/util/findUserByIdentifier.ts @@ -7,20 +7,20 @@ import { LogError } from '@/server/LogError' import { VALID_ALIAS_REGEX } from './validateAlias' export const findUserByIdentifier = async (identifier: string): Promise => { - let user: DbUser | undefined + let user: DbUser | null if (validate(identifier) && version(identifier) === 4) { user = await DbUser.findOne({ where: { gradidoID: identifier }, relations: ['emailContact'] }) if (!user) { throw new LogError('No user found to given identifier', identifier) } } else if (/^.{2,}@.{2,}\..{2,}$/.exec(identifier)) { - const userContact = await DbUserContact.findOne( - { + const userContact = await DbUserContact.findOne({ + where: { email: identifier, emailChecked: true, }, - { relations: ['user'] }, - ) + relations: ['user'], + }) if (!userContact) { throw new LogError('No user with this credentials', identifier) } diff --git a/backend/src/graphql/resolver/util/getLastTransaction.ts b/backend/src/graphql/resolver/util/getLastTransaction.ts index 5b3e862c2..0d7747088 100644 --- a/backend/src/graphql/resolver/util/getLastTransaction.ts +++ b/backend/src/graphql/resolver/util/getLastTransaction.ts @@ -3,12 +3,10 @@ import { Transaction as DbTransaction } from '@entity/Transaction' export const getLastTransaction = async ( userId: number, relations?: string[], -): Promise => { - return DbTransaction.findOne( - { userId }, - { - order: { balanceDate: 'DESC', id: 'DESC' }, - relations, - }, - ) +): Promise => { + return DbTransaction.findOne({ + where: { userId }, + order: { balanceDate: 'DESC', id: 'DESC' }, + relations, + }) } diff --git a/backend/src/graphql/resolver/util/transactionLinkList.ts b/backend/src/graphql/resolver/util/transactionLinkList.ts index ee79216c8..653f86804 100644 --- a/backend/src/graphql/resolver/util/transactionLinkList.ts +++ b/backend/src/graphql/resolver/util/transactionLinkList.ts @@ -1,4 +1,4 @@ -import { MoreThan } from '@dbTools/typeorm' +import { MoreThan, IsNull } from '@dbTools/typeorm' import { TransactionLink as DbTransactionLink } from '@entity/TransactionLink' import { User as DbUser } from '@entity/User' @@ -22,7 +22,7 @@ export async function transactionLinkList( const [transactionLinks, count] = await DbTransactionLink.findAndCount({ where: { userId: user.id, - ...(!withRedeemed && { redeemedBy: null }), + ...(!withRedeemed && { redeemedBy: IsNull() }), ...(!withExpired && { validUntil: MoreThan(new Date()) }), }, withDeleted, diff --git a/backend/src/seeds/graphql/queries.ts b/backend/src/seeds/graphql/queries.ts index a964cdb3a..6353fe1cd 100644 --- a/backend/src/seeds/graphql/queries.ts +++ b/backend/src/seeds/graphql/queries.ts @@ -235,6 +235,7 @@ export const adminListContributions = gql` $order: Order = DESC $statusFilter: [ContributionStatus!] $userId: Int + $query: String ) { adminListContributions( currentPage: $currentPage @@ -242,6 +243,7 @@ export const adminListContributions = gql` order: $order statusFilter: $statusFilter userId: $userId + query: $query ) { contributionCount contributionList { diff --git a/backend/src/server/context.ts b/backend/src/server/context.ts index c7e59365b..45f0a6c1f 100644 --- a/backend/src/server/context.ts +++ b/backend/src/server/context.ts @@ -15,7 +15,7 @@ export interface Context { clientTimezoneOffset?: number gradidoID?: string // hack to use less DB calls for Balance Resolver - lastTransaction?: dbTransaction + lastTransaction?: dbTransaction | null transactionCount?: number linkCount?: number sumHoldAvailableAmount?: Decimal diff --git a/backend/src/typeorm/DBVersion.ts b/backend/src/typeorm/DBVersion.ts index f465069d3..acde7c1f0 100644 --- a/backend/src/typeorm/DBVersion.ts +++ b/backend/src/typeorm/DBVersion.ts @@ -4,7 +4,7 @@ import { backendLogger as logger } from '@/server/logger' const getDBVersion = async (): Promise => { try { - const dbVersion = await Migration.findOne({ order: { version: 'DESC' } }) + const [dbVersion] = await Migration.find({ order: { version: 'DESC' }, take: 1 }) return dbVersion ? dbVersion.fileName : null } catch (error) { logger.error(error) diff --git a/backend/src/util/hasElopageBuys.ts b/backend/src/util/hasElopageBuys.ts index 4e23e717c..1465e76e2 100644 --- a/backend/src/util/hasElopageBuys.ts +++ b/backend/src/util/hasElopageBuys.ts @@ -1,6 +1,6 @@ import { LoginElopageBuys } from '@entity/LoginElopageBuys' export async function hasElopageBuys(email: string): Promise { - const elopageBuyCount = await LoginElopageBuys.count({ payerEmail: email }) + const elopageBuyCount = await LoginElopageBuys.count({ where: { payerEmail: email } }) return elopageBuyCount > 0 } From ec4b8294b23ba65face20245028fd8f780de649c Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 26 Jun 2023 14:04:32 +0200 Subject: [PATCH 35/94] dht node running on ne typeorm version --- dht-node/src/dht_node/index.test.ts | 8 ++++---- dht-node/src/dht_node/index.ts | 2 +- dht-node/src/typeorm/DBVersion.ts | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/dht-node/src/dht_node/index.test.ts b/dht-node/src/dht_node/index.test.ts index ec172c4f8..c6e972c52 100644 --- a/dht-node/src/dht_node/index.test.ts +++ b/dht-node/src/dht_node/index.test.ts @@ -340,7 +340,7 @@ describe('federation', () => { }, ] await socketEventMocks.data(Buffer.from(JSON.stringify(jsonArray))) - result = await DbFederatedCommunity.find({ foreign: true }) + result = await DbFederatedCommunity.find({ where: { foreign: true } }) }) afterAll(async () => { @@ -601,7 +601,7 @@ describe('federation', () => { { api: 'toolong api', url: 'some valid url' }, ] await socketEventMocks.data(Buffer.from(JSON.stringify(jsonArray))) - result = await DbFederatedCommunity.find({ foreign: true }) + result = await DbFederatedCommunity.find({ where: { foreign: true } }) }) afterAll(async () => { @@ -655,7 +655,7 @@ describe('federation', () => { }, ] await socketEventMocks.data(Buffer.from(JSON.stringify(jsonArray))) - result = await DbFederatedCommunity.find({ foreign: true }) + result = await DbFederatedCommunity.find({ where: { foreign: true } }) }) afterAll(async () => { @@ -791,7 +791,7 @@ describe('federation', () => { ]), ), ) - result = await DbFederatedCommunity.find({ foreign: true }) + result = await DbFederatedCommunity.find({ where: { foreign: true } }) }) afterAll(async () => { diff --git a/dht-node/src/dht_node/index.ts b/dht-node/src/dht_node/index.ts index a767c323e..f24522c3b 100644 --- a/dht-node/src/dht_node/index.ts +++ b/dht-node/src/dht_node/index.ts @@ -217,7 +217,7 @@ async function writeFederatedHomeCommunityEntries(pubKey: string): Promise { try { // check for existing homeCommunity entry - let homeCom = await DbCommunity.findOne({ foreign: false }) + let homeCom = await DbCommunity.findOne({ where: { foreign: false } }) if (homeCom) { // simply update the existing entry, but it MUST keep the ID and UUID because of possible relations homeCom.publicKey = keyPair.publicKey diff --git a/dht-node/src/typeorm/DBVersion.ts b/dht-node/src/typeorm/DBVersion.ts index 5bd23c1d5..850c6ed80 100644 --- a/dht-node/src/typeorm/DBVersion.ts +++ b/dht-node/src/typeorm/DBVersion.ts @@ -3,7 +3,7 @@ import { logger } from '@/server/logger' const getDBVersion = async (): Promise => { try { - const dbVersion = await Migration.findOne({ order: { version: 'DESC' } }) + const [dbVersion] = await Migration.find({ order: { version: 'DESC' }, take: 1 }) return dbVersion ? dbVersion.fileName : null } catch (error) { logger.error(error) From d5af6c3b21827226f2fc2d24a09b09c30527fc74 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 26 Jun 2023 14:08:12 +0200 Subject: [PATCH 36/94] federation running with new typeorm version --- .../src/graphql/api/1_0/resolver/PublicKeyResolver.ts | 6 ++++-- federation/src/typeorm/DBVersion.ts | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/federation/src/graphql/api/1_0/resolver/PublicKeyResolver.ts b/federation/src/graphql/api/1_0/resolver/PublicKeyResolver.ts index 0145324fc..e741e95c3 100644 --- a/federation/src/graphql/api/1_0/resolver/PublicKeyResolver.ts +++ b/federation/src/graphql/api/1_0/resolver/PublicKeyResolver.ts @@ -11,8 +11,10 @@ export class PublicKeyResolver { async getPublicKey(): Promise { logger.debug(`getPublicKey() via apiVersion=1_0 ...`) const homeCom = await DbFederatedCommunity.findOneOrFail({ - foreign: false, - apiVersion: '1_0', + where: { + foreign: false, + apiVersion: '1_0', + }, }) logger.info(`getPublicKey()-1_0... return publicKey=${homeCom.publicKey}`) return new GetPublicKeyResult(homeCom.publicKey.toString()) diff --git a/federation/src/typeorm/DBVersion.ts b/federation/src/typeorm/DBVersion.ts index bdb909c1d..267dfd57e 100644 --- a/federation/src/typeorm/DBVersion.ts +++ b/federation/src/typeorm/DBVersion.ts @@ -3,7 +3,7 @@ import { federationLogger as logger } from '@/server/logger' const getDBVersion = async (): Promise => { try { - const dbVersion = await Migration.findOne({ order: { version: 'DESC' } }) + const [dbVersion] = await Migration.find({ order: { version: 'DESC' }, take: 1 }) return dbVersion ? dbVersion.fileName : null } catch (error) { logger.error(error) From 27006be4ae2d7057590b3d8124d5f4896436563b Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 26 Jun 2023 14:21:35 +0200 Subject: [PATCH 37/94] undo changed comming from user query for find contributions --- .../resolver/ContributionResolver.test.ts | 58 ------------------- .../graphql/resolver/ContributionResolver.ts | 3 - .../resolver/util/findContributions.ts | 33 ++--------- 3 files changed, 6 insertions(+), 88 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index 81e913dde..d4c84b4f3 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -2890,64 +2890,6 @@ describe('ContributionResolver', () => { ]), }) }) - - describe('with query', () => { - it('returns the creations of queried user', async () => { - const result = await query({ - query: adminListContributions, - variables: { - currentPage: 1, - pageSize: 2, - order: Order.DESC, - query: 'peter', - }, - }) - const { - data: { adminListContributions: contributionListObject }, - } = await query({ - query: adminListContributions, - variables: { - currentPage: 1, - pageSize: 2, - order: Order.DESC, - query: 'peter', - }, - }) - expect(contributionListObject.contributionList).toHaveLength(3) - expect(contributionListObject).toMatchObject({ - contributionCount: 3, - contributionList: expect.arrayContaining([ - expect.objectContaining({ - amount: expect.decimalEqual(400), - firstName: 'Peter', - id: expect.any(Number), - lastName: 'Lustig', - memo: 'Herzlich Willkommen bei Gradido!', - messagesCount: 0, - state: 'PENDING', - }), - expect.objectContaining({ - amount: expect.decimalEqual(100), - firstName: 'Peter', - id: expect.any(Number), - lastName: 'Lustig', - memo: 'Test env contribution', - messagesCount: 0, - state: 'PENDING', - }), - expect.objectContaining({ - amount: expect.decimalEqual(200), - firstName: 'Peter', - id: expect.any(Number), - lastName: 'Lustig', - memo: 'Das war leider zu Viel!', - messagesCount: 0, - state: 'DELETED', - }), - ]), - }) - }) - }) }) }) }) diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 9727d6015..2e36eba3f 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -372,8 +372,6 @@ export class ContributionResolver { statusFilter?: ContributionStatus[] | null, @Arg('userId', () => Int, { nullable: true }) userId?: number | null, - @Arg('query', () => String, { nullable: true }) - query?: string | null, ): Promise { const [dbContributions, count] = await findContributions({ order, @@ -383,7 +381,6 @@ export class ContributionResolver { userId, relations: ['user', 'messages'], statusFilter, - query, }) return new ContributionListResult( diff --git a/backend/src/graphql/resolver/util/findContributions.ts b/backend/src/graphql/resolver/util/findContributions.ts index 66038538a..28984d5b1 100644 --- a/backend/src/graphql/resolver/util/findContributions.ts +++ b/backend/src/graphql/resolver/util/findContributions.ts @@ -1,4 +1,4 @@ -import { In, Like, FindOperator } from '@dbTools/typeorm' +import { In } from '@dbTools/typeorm' import { Contribution as DbContribution } from '@entity/Contribution' import { ContributionStatus } from '@enum/ContributionStatus' @@ -12,48 +12,27 @@ interface FindContributionsOptions { relations?: string[] userId?: number | null statusFilter?: ContributionStatus[] | null - query?: string | null } export const findContributions = async ( options: FindContributionsOptions, ): Promise<[DbContribution[], number]> => { - const { order, currentPage, pageSize, withDeleted, relations, userId, statusFilter, query } = { + const { order, currentPage, pageSize, withDeleted, relations, userId, statusFilter } = { withDeleted: false, relations: [], - query: '', ...options, } - const where: { - userId?: number | undefined - contributionStatus?: FindOperator | undefined - user?: Record>[] | undefined - } = { - ...(statusFilter?.length && { contributionStatus: In(statusFilter) }), - ...(userId && { userId }), - } - - if (query) { - where.user = [ - { firstName: Like(`%${query}%`) }, - { lastName: Like(`%${query}%`) }, - // emailContact: { email: Like(`%${query}%`) }, - ] - } - return DbContribution.findAndCount({ - relations: { - user: { - emailContact: true, - }, - messages: true, + where: { + ...(statusFilter?.length && { contributionStatus: In(statusFilter) }), + ...(userId && { userId }), }, withDeleted, - where, order: { createdAt: order, id: order, }, + relations, skip: (currentPage - 1) * pageSize, take: pageSize, }) From 95e7888d90e8703ce0e7c8880097d5a301d966c4 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 26 Jun 2023 15:57:43 +0200 Subject: [PATCH 38/94] try to get unit tests and seeds running again --- .../resolver/ContributionResolver.test.ts | 8 +- .../resolver/TransactionResolver.test.ts | 12 +- .../src/graphql/resolver/UserResolver.test.ts | 163 +++++++++--------- backend/src/graphql/resolver/UserResolver.ts | 12 +- backend/src/seeds/factory/creation.ts | 9 +- backend/src/seeds/factory/transactionLink.ts | 2 +- backend/src/seeds/factory/user.ts | 4 +- backend/src/seeds/index.ts | 12 +- backend/test/helpers.ts | 15 +- .../UserContact.ts | 2 +- 10 files changed, 131 insertions(+), 108 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index d4c84b4f3..42fe79ff0 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/no-explicit-any */ -import { Connection } from '@dbTools/typeorm' +import { Connection, Equal } from '@dbTools/typeorm' import { Contribution } from '@entity/Contribution' import { Event as DbEvent } from '@entity/Event' import { Transaction as DbTransaction } from '@entity/Transaction' @@ -457,7 +457,7 @@ describe('ContributionResolver', () => { describe('contribution has wrong status', () => { beforeAll(async () => { const contribution = await Contribution.findOneOrFail({ - id: pendingContribution.data.createContribution.id, + where: { id: pendingContribution.data.createContribution.id }, }) contribution.contributionStatus = ContributionStatus.DELETED await contribution.save() @@ -469,7 +469,7 @@ describe('ContributionResolver', () => { afterAll(async () => { const contribution = await Contribution.findOneOrFail({ - id: pendingContribution.data.createContribution.id, + where: { id: pendingContribution.data.createContribution.id }, }) contribution.contributionStatus = ContributionStatus.PENDING await contribution.save() @@ -1828,7 +1828,7 @@ describe('ContributionResolver', () => { creation = await Contribution.findOneOrFail({ where: { memo: 'Herzlich Willkommen bei Gradido!', - amount: 400, + amount: Equal(new Decimal('400')), }, }) }) diff --git a/backend/src/graphql/resolver/TransactionResolver.test.ts b/backend/src/graphql/resolver/TransactionResolver.test.ts index 96d434a29..60445e239 100644 --- a/backend/src/graphql/resolver/TransactionResolver.test.ts +++ b/backend/src/graphql/resolver/TransactionResolver.test.ts @@ -346,8 +346,10 @@ describe('send coins', () => { it('stores the TRANSACTION_SEND event in the database', async () => { // Find the exact transaction (sent one is the one with user[1] as user) const transaction = await Transaction.find({ - userId: user[1].id, - memo: 'unrepeatable memo', + where: { + userId: user[1].id, + memo: 'unrepeatable memo', + }, }) await expect(DbEvent.find()).resolves.toContainEqual( @@ -364,8 +366,10 @@ describe('send coins', () => { it('stores the TRANSACTION_RECEIVE event in the database', async () => { // Find the exact transaction (received one is the one with user[0] as user) const transaction = await Transaction.find({ - userId: user[0].id, - memo: 'unrepeatable memo', + where: { + userId: user[0].id, + memo: 'unrepeatable memo', + }, }) await expect(DbEvent.find()).resolves.toContainEqual( diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index 0384b64c5..bebaa912c 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -195,10 +195,12 @@ describe('UserResolver', () => { }) it('stores the USER_REGISTER event in the database', async () => { - const userConatct = await UserContact.findOneOrFail( - { email: 'peter@lustig.de' }, - { relations: ['user'] }, - ) + const userConatct = await UserContact.findOneOrFail({ + where: { + email: 'peter@lustig.de', + }, + relations: ['user'], + }) await expect(DbEvent.find()).resolves.toContainEqual( expect.objectContaining({ type: EventType.USER_REGISTER, @@ -271,10 +273,10 @@ describe('UserResolver', () => { }) it('stores the EMAIL_ACCOUNT_MULTIREGISTRATION event in the database', async () => { - const userConatct = await UserContact.findOneOrFail( - { email: 'peter@lustig.de' }, - { relations: ['user'] }, - ) + const userConatct = await UserContact.findOneOrFail({ + where: { email: 'peter@lustig.de' }, + relations: ['user'], + }) await expect(DbEvent.find()).resolves.toContainEqual( expect.objectContaining({ type: EventType.EMAIL_ACCOUNT_MULTIREGISTRATION, @@ -292,7 +294,7 @@ describe('UserResolver', () => { variables: { ...variables, email: 'bibi@bloxberg.de', language: 'it' }, }) await expect( - UserContact.findOne({ email: 'bibi@bloxberg.de' }, { relations: ['user'] }), + UserContact.findOne({ where: { email: 'bibi@bloxberg.de' }, relations: ['user'] }), ).resolves.toEqual( expect.objectContaining({ email: 'bibi@bloxberg.de', @@ -334,7 +336,7 @@ describe('UserResolver', () => { }) // make Peter Lustig Admin - const peter = await User.findOneOrFail({ id: user[0].id }) + const peter = await User.findOneOrFail({ where: { id: user[0].id } }) peter.isAdmin = new Date() await peter.save() @@ -365,7 +367,7 @@ describe('UserResolver', () => { it('sets the contribution link id', async () => { await expect( - UserContact.findOne({ email: 'ein@besucher.de' }, { relations: ['user'] }), + UserContact.findOne({ where: { email: 'ein@besucher.de' }, relations: ['user'] }), ).resolves.toEqual( expect.objectContaining({ user: expect.objectContaining({ @@ -445,7 +447,7 @@ describe('UserResolver', () => { memo: `testing transaction link`, }) - transactionLink = await TransactionLink.findOneOrFail() + transactionLink = await TransactionLink.findOneOrFail({}) resetToken() @@ -462,7 +464,7 @@ describe('UserResolver', () => { it('sets the referrer id to bob baumeister id', async () => { await expect( - UserContact.findOne({ email: 'which@ever.de' }, { relations: ['user'] }), + UserContact.findOne({ where: { email: 'which@ever.de' }, relations: ['user'] }), ).resolves.toEqual( expect.objectContaining({ user: expect.objectContaining({ referrerId: bob.data.login.id }), @@ -529,16 +531,18 @@ describe('UserResolver', () => { beforeAll(async () => { await mutate({ mutation: createUser, variables: createUserVariables }) - const emailContact = await UserContact.findOneOrFail({ email: createUserVariables.email }) + const emailContact = await UserContact.findOneOrFail({ + where: { email: createUserVariables.email }, + }) emailVerificationCode = emailContact.emailVerificationCode.toString() result = await mutate({ mutation: setPassword, variables: { code: emailVerificationCode, password: 'Aa12345_' }, }) - newUser = await User.findOneOrFail( - { id: emailContact.userId }, - { relations: ['emailContact'] }, - ) + newUser = await User.findOneOrFail({ + where: { id: emailContact.userId }, + relations: ['emailContact'], + }) }) afterAll(async () => { @@ -571,7 +575,9 @@ describe('UserResolver', () => { describe('no valid password', () => { beforeAll(async () => { await mutate({ mutation: createUser, variables: createUserVariables }) - const emailContact = await UserContact.findOneOrFail({ email: createUserVariables.email }) + const emailContact = await UserContact.findOneOrFail({ + where: { email: createUserVariables.email }, + }) emailVerificationCode = emailContact.emailVerificationCode.toString() }) @@ -697,10 +703,10 @@ describe('UserResolver', () => { }) it('stores the USER_LOGIN event in the database', async () => { - const userConatct = await UserContact.findOneOrFail( - { email: 'bibi@bloxberg.de' }, - { relations: ['user'] }, - ) + const userConatct = await UserContact.findOneOrFail({ + where: { email: 'bibi@bloxberg.de' }, + relations: ['user'], + }) await expect(DbEvent.find()).resolves.toContainEqual( expect.objectContaining({ type: EventType.USER_LOGIN, @@ -879,10 +885,10 @@ describe('UserResolver', () => { }) it('stores the USER_LOGOUT event in the database', async () => { - const userConatct = await UserContact.findOneOrFail( - { email: 'bibi@bloxberg.de' }, - { relations: ['user'] }, - ) + const userConatct = await UserContact.findOneOrFail({ + where: { email: 'bibi@bloxberg.de' }, + relations: ['user'], + }) await expect(DbEvent.find()).resolves.toContainEqual( expect.objectContaining({ type: EventType.USER_LOGOUT, @@ -1047,10 +1053,10 @@ describe('UserResolver', () => { }) it('stores the EMAIL_FORGOT_PASSWORD event in the database', async () => { - const userConatct = await UserContact.findOneOrFail( - { email: 'bibi@bloxberg.de' }, - { relations: ['user'] }, - ) + const userConatct = await UserContact.findOneOrFail({ + where: { email: 'bibi@bloxberg.de' }, + relations: ['user'], + }) await expect(DbEvent.find()).resolves.toContainEqual( expect.objectContaining({ type: EventType.EMAIL_FORGOT_PASSWORD, @@ -1083,7 +1089,7 @@ describe('UserResolver', () => { beforeAll(async () => { await userFactory(testEnv, bibiBloxberg) - emailContact = await UserContact.findOneOrFail({ email: bibiBloxberg.email }) + emailContact = await UserContact.findOneOrFail({ where: { email: bibiBloxberg.email } }) }) afterAll(async () => { @@ -1175,7 +1181,7 @@ describe('UserResolver', () => { locale: 'en', }, }) - await expect(User.findOne()).resolves.toEqual( + await expect(User.findOne({})).resolves.toEqual( expect.objectContaining({ firstName: 'Benjamin', lastName: 'Blümchen', @@ -1185,10 +1191,10 @@ describe('UserResolver', () => { }) it('stores the USER_INFO_UPDATE event in the database', async () => { - const userConatct = await UserContact.findOneOrFail( - { email: 'bibi@bloxberg.de' }, - { relations: ['user'] }, - ) + const userConatct = await UserContact.findOneOrFail({ + where: { email: 'bibi@bloxberg.de' }, + relations: ['user'], + }) await expect(DbEvent.find()).resolves.toContainEqual( expect.objectContaining({ type: EventType.USER_INFO_UPDATE, @@ -1212,7 +1218,7 @@ describe('UserResolver', () => { alias: 'bibi_Bloxberg', }, }) - await expect(User.findOne()).resolves.toEqual( + await expect(User.findOne({})).resolves.toEqual( expect.objectContaining({ alias: 'bibi_Bloxberg', }), @@ -1433,10 +1439,10 @@ describe('UserResolver', () => { let bibi: User beforeAll(async () => { - const usercontact = await UserContact.findOneOrFail( - { email: 'bibi@bloxberg.de' }, - { relations: ['user'] }, - ) + const usercontact = await UserContact.findOneOrFail({ + where: { email: 'bibi@bloxberg.de' }, + relations: ['user'], + }) bibi = usercontact.user bibi.passwordEncryptionType = PasswordEncryptionType.EMAIL bibi.password = SecretKeyCryptographyCreateKey( @@ -1450,10 +1456,10 @@ describe('UserResolver', () => { it('changes to gradidoID on login', async () => { await mutate({ mutation: login, variables }) - const usercontact = await UserContact.findOneOrFail( - { email: 'bibi@bloxberg.de' }, - { relations: ['user'] }, - ) + const usercontact = await UserContact.findOneOrFail({ + where: { email: 'bibi@bloxberg.de' }, + relations: ['user'], + }) bibi = usercontact.user expect(bibi).toEqual( @@ -1590,14 +1596,14 @@ describe('UserResolver', () => { }) it('stores the ADMIN_USER_ROLE_SET event in the database', async () => { - const userConatct = await UserContact.findOneOrFail( - { email: 'bibi@bloxberg.de' }, - { relations: ['user'] }, - ) - const adminConatct = await UserContact.findOneOrFail( - { email: 'peter@lustig.de' }, - { relations: ['user'] }, - ) + const userConatct = await UserContact.findOneOrFail({ + where: { email: 'bibi@bloxberg.de' }, + relations: ['user'], + }) + const adminConatct = await UserContact.findOneOrFail({ + where: { email: 'peter@lustig.de' }, + relations: ['user'], + }) await expect(DbEvent.find()).resolves.toContainEqual( expect.objectContaining({ type: EventType.ADMIN_USER_ROLE_SET, @@ -1792,14 +1798,15 @@ describe('UserResolver', () => { }) it('stores the ADMIN_USER_DELETE event in the database', async () => { - const userConatct = await UserContact.findOneOrFail( - { email: 'bibi@bloxberg.de' }, - { relations: ['user'], withDeleted: true }, - ) - const adminConatct = await UserContact.findOneOrFail( - { email: 'peter@lustig.de' }, - { relations: ['user'] }, - ) + const userConatct = await UserContact.findOneOrFail({ + where: { email: 'bibi@bloxberg.de' }, + relations: ['user'], + withDeleted: true, + }) + const adminConatct = await UserContact.findOneOrFail({ + where: { email: 'peter@lustig.de' }, + relations: ['user'], + }) await expect(DbEvent.find()).resolves.toContainEqual( expect.objectContaining({ type: EventType.ADMIN_USER_DELETE, @@ -1943,10 +1950,10 @@ describe('UserResolver', () => { }) it('sends an account activation email', async () => { - const userConatct = await UserContact.findOneOrFail( - { email: 'bibi@bloxberg.de' }, - { relations: ['user'] }, - ) + const userConatct = await UserContact.findOneOrFail({ + where: { email: 'bibi@bloxberg.de' }, + relations: ['user'], + }) const activationLink = CONFIG.EMAIL_LINK_VERIFICATION.replace( /{optin}/g, userConatct.emailVerificationCode.toString(), @@ -1965,10 +1972,10 @@ describe('UserResolver', () => { }) it('stores the EMAIL_ADMIN_CONFIRMATION event in the database', async () => { - const userConatct = await UserContact.findOneOrFail( - { email: 'bibi@bloxberg.de' }, - { relations: ['user'] }, - ) + const userConatct = await UserContact.findOneOrFail({ + where: { email: 'bibi@bloxberg.de' }, + relations: ['user'], + }) await expect(DbEvent.find()).resolves.toContainEqual( expect.objectContaining({ type: EventType.EMAIL_ADMIN_CONFIRMATION, @@ -2086,14 +2093,14 @@ describe('UserResolver', () => { }) it('stores the ADMIN_USER_UNDELETE event in the database', async () => { - const userConatct = await UserContact.findOneOrFail( - { email: 'bibi@bloxberg.de' }, - { relations: ['user'] }, - ) - const adminConatct = await UserContact.findOneOrFail( - { email: 'peter@lustig.de' }, - { relations: ['user'] }, - ) + const userConatct = await UserContact.findOneOrFail({ + where: { email: 'bibi@bloxberg.de' }, + relations: ['user'], + }) + const adminConatct = await UserContact.findOneOrFail({ + where: { email: 'peter@lustig.de' }, + relations: ['user'], + }) await expect(DbEvent.find()).resolves.toContainEqual( expect.objectContaining({ type: EventType.ADMIN_USER_UNDELETE, diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 840bb43c9..214da858d 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -2,7 +2,7 @@ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-member-access */ /* eslint-disable @typescript-eslint/restrict-template-expressions */ -import { getConnection, getCustomRepository, IsNull, Not, Equal } from '@dbTools/typeorm' +import { getConnection, getCustomRepository, IsNull, Not } from '@dbTools/typeorm' import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' import { TransactionLink as DbTransactionLink } from '@entity/TransactionLink' import { User as DbUser } from '@entity/User' @@ -82,13 +82,13 @@ const newEmailContact = (email: string, userId: number): DbUserContact => { emailContact.type = UserContactType.USER_CONTACT_EMAIL emailContact.emailChecked = false emailContact.emailOptInTypeId = OptInType.EMAIL_OPT_IN_REGISTER - emailContact.emailVerificationCode = random(64) + emailContact.emailVerificationCode = random(64).toString() logger.debug('newEmailContact...successful', emailContact) return emailContact } // eslint-disable-next-line @typescript-eslint/ban-types -export const activationLink = (verificationCode: BigInt): string => { +export const activationLink = (verificationCode: string): string => { logger.debug(`activationLink(${verificationCode})...`) return CONFIG.EMAIL_LINK_SETPASSWORD.replace(/{optin}/g, verificationCode.toString()) } @@ -365,7 +365,7 @@ export class UserResolver { user.emailContact.updatedAt = new Date() user.emailContact.emailResendCount++ - user.emailContact.emailVerificationCode = random(64) + user.emailContact.emailVerificationCode = random(64).toString() user.emailContact.emailOptInTypeId = OptInType.EMAIL_OPT_IN_RESET_PASSWORD await user.emailContact.save().catch(() => { throw new LogError('Unable to save email verification code', user.emailContact) @@ -404,7 +404,7 @@ export class UserResolver { // load code const userContact = await DbUserContact.findOneOrFail({ - where: { emailVerificationCode: Equal(BigInt(code)) }, + where: { emailVerificationCode: code }, relations: ['user'], }).catch(() => { throw new LogError('Could not login with emailVerificationCode') @@ -475,7 +475,7 @@ export class UserResolver { async queryOptIn(@Arg('optIn') optIn: string): Promise { logger.info(`queryOptIn(${optIn})...`) const userContact = await DbUserContact.findOneOrFail({ - where: { emailVerificationCode: Equal(BigInt(optIn)) }, + where: { emailVerificationCode: optIn }, }) logger.debug('found optInCode', userContact) // Code is only valid for `CONFIG.EMAIL_CODE_VALID_TIME` minutes diff --git a/backend/src/seeds/factory/creation.ts b/backend/src/seeds/factory/creation.ts index 5b4c56c57..5ad1b2e4e 100644 --- a/backend/src/seeds/factory/creation.ts +++ b/backend/src/seeds/factory/creation.ts @@ -19,7 +19,10 @@ export const creationFactory = async ( creation: CreationInterface, ): Promise => { const { mutate } = client - await mutate({ mutation: login, variables: { email: creation.email, password: 'Aa12345_' } }) + await mutate({ + mutation: login, + variables: { email: creation.email, password: 'Aa12345_' }, + }) const { data: { createContribution: contribution }, @@ -30,7 +33,9 @@ export const creationFactory = async ( await mutate({ mutation: login, variables: { email: 'peter@lustig.de', password: 'Aa12345_' } }) await mutate({ mutation: confirmContribution, variables: { id: contribution.id } }) - const confirmedContribution = await Contribution.findOneOrFail({ id: contribution.id }) + const confirmedContribution = await Contribution.findOneOrFail({ + where: { id: contribution.id }, + }) if (creation.moveCreationDate) { const transaction = await Transaction.findOneOrFail({ diff --git a/backend/src/seeds/factory/transactionLink.ts b/backend/src/seeds/factory/transactionLink.ts index cab478c4b..b44fe349c 100644 --- a/backend/src/seeds/factory/transactionLink.ts +++ b/backend/src/seeds/factory/transactionLink.ts @@ -32,7 +32,7 @@ export const transactionLinkFactory = async ( } = await mutate({ mutation: createTransactionLink, variables }) if (transactionLink.createdAt || transactionLink.deletedAt) { - const dbTransactionLink = await TransactionLink.findOneOrFail({ id }) + const dbTransactionLink = await TransactionLink.findOneOrFail({ where: { id } }) if (transactionLink.createdAt) { dbTransactionLink.createdAt = transactionLink.createdAt diff --git a/backend/src/seeds/factory/user.ts b/backend/src/seeds/factory/user.ts index 13a274911..d40154e12 100644 --- a/backend/src/seeds/factory/user.ts +++ b/backend/src/seeds/factory/user.ts @@ -19,7 +19,7 @@ export const userFactory = async ( } = await mutate({ mutation: createUser, variables: user }) // console.log('creatUser:', { id }, { user }) // get user from database - let dbUser = await User.findOneOrFail({ id }, { relations: ['emailContact'] }) + let dbUser = await User.findOneOrFail({ where: { id }, relations: ['emailContact'] }) // console.log('dbUser:', dbUser) const emailContact = dbUser.emailContact @@ -33,7 +33,7 @@ export const userFactory = async ( } // get last changes of user from database - dbUser = await User.findOneOrFail({ id }) + dbUser = await User.findOneOrFail({ where: { id } }) if (user.createdAt || user.deletedAt || user.isAdmin) { if (user.createdAt) dbUser.createdAt = user.createdAt diff --git a/backend/src/seeds/index.ts b/backend/src/seeds/index.ts index 77fa51990..bc7950f26 100644 --- a/backend/src/seeds/index.ts +++ b/backend/src/seeds/index.ts @@ -1,3 +1,9 @@ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-unsafe-call */ +/* eslint-disable @typescript-eslint/no-unsafe-return */ + import { entities } from '@entity/index' import { createTestClient } from 'apollo-server-testing' import { name, internet, datatype } from 'faker' @@ -36,12 +42,10 @@ export const cleanDB = async () => { } } -const [entityTypes] = entities - -const resetEntity = async (entity: typeof entityTypes) => { +const resetEntity = async (entity: any) => { const items = await entity.find({ withDeleted: true }) if (items.length > 0) { - const ids = items.map((i) => i.id) + const ids = items.map((e: any) => e.id) await entity.delete(ids) } } diff --git a/backend/test/helpers.ts b/backend/test/helpers.ts index 7f55b3c70..ec9c14795 100644 --- a/backend/test/helpers.ts +++ b/backend/test/helpers.ts @@ -1,4 +1,10 @@ /* eslint-disable @typescript-eslint/unbound-method */ +/* eslint-disable @typescript-eslint/no-unsafe-assignment */ +/* eslint-disable @typescript-eslint/no-unsafe-member-access */ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/no-unsafe-call */ +/* eslint-disable @typescript-eslint/no-unsafe-return */ + import { entities } from '@entity/index' import { createTestClient } from 'apollo-server-testing' @@ -7,7 +13,6 @@ import { createServer } from '@/server/createServer' import { i18n, logger } from './testSetup' export const headerPushMock = jest.fn((t) => { - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access context.token = t.value }) @@ -21,7 +26,7 @@ const context = { } export const cleanDB = async () => { - // this only works as lond we do not have foreign key constraints + // this only works as long we do not have foreign key constraints for (const entity of entities) { await resetEntity(entity) } @@ -36,12 +41,10 @@ export const testEnvironment = async (testLogger = logger, testI18n = i18n) => { return { mutate, query, con } } -const [entityTypes] = entities - -export const resetEntity = async (entity: typeof entityTypes) => { +export const resetEntity = async (entity: anny) => { const items = await entity.find({ withDeleted: true }) if (items.length > 0) { - const ids = items.map((i) => i.id) + const ids = items.map((e: any) => e.id) await entity.delete(ids) } } diff --git a/database/entity/0057-clear_old_password_junk/UserContact.ts b/database/entity/0057-clear_old_password_junk/UserContact.ts index dd06d3bbc..6064a3ea3 100644 --- a/database/entity/0057-clear_old_password_junk/UserContact.ts +++ b/database/entity/0057-clear_old_password_junk/UserContact.ts @@ -32,7 +32,7 @@ export class UserContact extends BaseEntity { email: string @Column({ name: 'email_verification_code', type: 'bigint', unsigned: true, unique: true }) - emailVerificationCode: BigInt + emailVerificationCode: string @Column({ name: 'email_opt_in_type_id' }) emailOptInTypeId: number From 642d2202bf80c5386aeef381eb4e5e675dde8dbd Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 26 Jun 2023 17:34:32 +0200 Subject: [PATCH 39/94] try to get repository working again --- .../src/graphql/resolver/BalanceResolver.ts | 3 +- .../resolver/TransactionLinkResolver.ts | 8 ++ .../graphql/resolver/TransactionResolver.ts | 3 +- backend/src/seeds/factory/transactionLink.ts | 5 +- backend/src/seeds/index.ts | 1 + backend/src/server/createServer.ts | 1 + .../src/typeorm/repository/TransactionLink.ts | 73 ++++++++++--------- backend/src/util/validate.ts | 5 +- backend/test/helpers.ts | 2 +- 9 files changed, 57 insertions(+), 44 deletions(-) diff --git a/backend/src/graphql/resolver/BalanceResolver.ts b/backend/src/graphql/resolver/BalanceResolver.ts index 9cd133181..9a11093b8 100644 --- a/backend/src/graphql/resolver/BalanceResolver.ts +++ b/backend/src/graphql/resolver/BalanceResolver.ts @@ -6,7 +6,7 @@ import { Decimal } from 'decimal.js-light' import { Resolver, Query, Ctx, Authorized } from 'type-graphql' import { Balance } from '@model/Balance' -import { TransactionLinkRepository } from '@repository/TransactionLink' +import { transactionLinkRepository } from '@repository/TransactionLink' import { RIGHTS } from '@/auth/RIGHTS' import { Context, getUser } from '@/server/context' @@ -77,7 +77,6 @@ export class BalanceResolver { ) // The final balance is reduced by the link amount withheld - const transactionLinkRepository = getCustomRepository(TransactionLinkRepository) const { sumHoldAvailableAmount } = context.sumHoldAvailableAmount ? { sumHoldAvailableAmount: context.sumHoldAvailableAmount } : await transactionLinkRepository.summary(user.id, now) diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.ts b/backend/src/graphql/resolver/TransactionLinkResolver.ts index 0ff606fa5..b198a2335 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.ts @@ -76,14 +76,22 @@ export class TransactionLinkResolver { throw new LogError('Amount must be a positive number', amount) } + console.log('Hallo') + const holdAvailableAmount = amount.minus(calculateDecay(amount, createdDate, validUntil).decay) + console.log(holdAvailableAmount) + // validate amount const sendBalance = await calculateBalance(user.id, holdAvailableAmount.mul(-1), createdDate) + console.log('sendBalance', sendBalance) + if (!sendBalance) { throw new LogError('User has not enough GDD', user.id) } + console.log(sendBalance) + const transactionLink = DbTransactionLink.create() transactionLink.userId = user.id transactionLink.amount = amount diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index 40e9ec2dd..8a1097b99 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -16,7 +16,7 @@ import { TransactionTypeId } from '@enum/TransactionTypeId' import { Transaction } from '@model/Transaction' import { TransactionList } from '@model/TransactionList' import { User } from '@model/User' -import { TransactionLinkRepository } from '@repository/TransactionLink' +import { transactionLinkRepository } from '@repository/TransactionLink' import { RIGHTS } from '@/auth/RIGHTS' import { @@ -245,7 +245,6 @@ export class TransactionResolver { const self = new User(user) const transactions: Transaction[] = [] - const transactionLinkRepository = getCustomRepository(TransactionLinkRepository) const { sumHoldAvailableAmount, sumAmount, lastDate, firstDate, transactionLinkcount } = await transactionLinkRepository.summary(user.id, now) context.linkCount = transactionLinkcount diff --git a/backend/src/seeds/factory/transactionLink.ts b/backend/src/seeds/factory/transactionLink.ts index b44fe349c..8bbdb64c4 100644 --- a/backend/src/seeds/factory/transactionLink.ts +++ b/backend/src/seeds/factory/transactionLink.ts @@ -24,12 +24,15 @@ export const transactionLinkFactory = async ( memo: transactionLink.memo, } + const result = await mutate({ mutation: createTransactionLink, variables }) + console.log(result) + // get the transaction links's id const { data: { createTransactionLink: { id }, }, - } = await mutate({ mutation: createTransactionLink, variables }) + } = result if (transactionLink.createdAt || transactionLink.deletedAt) { const dbTransactionLink = await TransactionLink.findOneOrFail({ where: { id } }) diff --git a/backend/src/seeds/index.ts b/backend/src/seeds/index.ts index bc7950f26..2560aa883 100644 --- a/backend/src/seeds/index.ts +++ b/backend/src/seeds/index.ts @@ -52,6 +52,7 @@ const resetEntity = async (entity: any) => { const run = async () => { const server = await createServer(context) + console.log(server) const seedClient = createTestClient(server.apollo) const { con } = server await cleanDB() diff --git a/backend/src/server/createServer.ts b/backend/src/server/createServer.ts index c162d9f6f..36a5bd5e0 100644 --- a/backend/src/server/createServer.ts +++ b/backend/src/server/createServer.ts @@ -37,6 +37,7 @@ export const createServer = async ( logger.debug('createServer...') // open mysql connection + console.log('Connection.getInstance') const con = await Connection.getInstance() if (!con?.isConnected) { logger.fatal(`Couldn't open connection to database!`) diff --git a/backend/src/typeorm/repository/TransactionLink.ts b/backend/src/typeorm/repository/TransactionLink.ts index 8a66aa7cf..45586c538 100644 --- a/backend/src/typeorm/repository/TransactionLink.ts +++ b/backend/src/typeorm/repository/TransactionLink.ts @@ -1,41 +1,42 @@ /* eslint-disable @typescript-eslint/no-unsafe-assignment */ /* eslint-disable @typescript-eslint/no-unsafe-argument */ -import { Repository, EntityRepository } from '@dbTools/typeorm' +import { getConnection } from '@dbTools/typeorm' import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink' import { Decimal } from 'decimal.js-light' -@EntityRepository(dbTransactionLink) -export class TransactionLinkRepository extends Repository { - async summary( - userId: number, - date: Date, - ): Promise<{ - sumHoldAvailableAmount: Decimal - sumAmount: Decimal - lastDate: Date | null - firstDate: Date | null - transactionLinkcount: number - }> { - const { sumHoldAvailableAmount, sumAmount, lastDate, firstDate, count } = - await this.createQueryBuilder('transactionLinks') - .select('SUM(transactionLinks.holdAvailableAmount)', 'sumHoldAvailableAmount') - .addSelect('SUM(transactionLinks.amount)', 'sumAmount') - .addSelect('MAX(transactionLinks.validUntil)', 'lastDate') - .addSelect('MIN(transactionLinks.createdAt)', 'firstDate') - .addSelect('COUNT(*)', 'count') - .where('transactionLinks.userId = :userId', { userId }) - .andWhere('transactionLinks.redeemedAt is NULL') - .andWhere('transactionLinks.validUntil > :date', { date }) - .orderBy('transactionLinks.createdAt', 'DESC') - .getRawOne() - return { - sumHoldAvailableAmount: sumHoldAvailableAmount - ? new Decimal(sumHoldAvailableAmount) - : new Decimal(0), - sumAmount: sumAmount ? new Decimal(sumAmount) : new Decimal(0), - lastDate: lastDate || null, - firstDate: firstDate || null, - transactionLinkcount: count || 0, - } - } -} +export const transactionLinkRepository = getConnection() + .getRepository(dbTransactionLink) + .extend({ + async summary( + userId: number, + date: Date, + ): Promise<{ + sumHoldAvailableAmount: Decimal + sumAmount: Decimal + lastDate: Date | null + firstDate: Date | null + transactionLinkcount: number + }> { + const { sumHoldAvailableAmount, sumAmount, lastDate, firstDate, count } = + await this.createQueryBuilder('transactionLinks') + .select('SUM(transactionLinks.holdAvailableAmount)', 'sumHoldAvailableAmount') + .addSelect('SUM(transactionLinks.amount)', 'sumAmount') + .addSelect('MAX(transactionLinks.validUntil)', 'lastDate') + .addSelect('MIN(transactionLinks.createdAt)', 'firstDate') + .addSelect('COUNT(*)', 'count') + .where('transactionLinks.userId = :userId', { userId }) + .andWhere('transactionLinks.redeemedAt is NULL') + .andWhere('transactionLinks.validUntil > :date', { date }) + .orderBy('transactionLinks.createdAt', 'DESC') + .getRawOne() + return { + sumHoldAvailableAmount: sumHoldAvailableAmount + ? new Decimal(sumHoldAvailableAmount) + : new Decimal(0), + sumAmount: sumAmount ? new Decimal(sumAmount) : new Decimal(0), + lastDate: lastDate || null, + firstDate: firstDate || null, + transactionLinkcount: count || 0, + } + }, + }) diff --git a/backend/src/util/validate.ts b/backend/src/util/validate.ts index 22a6ee5db..8c84b06b2 100644 --- a/backend/src/util/validate.ts +++ b/backend/src/util/validate.ts @@ -3,7 +3,7 @@ import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink' import { Decimal } from 'decimal.js-light' import { Decay } from '@model/Decay' -import { TransactionLinkRepository } from '@repository/TransactionLink' +import { transactionLinkRepository } from '@repository/TransactionLink' import { getLastTransaction } from '@/graphql/resolver/util/getLastTransaction' @@ -26,10 +26,11 @@ async function calculateBalance( const lastTransaction = await getLastTransaction(userId) if (!lastTransaction) return null + console.log(lastTransaction) + const decay = calculateDecay(lastTransaction.balance, lastTransaction.balanceDate, time) const balance = decay.balance.add(amount.toString()) - const transactionLinkRepository = getCustomRepository(TransactionLinkRepository) const { sumHoldAvailableAmount } = await transactionLinkRepository.summary(userId, time) // If we want to redeem a link we need to make sure that the link amount is not considered as blocked diff --git a/backend/test/helpers.ts b/backend/test/helpers.ts index ec9c14795..8a541e3e4 100644 --- a/backend/test/helpers.ts +++ b/backend/test/helpers.ts @@ -41,7 +41,7 @@ export const testEnvironment = async (testLogger = logger, testI18n = i18n) => { return { mutate, query, con } } -export const resetEntity = async (entity: anny) => { +export const resetEntity = async (entity: any) => { const items = await entity.find({ withDeleted: true }) if (items.length > 0) { const ids = items.map((e: any) => e.id) From 3af471aebbab0138e629878de13d8780d742071a Mon Sep 17 00:00:00 2001 From: elweyn Date: Mon, 26 Jun 2023 20:00:24 +0200 Subject: [PATCH 40/94] Change btn-warning color and background color to #e1a908 --- admin/src/components/Tables/OpenCreationsTable.vue | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/admin/src/components/Tables/OpenCreationsTable.vue b/admin/src/components/Tables/OpenCreationsTable.vue index 9d93eba60..51f00a7d4 100644 --- a/admin/src/components/Tables/OpenCreationsTable.vue +++ b/admin/src/components/Tables/OpenCreationsTable.vue @@ -166,3 +166,9 @@ export default { }, } + From 9ceb5383cfea3da192d213d111900a20a35ec07f Mon Sep 17 00:00:00 2001 From: elweyn Date: Tue, 27 Jun 2023 09:14:20 +0200 Subject: [PATCH 41/94] Set cols from 12 to 6, px from 2 to 1 and remove offset. --- .../DecayInformation-Long.vue | 27 ++++++++++--------- .../TransactionRows/DurationRow.vue | 4 +-- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/frontend/src/components/DecayInformations/DecayInformation-Long.vue b/frontend/src/components/DecayInformations/DecayInformation-Long.vue index d7e943225..d4ff66af0 100644 --- a/frontend/src/components/DecayInformations/DecayInformation-Long.vue +++ b/frontend/src/components/DecayInformations/DecayInformation-Long.vue @@ -1,5 +1,5 @@