From eb7f8290aff7f7b43c9ee380765e185e03e90936 Mon Sep 17 00:00:00 2001 From: ogerly Date: Wed, 8 Jun 2022 22:15:59 +0200 Subject: [PATCH 001/977] add Page Community, add query listContributionLinks --- frontend/src/components/Menu/Sidebar.vue | 4 ++ frontend/src/graphql/queries.js | 15 +++++++ frontend/src/pages/Community.vue | 50 ++++++++++++++++++++++++ frontend/src/routes/routes.js | 7 ++++ 4 files changed, 76 insertions(+) create mode 100644 frontend/src/pages/Community.vue diff --git a/frontend/src/components/Menu/Sidebar.vue b/frontend/src/components/Menu/Sidebar.vue index 028b7aca6..8062e5ef5 100644 --- a/frontend/src/components/Menu/Sidebar.vue +++ b/frontend/src/components/Menu/Sidebar.vue @@ -34,6 +34,10 @@ {{ $t('navigation.admin_area') }} + + + {{ $t('community.community') }} + {{ $t('navigation.logout') }} diff --git a/frontend/src/graphql/queries.js b/frontend/src/graphql/queries.js index 601880a51..c6c847868 100644 --- a/frontend/src/graphql/queries.js +++ b/frontend/src/graphql/queries.js @@ -144,3 +144,18 @@ export const listTransactionLinks = gql` } } ` + +export const listContributionLinks = gql` + query { + listContributionLinks { + startDate + endDate + name + memo + amount + cycle + repetition + maxAmount + } + } +` diff --git a/frontend/src/pages/Community.vue b/frontend/src/pages/Community.vue new file mode 100644 index 000000000..1786f30a0 --- /dev/null +++ b/frontend/src/pages/Community.vue @@ -0,0 +1,50 @@ + + diff --git a/frontend/src/routes/routes.js b/frontend/src/routes/routes.js index e68f97502..540ef9d69 100755 --- a/frontend/src/routes/routes.js +++ b/frontend/src/routes/routes.js @@ -38,6 +38,13 @@ const routes = [ requiresAuth: true, }, }, + { + path: '/community', + component: () => import('@/pages/Community.vue'), + meta: { + requiresAuth: true, + }, + }, { path: '/login/:code?', component: () => import('@/pages/Login.vue'), From 83ebf4aa2efb8396dc6ee42c8b7d3454567ee340 Mon Sep 17 00:00:00 2001 From: ogerly Date: Wed, 8 Jun 2022 22:25:14 +0200 Subject: [PATCH 002/977] add Statistik Container --- frontend/src/pages/Community.vue | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/frontend/src/pages/Community.vue b/frontend/src/pages/Community.vue index 1786f30a0..a59d708d8 100644 --- a/frontend/src/pages/Community.vue +++ b/frontend/src/pages/Community.vue @@ -34,6 +34,20 @@ suport@gradido.net +
+ +
Statistik
+
+
+ Mitglieder + 1203 +
+
+ Mitglieder + 1203 +
+
+
diff --git a/frontend/src/routes/routes.js b/frontend/src/routes/routes.js index e68f97502..540ef9d69 100755 --- a/frontend/src/routes/routes.js +++ b/frontend/src/routes/routes.js @@ -38,6 +38,13 @@ const routes = [ requiresAuth: true, }, }, + { + path: '/community', + component: () => import('@/pages/Community.vue'), + meta: { + requiresAuth: true, + }, + }, { path: '/login/:code?', component: () => import('@/pages/Login.vue'), From 1664a2070fdb96bcbbfe83d42ef9895d3c16dae9 Mon Sep 17 00:00:00 2001 From: ogerly Date: Thu, 7 Jul 2022 08:16:00 +0200 Subject: [PATCH 008/977] locales for Community.vue Page --- frontend/src/locales/de.json | 7 +++++-- frontend/src/locales/en.json | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index fec24b1dc..74850d556 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -28,7 +28,9 @@ "continue-to-registration": "Weiter zur Registrierung", "current-community": "Aktuelle Gemeinschaft", "other-communities": "Weitere Gemeinschaften", - "switch-to-this-community": "zu dieser Gemeinschaft wechseln" + "switch-to-this-community": "zu dieser Gemeinschaft wechseln", + "writing":"Schreiben", + "myContributions":"Meine Beiträge" }, "contribution-link": { "thanksYouWith": "dankt dir mit" @@ -200,7 +202,8 @@ "profile": "Mein Profil", "send": "Senden", "support": "Support", - "transactions": "Transaktionen" + "transactions": "Transaktionen", + "community":"Gemeinschaft" }, "qrCode": "QR Code", "send_gdd": "GDD versenden", diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index a0ef6723d..1312b60b4 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -28,7 +28,9 @@ "continue-to-registration": "Continue to registration", "current-community": "Current community", "other-communities": "Other communities", - "switch-to-this-community": "Switch to this community" + "switch-to-this-community": "Switch to this community", + "writing":"Writing", + "myContributions":"My contributions" }, "contribution-link": { "thanksYouWith": "thanks you with" @@ -200,7 +202,8 @@ "profile": "My profile", "send": "Send", "support": "Support", - "transactions": "Transactions" + "transactions": "Transactions", + "community":"Community" }, "qrCode": "QR Code", "send_gdd": "GDD send", From d8fb3608a2931d380f1902244b9169e70ef1476d Mon Sep 17 00:00:00 2001 From: ogerly Date: Thu, 7 Jul 2022 12:01:27 +0200 Subject: [PATCH 009/977] add new component ContributionForm.vue --- .../Contributions/ContributionForm.vue | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 frontend/src/components/Contributions/ContributionForm.vue diff --git a/frontend/src/components/Contributions/ContributionForm.vue b/frontend/src/components/Contributions/ContributionForm.vue new file mode 100644 index 000000000..a67b4642f --- /dev/null +++ b/frontend/src/components/Contributions/ContributionForm.vue @@ -0,0 +1,79 @@ + + From fa0598c75262da33fedd4056ec9defba4f969551 Mon Sep 17 00:00:00 2001 From: ogerly Date: Thu, 7 Jul 2022 12:02:31 +0200 Subject: [PATCH 010/977] add form in ContributionForm.vue --- frontend/src/i18n.js | 18 ++++++++++++++++++ frontend/src/locales/de.json | 10 +++++++++- frontend/src/locales/en.json | 9 ++++++++- frontend/src/pages/Community.vue | 6 +++++- 4 files changed, 40 insertions(+), 3 deletions(-) diff --git a/frontend/src/i18n.js b/frontend/src/i18n.js index f4f969008..74de46c29 100644 --- a/frontend/src/i18n.js +++ b/frontend/src/i18n.js @@ -75,6 +75,15 @@ const dateTimeFormats = { hour: 'numeric', minute: 'numeric', }, + monthShort: { + month: 'short', + }, + month: { + month: 'long', + }, + year: { + year: 'numeric', + }, }, de: { short: { @@ -90,6 +99,15 @@ const dateTimeFormats = { hour: 'numeric', minute: 'numeric', }, + monthShort: { + month: 'short', + }, + month: { + month: 'long', + }, + year: { + year: 'numeric', + }, }, } diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index 74850d556..3af893009 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -32,6 +32,10 @@ "writing":"Schreiben", "myContributions":"Meine Beiträge" }, + "contribution": { + "activity":"Tätigkeit", + "submit":"Einreichen" + }, "contribution-link": { "thanksYouWith": "dankt dir mit" }, @@ -182,7 +186,10 @@ "equal": "=", "exclaim": "!", "minus": "−", - "pipe": "|" + "pipe": "|", + "divide": "/", + "equalTo":"<" + }, "message": { "activateEmail": "Dein Konto wurde noch nicht aktiviert. Bitte überprüfe deine E-Mail und klicke den Aktivierungslink oder fordere einen neuen Aktivierungslink über die Password Reset Seite an.", @@ -275,6 +282,7 @@ "days": "Tage", "hours": "Stunden", "minutes": "Minuten", + "month": "Monat", "months": "Monate", "seconds": "Sekunden", "years": "Jahr" diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index 1312b60b4..8244eb1fb 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -32,6 +32,10 @@ "writing":"Writing", "myContributions":"My contributions" }, + "contribution": { + "activity":"Activity", + "submit":"Submit" + }, "contribution-link": { "thanksYouWith": "thanks you with" }, @@ -182,7 +186,9 @@ "equal": "=", "exclaim": "!", "minus": "−", - "pipe": "|" + "pipe": "|", + "divide": "/", + "equalTo":"<" }, "message": { "activateEmail": "Your account has not been activated yet. Please check your emails and click the activation link or order a new activation link over the password reset page.", @@ -275,6 +281,7 @@ "days": "Days", "hours": "Hours", "minutes": "Minutes", + "month": "Month", "months": "Months", "seconds": "Seconds", "years": "Year" diff --git a/frontend/src/pages/Community.vue b/frontend/src/pages/Community.vue index 9264df623..66fdfcae6 100644 --- a/frontend/src/pages/Community.vue +++ b/frontend/src/pages/Community.vue @@ -3,7 +3,7 @@
-

{{ $t('community.writing') }}

+

{{ $t('community.myContributions') }}

@@ -16,7 +16,11 @@
From 50050e138f96bcd7b75890b001737ce419643840 Mon Sep 17 00:00:00 2001 From: ogerly Date: Thu, 7 Jul 2022 12:05:06 +0200 Subject: [PATCH 011/977] change form.text to form.memo --- .../components/Contributions/ContributionForm.vue | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/frontend/src/components/Contributions/ContributionForm.vue b/frontend/src/components/Contributions/ContributionForm.vue index a67b4642f..9b4f9de1b 100644 --- a/frontend/src/components/Contributions/ContributionForm.vue +++ b/frontend/src/components/Contributions/ContributionForm.vue @@ -13,7 +13,7 @@
- {{ form.text.length }} - {{ $t('math.equalTo') }} {{ minlength }} + {{ form.memo.length }} + {{ $t('math.equalTo') }} {{ minlength }} {{ $t('math.divide') }} {{ maxlength }}
@@ -49,8 +49,9 @@ export default { minlength: 50, maxlength: 500, form: { - text: '', selected: this.$moment().format('MMMM'), + memo: '', + amount: 0, }, options: [ @@ -70,7 +71,7 @@ export default { }, computed: { disable() { - if (this.form.text.length < this.minlength) return true + if (this.form.memo.length < this.minlength) return true if (this.form.amount < 1 && this.form.amount < 1000) return true return false }, From 924db68d0638172d3dbc280e1ca7dd321d9abed6 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 7 Jul 2022 15:52:55 +0200 Subject: [PATCH 012/977] setup community statistics --- backend/src/auth/RIGHTS.ts | 1 + .../src/graphql/model/CommunityStatistics.ts | 26 +++++++++++++++++++ .../graphql/resolver/StatisticsResolver.ts | 26 +++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 backend/src/graphql/model/CommunityStatistics.ts create mode 100644 backend/src/graphql/resolver/StatisticsResolver.ts diff --git a/backend/src/auth/RIGHTS.ts b/backend/src/auth/RIGHTS.ts index c10fc96de..cbf650ec1 100644 --- a/backend/src/auth/RIGHTS.ts +++ b/backend/src/auth/RIGHTS.ts @@ -44,4 +44,5 @@ export enum RIGHTS { LIST_CONTRIBUTION_LINKS = 'LIST_CONTRIBUTION_LINKS', DELETE_CONTRIBUTION_LINK = 'DELETE_CONTRIBUTION_LINK', UPDATE_CONTRIBUTION_LINK = 'UPDATE_CONTRIBUTION_LINK', + COMMUNITY_STATISTICS = 'COMMUNITY_STATISTICS', } diff --git a/backend/src/graphql/model/CommunityStatistics.ts b/backend/src/graphql/model/CommunityStatistics.ts new file mode 100644 index 000000000..61354115c --- /dev/null +++ b/backend/src/graphql/model/CommunityStatistics.ts @@ -0,0 +1,26 @@ +import { ObjectType, Field } from 'type-graphql' +import Decimal from 'decimal.js-light' + +@ObjectType() +export class CommunityStatistics { + @Field(() => Number) + totalUsers: number + + @Field(() => Number) + activeUsers: number + + @Field(() => Number) + deletedUsers: number + + @Field(() => Decimal) + totalGradidoCreated: Decimal + + @Field(() => Decimal) + totalGradidoDecayed: Decimal + + @Field(() => Decimal) + totalGradidoAvailable: Decimal + + @Field(() => Decimal) + totalGradidoUnbookedDecayed: Decimal +} diff --git a/backend/src/graphql/resolver/StatisticsResolver.ts b/backend/src/graphql/resolver/StatisticsResolver.ts new file mode 100644 index 000000000..a90d42f75 --- /dev/null +++ b/backend/src/graphql/resolver/StatisticsResolver.ts @@ -0,0 +1,26 @@ +import { Resolver, Query, Arg, Args, Authorized, Ctx, Int } from 'type-graphql' +import { RIGHTS } from '@/auth/RIGHTS' +import { CommunityStatistics } from '@model/CommunityStatistics' +import { User as DbUser } from '@entity/User' +import { getConnection } from '@dbTools/typeorm' +import Decimal from 'decimal.js-light' + +@Resolver() +export class StatisticsResolver { + @Authorized([RIGHTS.COMMUNITY_STATISTICS]) + @Query(() => CommunityStatistics) + async communityStatistics(): Promise { + const totalUsers = await DbUser.find({ withDeleted: true }) + console.log(totalUsers.length) + + return { + totalUsers: 12, + activeUsers: 6, + deletedUsers: 1, + totalGradidoCreated: new Decimal(3000), + totalGradidoDecayed: new Decimal(200), + totalGradidoAvailable: new Decimal(2800), + totalGradidoUnbookedDecayed: new Decimal(200), + } + } +} From df227607ad539ad0bc209eebed917d0a7b356bed Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 7 Jul 2022 17:27:50 +0200 Subject: [PATCH 013/977] get basic statistics from database --- .../graphql/resolver/StatisticsResolver.ts | 71 ++++++++++++++++--- 1 file changed, 61 insertions(+), 10 deletions(-) diff --git a/backend/src/graphql/resolver/StatisticsResolver.ts b/backend/src/graphql/resolver/StatisticsResolver.ts index a90d42f75..4c1500839 100644 --- a/backend/src/graphql/resolver/StatisticsResolver.ts +++ b/backend/src/graphql/resolver/StatisticsResolver.ts @@ -1,26 +1,77 @@ -import { Resolver, Query, Arg, Args, Authorized, Ctx, Int } from 'type-graphql' +import { Resolver, Query, Authorized } from 'type-graphql' import { RIGHTS } from '@/auth/RIGHTS' import { CommunityStatistics } from '@model/CommunityStatistics' import { User as DbUser } from '@entity/User' +import { Transaction as DbTransaction } from '@entity/Transaction' import { getConnection } from '@dbTools/typeorm' import Decimal from 'decimal.js-light' +import { calculateDecay } from '@/util/decay' @Resolver() export class StatisticsResolver { @Authorized([RIGHTS.COMMUNITY_STATISTICS]) @Query(() => CommunityStatistics) async communityStatistics(): Promise { - const totalUsers = await DbUser.find({ withDeleted: true }) - console.log(totalUsers.length) + const allUsers = await DbUser.find({ withDeleted: true }) + + let totalUsers = 0 + let activeUsers = 0 + let deletedUsers = 0 + + let totalGradidoAvailable: Decimal = new Decimal(0) + let totalGradidoUnbookedDecayed: Decimal = new Decimal(0) + + const receivedCallDate = new Date() + + for (let i = 0; i < allUsers.length; i++) { + if (allUsers[i].deletedAt) { + deletedUsers++ + } else { + totalUsers++ + const lastTransaction = await DbTransaction.findOne({ + where: { userId: allUsers[i].id }, + order: { balanceDate: 'DESC' }, + }) + if (lastTransaction) { + activeUsers++ + const decay = calculateDecay( + lastTransaction.balance, + lastTransaction.balanceDate, + receivedCallDate, + ) + if (decay) { + totalGradidoAvailable = totalGradidoAvailable.plus(decay.balance.toString()) + totalGradidoUnbookedDecayed = totalGradidoUnbookedDecayed.plus(decay.decay.toString()) + } + } + } + } + + const queryRunner = getConnection().createQueryRunner() + await queryRunner.connect() + + const { totalGradidoCreated } = await queryRunner.manager + .createQueryBuilder() + .select('SUM(transaction.amount) AS totalGradidoCreated') + .from(DbTransaction, 'transaction') + .where('transaction.typeId = 1') + .getRawOne() + + const { totalGradidoDecayed } = await queryRunner.manager + .createQueryBuilder() + .select('SUM(transaction.decay) AS totalGradidoDecayed') + .from(DbTransaction, 'transaction') + .where('transaction.decay IS NOT NULL') + .getRawOne() return { - totalUsers: 12, - activeUsers: 6, - deletedUsers: 1, - totalGradidoCreated: new Decimal(3000), - totalGradidoDecayed: new Decimal(200), - totalGradidoAvailable: new Decimal(2800), - totalGradidoUnbookedDecayed: new Decimal(200), + totalUsers, + activeUsers, + deletedUsers, + totalGradidoCreated, + totalGradidoDecayed, + totalGradidoAvailable, + totalGradidoUnbookedDecayed, } } } From baa5084f5d6365485f1af3a109e5dcd771155eed Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 7 Jul 2022 17:29:09 +0200 Subject: [PATCH 014/977] add query for communty statistics --- admin/src/graphql/communityStatistics.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 admin/src/graphql/communityStatistics.js diff --git a/admin/src/graphql/communityStatistics.js b/admin/src/graphql/communityStatistics.js new file mode 100644 index 000000000..868bfd02a --- /dev/null +++ b/admin/src/graphql/communityStatistics.js @@ -0,0 +1,15 @@ +import gql from 'graphql-tag' + +export const communityStatistics = gql` + query { + communityStatistics { + totalUsers + activeUsers + deletedUsers + totalGradidoCreated + totalGradidoDecayed + totalGradidoAvailable + totalGradidoUnbookedDecayed + } + } +` From c3d62db1e5bdb8d2eeaf7b4eefaca40313d3fded Mon Sep 17 00:00:00 2001 From: ogerly Date: Fri, 8 Jul 2022 11:34:55 +0200 Subject: [PATCH 015/977] add componente ContributionList.vue --- .../Contributions/ContributionList.vue | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 frontend/src/components/Contributions/ContributionList.vue diff --git a/frontend/src/components/Contributions/ContributionList.vue b/frontend/src/components/Contributions/ContributionList.vue new file mode 100644 index 000000000..e3dc41b5f --- /dev/null +++ b/frontend/src/components/Contributions/ContributionList.vue @@ -0,0 +1,17 @@ + + From 4cc1642988fb65a0d4f50440f8346bced7f8bff3 Mon Sep 17 00:00:00 2001 From: ogerly Date: Fri, 8 Jul 2022 21:26:18 +0200 Subject: [PATCH 016/977] add mutations createContribution --- frontend/src/graphql/mutations.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/frontend/src/graphql/mutations.js b/frontend/src/graphql/mutations.js index 9b035cba6..d70eb8c99 100644 --- a/frontend/src/graphql/mutations.js +++ b/frontend/src/graphql/mutations.js @@ -89,3 +89,12 @@ export const redeemTransactionLink = gql` redeemTransactionLink(code: $code) } ` + +export const createContribution = gql` + mutation($creationDate: String!, $memo: String!, $amount: Decimal!) { + createContribution(creationDate: $creationDate, memo: $memo, amount: $amount) { + amount + memo + } + } +` From 06e2e11da84c7c065d1365ea19b42109d29b7e11 Mon Sep 17 00:00:00 2001 From: mahula Date: Sun, 10 Jul 2022 20:23:21 +0200 Subject: [PATCH 017/977] add initial e2e test setup utilizing Playwright --- e2e-tests/playwright/Dockerfile | 14 ++++++++ e2e-tests/playwright/README.md | 24 ++++++++++++++ e2e-tests/playwright/tests/global-setup.ts | 8 +++++ .../playwright/tests/gradido_login.spec.ts | 15 +++++++++ .../playwright/tests/models/login_page.ts | 33 +++++++++++++++++++ .../playwright/tests/models/welcome_page.ts | 13 ++++++++ .../playwright/tests/playwright.config.ts | 19 +++++++++++ 7 files changed, 126 insertions(+) create mode 100644 e2e-tests/playwright/Dockerfile create mode 100644 e2e-tests/playwright/README.md create mode 100644 e2e-tests/playwright/tests/global-setup.ts create mode 100644 e2e-tests/playwright/tests/gradido_login.spec.ts create mode 100644 e2e-tests/playwright/tests/models/login_page.ts create mode 100644 e2e-tests/playwright/tests/models/welcome_page.ts create mode 100644 e2e-tests/playwright/tests/playwright.config.ts diff --git a/e2e-tests/playwright/Dockerfile b/e2e-tests/playwright/Dockerfile new file mode 100644 index 000000000..ef8d51984 --- /dev/null +++ b/e2e-tests/playwright/Dockerfile @@ -0,0 +1,14 @@ +############################################################################### +# Dockerfile to create a ready to use Playwright Docker image for end-to-end +# testing +############################################################################### +ARG PLAYWIRGHT_VERSION=1.23.2 + +FROM mcr.microsoft.com/playwright:v$PLAYWIRGHT_VERSION-focal + +WORKDIR /tests + +RUN npm install playwright@$PLAYWIRGHT_VERSION +RUN npm install -D @playwright/test + +COPY tests/ /tests diff --git a/e2e-tests/playwright/README.md b/e2e-tests/playwright/README.md new file mode 100644 index 000000000..7f01b780e --- /dev/null +++ b/e2e-tests/playwright/README.md @@ -0,0 +1,24 @@ +# Gradido End-to-End Testing with [Playwright](https://playwright.dev/) (CI-ready via Docker) + + +A sample setup to show-case Playwright (using Typescript) as an end-to-end testing tool for Gradido runniing in a Docker container. +Here we have a simple UI-based happy path login test running against the DEV system. + +## Precondition +Since dependencies and configurations for Github Actions integration is not set up yet, please run + +```bash +docker-compose up +``` + +to boot up the DEV system, before running the test. + +## Execute the test + +```bash +# build a Docker image from the Dockerfile +docker build -t gradido_e2e-tests-playwright . + +# run the Docker container and execute the given tests +docker run -it gradido_e2e-tests-playwright npx playwright test +``` diff --git a/e2e-tests/playwright/tests/global-setup.ts b/e2e-tests/playwright/tests/global-setup.ts new file mode 100644 index 000000000..6f9dad9c4 --- /dev/null +++ b/e2e-tests/playwright/tests/global-setup.ts @@ -0,0 +1,8 @@ +import { FullConfig } from '@playwright/test'; + +async function globalSetup(config: FullConfig) { + process.env.EMAIL = 'bibi@bloxberg.de'; + process.env.PASSWORD = 'Aa12345_'; +} + +export default globalSetup; diff --git a/e2e-tests/playwright/tests/gradido_login.spec.ts b/e2e-tests/playwright/tests/gradido_login.spec.ts new file mode 100644 index 000000000..0853780d1 --- /dev/null +++ b/e2e-tests/playwright/tests/gradido_login.spec.ts @@ -0,0 +1,15 @@ +import { test, expect } from '@playwright/test'; +import { LoginPage } from './models/login_page'; +import { WelcomePage } from './models/welcome_page'; + + +test('Gradido login test (happy path)', async ({ page }) => { + const { EMAIL, PASSWORD } = process.env; + const loginPage = new LoginPage(page); + await loginPage.goto(); + await loginPage.enterEmail(EMAIL); + await loginPage.enterPassword(PASSWORD); + await loginPage.submitLogin(); + // assertions + await expect(page).toHaveURL('./overview'); +}); diff --git a/e2e-tests/playwright/tests/models/login_page.ts b/e2e-tests/playwright/tests/models/login_page.ts new file mode 100644 index 000000000..418adc555 --- /dev/null +++ b/e2e-tests/playwright/tests/models/login_page.ts @@ -0,0 +1,33 @@ +import { expect, test, Locator, Page } from '@playwright/test'; + +export class LoginPage { + readonly page: Page; + readonly url: string; + readonly emailInput: Locator; + readonly passwordInput: Locator; + readonly submitBtn: Locator; + + constructor(page: Page) { + this.page = page; + this.url = './login'; + this.emailInput = page.locator('id=Email-input-field'); + this.passwordInput = page.locator('id=Passwort-input-field'); + this.submitBtn = page.locator('text=Anmeldung'); + } + + async goto() { + await this.page.goto(this.url); + } + + async enterEmail(email: string) { + await this.emailInput.fill(email); + } + + async enterPassword(password: string) { + await this.passwordInput.fill(password); + } + + async submitLogin() { + await this.submitBtn.click(); + } +} diff --git a/e2e-tests/playwright/tests/models/welcome_page.ts b/e2e-tests/playwright/tests/models/welcome_page.ts new file mode 100644 index 000000000..81d73a771 --- /dev/null +++ b/e2e-tests/playwright/tests/models/welcome_page.ts @@ -0,0 +1,13 @@ +import { expect, Locator, Page } from '@playwright/test'; + +export class WelcomePage { + readonly page: Page; + readonly url: string; + readonly profileLink: Locator; + + constructor(page: Page){ + this.page = page; + this.url = './overview'; + this.profileLink = page.locator('href=/profile'); + } +} diff --git a/e2e-tests/playwright/tests/playwright.config.ts b/e2e-tests/playwright/tests/playwright.config.ts new file mode 100644 index 000000000..073c34b06 --- /dev/null +++ b/e2e-tests/playwright/tests/playwright.config.ts @@ -0,0 +1,19 @@ +import type { PlaywrightTestConfig } from '@playwright/test'; + +const config: PlaywrightTestConfig = { + globalSetup: require.resolve('./global-setup'), + ignoreHTTPSErrors: true, + locale: 'de-DE', + reporter: process.env.CI ? 'github' : 'list', + retries: 1, + screenshot: 'only-on-failure', + testDir: '.', + timeout: 30000, + trace: 'on-first-retry', + video: 'never', + viewport: { width: 1280, height: 720 }, + use: { + baseURL: process.env.URL || 'http://localhost:3000', + }, +}; +export default config; From a65d680bdaf125f539982d203df2ac033b2eb5cf Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 11 Jul 2022 08:19:29 +0200 Subject: [PATCH 018/977] change form, ,maxlenght 255, add items for list --- .../Contributions/ContributionForm.vue | 40 ++++++------- frontend/src/locales/de.json | 3 +- frontend/src/locales/en.json | 3 +- frontend/src/pages/Community.vue | 60 ++++++++++++++++++- 4 files changed, 79 insertions(+), 27 deletions(-) diff --git a/frontend/src/components/Contributions/ContributionForm.vue b/frontend/src/components/Contributions/ContributionForm.vue index 9b4f9de1b..ac59959a1 100644 --- a/frontend/src/components/Contributions/ContributionForm.vue +++ b/frontend/src/components/Contributions/ContributionForm.vue @@ -1,15 +1,17 @@ From f79ff13183c946ff1f403749bb5a00d2bb1883f4 Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 11 Jul 2022 08:20:23 +0200 Subject: [PATCH 019/977] fix locales --- frontend/src/locales/de.json | 21 ++++++++++----------- frontend/src/locales/en.json | 20 ++++++++++---------- 2 files changed, 20 insertions(+), 21 deletions(-) diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index d8374a541..14e0d2300 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -27,15 +27,15 @@ "community": "Gemeinschaft", "continue-to-registration": "Weiter zur Registrierung", "current-community": "Aktuelle Gemeinschaft", + "myContributions": "Meine Beiträge", "other-communities": "Weitere Gemeinschaften", "switch-to-this-community": "zu dieser Gemeinschaft wechseln", - "writing":"Schreiben", - "myContributions":"Meine Beiträge" + "writing": "Schreiben" }, "contribution": { - "activity":"Tätigkeit", - "submit":"Einreichen", - "noDateSelected": "Kein Datum ausgewählt" + "activity": "Tätigkeit", + "noDateSelected": "Kein Datum ausgewählt", + "submit": "Einreichen" }, "contribution-link": { "thanksYouWith": "dankt dir mit" @@ -184,13 +184,12 @@ "login": "Anmeldung", "math": { "aprox": "~", + "divide": "/", "equal": "=", + "equalTo": "<", "exclaim": "!", "minus": "−", - "pipe": "|", - "divide": "/", - "equalTo":"<" - + "pipe": "|" }, "message": { "activateEmail": "Dein Konto wurde noch nicht aktiviert. Bitte überprüfe deine E-Mail und klicke den Aktivierungslink oder fordere einen neuen Aktivierungslink über die Password Reset Seite an.", @@ -204,14 +203,14 @@ }, "navigation": { "admin_area": "Adminbereich", + "community": "Gemeinschaft", "logout": "Abmelden", "members_area": "Mitgliederbereich", "overview": "Übersicht", "profile": "Mein Profil", "send": "Senden", "support": "Support", - "transactions": "Transaktionen", - "community":"Gemeinschaft" + "transactions": "Transaktionen" }, "qrCode": "QR Code", "send_gdd": "GDD versenden", diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index c10b62508..b06d141d3 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -27,15 +27,15 @@ "community": "Community", "continue-to-registration": "Continue to registration", "current-community": "Current community", + "myContributions": "My contributions", "other-communities": "Other communities", "switch-to-this-community": "Switch to this community", - "writing":"Writing", - "myContributions":"My contributions" + "writing": "Writing" }, "contribution": { - "activity":"Activity", - "submit":"Submit", - "noDateSelected": "No date selected" + "activity": "Activity", + "noDateSelected": "No date selected", + "submit": "Submit" }, "contribution-link": { "thanksYouWith": "thanks you with" @@ -184,12 +184,12 @@ "login": "Login", "math": { "aprox": "~", + "divide": "/", "equal": "=", + "equalTo": "<", "exclaim": "!", "minus": "−", - "pipe": "|", - "divide": "/", - "equalTo":"<" + "pipe": "|" }, "message": { "activateEmail": "Your account has not been activated yet. Please check your emails and click the activation link or order a new activation link over the password reset page.", @@ -203,14 +203,14 @@ }, "navigation": { "admin_area": "Admin Area", + "community": "Community", "logout": "Logout", "members_area": "Members area", "overview": "Overview", "profile": "My profile", "send": "Send", "support": "Support", - "transactions": "Transactions", - "community":"Community" + "transactions": "Transactions" }, "qrCode": "QR Code", "send_gdd": "GDD send", From 0c857417e5bda4581589bd11ce067c3dd9e06f92 Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 11 Jul 2022 08:27:45 +0200 Subject: [PATCH 020/977] fix test --- frontend/src/components/Menu/Sidebar.spec.js | 13 ++++++++----- frontend/src/routes/router.test.js | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/frontend/src/components/Menu/Sidebar.spec.js b/frontend/src/components/Menu/Sidebar.spec.js index fec7945c8..982192a8f 100644 --- a/frontend/src/components/Menu/Sidebar.spec.js +++ b/frontend/src/components/Menu/Sidebar.spec.js @@ -33,7 +33,7 @@ describe('Sidebar', () => { describe('navigation Navbar', () => { it('has seven b-nav-item in the navbar', () => { - expect(wrapper.findAll('.nav-item')).toHaveLength(7) + expect(wrapper.findAll('.nav-item')).toHaveLength(8) }) it('has first nav-item "navigation.overview" in navbar', () => { @@ -50,15 +50,18 @@ describe('Sidebar', () => { it('has first nav-item "navigation.profile" in navbar', () => { expect(wrapper.findAll('.nav-item').at(3).text()).toEqual('navigation.profile') }) + it('has a link to the community area', () => { + expect(wrapper.findAll('.nav-item').at(4).text()).toContain('navigation.community') + }) it('has a link to the members area', () => { - expect(wrapper.findAll('.nav-item').at(4).text()).toContain('navigation.members_area') - expect(wrapper.findAll('.nav-item').at(4).find('a').attributes('href')).toBe('#') + expect(wrapper.findAll('.nav-item').at(5).text()).toEqual('navigation.members_area') + expect(wrapper.findAll('.nav-item').at(5).find('a').attributes('href')).toBe('#') }) it('has first nav-item "navigation.admin_area" in navbar', () => { - expect(wrapper.findAll('.nav-item').at(5).text()).toEqual('navigation.admin_area') + expect(wrapper.findAll('.nav-item').at(6).text()).toEqual('navigation.admin_area') }) it('has first nav-item "navigation.logout" in navbar', () => { - expect(wrapper.findAll('.nav-item').at(6).text()).toEqual('navigation.logout') + expect(wrapper.findAll('.nav-item').at(7).text()).toEqual('navigation.logout') }) }) }) diff --git a/frontend/src/routes/router.test.js b/frontend/src/routes/router.test.js index 32ab90d4e..1edc6568b 100644 --- a/frontend/src/routes/router.test.js +++ b/frontend/src/routes/router.test.js @@ -50,7 +50,7 @@ describe('router', () => { }) it('has sixteen routes defined', () => { - expect(routes).toHaveLength(16) + expect(routes).toHaveLength(17) }) describe('overview', () => { From 4d622ee52cbaf065f6882359d5ceced1d32c0988 Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 11 Jul 2022 14:53:57 +0200 Subject: [PATCH 021/977] add test for Community.vue --- frontend/src/pages/Community.spec.js | 41 ++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 frontend/src/pages/Community.spec.js diff --git a/frontend/src/pages/Community.spec.js b/frontend/src/pages/Community.spec.js new file mode 100644 index 000000000..30bb2acda --- /dev/null +++ b/frontend/src/pages/Community.spec.js @@ -0,0 +1,41 @@ +import { mount } from '@vue/test-utils' +import Community from './Community' +// import { createContribution } from '@/graphql/mutations' + +// import { toastErrorSpy } from '@test/testSetup' + +const localVue = global.localVue + +const apolloMutationMock = jest.fn() +apolloMutationMock.mockResolvedValue('success') + +describe('Community', () => { + let wrapper + + const mocks = { + $t: jest.fn((t) => t), + $apollo: { + mutate: apolloMutationMock, + }, + $route: { + query: {}, + }, + } + + const Wrapper = () => { + return mount(Community, { + localVue, + mocks, + }) + } + + describe('mount', () => { + beforeEach(() => { + wrapper = Wrapper() + }) + + it('has a components community-page', () => { + expect(wrapper.find('div.community-page').exists()).toBe(true) + }) + }) +}) From 280f386a35be55150d17e262cfeeb92fbb454052 Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 11 Jul 2022 14:54:35 +0200 Subject: [PATCH 022/977] change text for fromular, change disable submit --- .../Contributions/ContributionForm.vue | 25 ++++++++++++++++--- frontend/src/locales/de.json | 9 ++++++- frontend/src/locales/en.json | 9 ++++++- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/frontend/src/components/Contributions/ContributionForm.vue b/frontend/src/components/Contributions/ContributionForm.vue index ac59959a1..67db69f5b 100644 --- a/frontend/src/components/Contributions/ContributionForm.vue +++ b/frontend/src/components/Contributions/ContributionForm.vue @@ -1,6 +1,18 @@ diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index 552b7f0a7..12ebc86b3 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -35,10 +35,10 @@ "activity": "Tätigkeit", "formText": { "h3": "Dein Beitrag zum Gemeinwohl", - "lastMonth": "Für Juni 2022 kannst du noch 200 GDD einreichen .", + "lastMonth": "Für {month} {year} kannst du noch {creation} GDD einreichen.", "text1": "Bring dich mit deinen Talenten in die Gemeinschaft ein! Dein freiwilliges Engagement honorieren wir mit 20 GDD pro Stunde bis maximal 1.000 GDD im Monat.", "text2": "Beschreibe deine Gemeinwohl-Tätigkeit mit Angabe der Stunden und trage einen Betrag von 20 GDD pro Stunde ein! Nach Bestätigung durch einen Moderator wird der Betrag deinem Konto gutgeschrieben.", - "thisMonth": "Für Juli 2022 kannst du noch 500 GDD einreichen. " + "thisMonth": "Für {month} {year} kannst du noch {creation} GDD einreichen. " }, "noDateSelected": "Kein Datum ausgewählt", "submit": "Einreichen" diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index a25d2da56..1ef7052d5 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -35,10 +35,10 @@ "activity": "Activity", "formText": { "h3": "Your contribution to the common good", - "lastMonth": "For June 2022, you can still submit 200 GDD.", + "lastMonth": "For {month} {year}, you can still submit {creation} GDD.", "text1": "Bring your talents to the community! Your voluntary commitment will be rewarded with 20 GDD per hour up to a maximum of 1,000 GDD per month.", "text2": "Describe your community service activity with hours and enter an amount of 20 GDD per hour! After confirmation by a moderator, the amount will be credited to your account.", - "thisMonth": "For July 2022, you can still submit 500 GDD." + "thisMonth": "For {month} {year}, you can still submit {creation} GDD." }, "noDateSelected": "No date selected", "submit": "Submit" From 910ba6bbdf7630c85db5c1d919ff89d92dc8d722 Mon Sep 17 00:00:00 2001 From: ogerly Date: Wed, 13 Jul 2022 08:54:28 +0200 Subject: [PATCH 038/977] moved from v-html to computed --- .../Contributions/ContributionForm.vue | 45 ++++++++++--------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/frontend/src/components/Contributions/ContributionForm.vue b/frontend/src/components/Contributions/ContributionForm.vue index edbaca6de..072f6c04d 100644 --- a/frontend/src/components/Contributions/ContributionForm.vue +++ b/frontend/src/components/Contributions/ContributionForm.vue @@ -4,8 +4,8 @@

{{ $t('contribution.formText.h3') }}

{{ $t('contribution.formText.text1') }}
    -
  • -
  • +
  • +
@@ -39,7 +39,6 @@ class="text-right" :class="form.memo.length < minlength ? 'text-danger' : 'text-success'" > - {{ form.memo.length }} {{ $t('math.equalTo') }} {{ minlength }} {{ $t('math.divide') }} {{ maxlength }}
@@ -65,10 +64,10 @@ From 6dd11a961ffbdaba903f3bb4eb6f253e5e768732 Mon Sep 17 00:00:00 2001 From: ogerly Date: Wed, 13 Jul 2022 09:04:14 +0200 Subject: [PATCH 039/977] resolve merge conflict for ContributionResolver.ts 2 --- backend/src/graphql/resolver/ContributionResolver.ts | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index bfce1ba03..4424b40d0 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -3,7 +3,6 @@ import { Context, getUser } from '@/server/context' import { backendLogger as logger } from '@/server/logger' import { Contribution as dbContribution } from '@entity/Contribution' import { Arg, Args, Authorized, Ctx, Mutation, Query, Resolver } from 'type-graphql' -<<<<<<< HEAD import { FindOperator, IsNull } from '@dbTools/typeorm' import ContributionArgs from '@arg/ContributionArgs' import Paginated from '@arg/Paginated' @@ -11,15 +10,6 @@ import { Order } from '@enum/Order' import { Contribution } from '@model/Contribution' import { UnconfirmedContribution } from '@model/UnconfirmedContribution' import { User } from '@model/User' -======= -import { IsNull, Not } from '../../../../database/node_modules/typeorm' -import ContributionArgs from '../arg/ContributionArgs' -import Paginated from '../arg/Paginated' -import { Order } from '../enum/Order' -import { Contribution } from '../model/Contribution' -import { UnconfirmedContribution } from '../model/UnconfirmedContribution' -import { User } from '../model/User' ->>>>>>> 193c7927e (resolve conflict) import { validateContribution, getUserCreation } from './util/creations' @Resolver() From b0df5996e0f8f4029a23120855bf04656d357eac Mon Sep 17 00:00:00 2001 From: ogerly Date: Wed, 13 Jul 2022 11:06:29 +0200 Subject: [PATCH 040/977] change computed lastMonthObject --- .../Contributions/ContributionForm.vue | 14 +---- frontend/src/graphql/queries.js | 22 +++++++ frontend/src/pages/Community.vue | 57 ++++++++++--------- 3 files changed, 56 insertions(+), 37 deletions(-) diff --git a/frontend/src/components/Contributions/ContributionForm.vue b/frontend/src/components/Contributions/ContributionForm.vue index 072f6c04d..5eae4718f 100644 --- a/frontend/src/components/Contributions/ContributionForm.vue +++ b/frontend/src/components/Contributions/ContributionForm.vue @@ -57,7 +57,6 @@ {{ $t('contribution.submit') }} - {{ form }} @@ -102,19 +101,12 @@ export default { return false }, lastMonthObject() { - let obj = { - month: new Date(this.lastMonth).toLocaleString(this.$i18n.locale, { month: 'long' }), - year: new Date().getFullYear(), - creation: this.$store.state.creation[1], - } - // If the current month is January then the current year must be counted back by -1. - if (new Date().getMonth === 1) { - obj = { + // new Date().getMonth === 1 If the current month is January, then one year must be gone back in the previous month + const obj = { month: new Date(this.lastMonth).toLocaleString(this.$i18n.locale, { month: 'long' }), - year: new Date().getFullYear() - 1, + year: new Date().getMonth === 1 ? new Date().getFullYear() - 1 : new Date().getFullYear(), creation: this.$store.state.creation[1], } - } return this.$t('contribution.formText.lastMonth', obj) }, thisMonthObject() { diff --git a/frontend/src/graphql/queries.js b/frontend/src/graphql/queries.js index 27e63d568..a25c4b4f4 100644 --- a/frontend/src/graphql/queries.js +++ b/frontend/src/graphql/queries.js @@ -162,3 +162,25 @@ export const listTransactionLinks = gql` } } ` + +export const listContributions = gql` + query( + $currentPage: Int = 1 + $pageSize: Int = 25 + $order: Order = DESC + $filterConfirmed: Boolean = false + ) { + listContributions( + currentPage: $currentPage + pageSize: $pageSize + order: $order + filterConfirmed: $filterConfirmed + ) { + id + amount + memo + createdAt + deletedAt + } + } +` diff --git a/frontend/src/pages/Community.vue b/frontend/src/pages/Community.vue index 0559ea3e8..dc7c22aa0 100644 --- a/frontend/src/pages/Community.vue +++ b/frontend/src/pages/Community.vue @@ -20,6 +20,7 @@ import ContributionForm from '@/components/Contributions/ContributionForm.vue' import ContributionList from '@/components/Contributions/ContributionList.vue' import { createContribution } from '@/graphql/mutations' +import { listContributions } from '@/graphql/queries' export default { name: 'Community', @@ -29,39 +30,18 @@ export default { }, data() { return { - items: [ - { - id: '0', - date: '07/06/2022', - memo: 'Ich habe 10 Stunden die Elbwiesen von Müll befreit.', - amount: 200, - status: 'pending', - }, - { - id: '1', - date: '06/22/2022', - memo: 'Ich habe 30 Stunden Frau Müller beim EInkaufen und im Haushalt geholfen.', - amount: 600, - status: 'pending', - }, - { - id: '2', - date: '05/04/2022', - memo: - 'Ich habe 50 Stunden den Nachbarkindern bei ihren Hausaufgaben geholfen und Nachhilfeunterricht gegeben.', - amount: 1000, - status: 'pending', - }, - ], + currentPage: 1, + pageSize: 25, + items: [], } }, methods: { setContribution(data) { // console.log('setContribution', data) this.$apollo - .query({ + .mutate({ fetchPolicy: 'no-cache', - query: createContribution, + mutation: createContribution, variables: { creationDate: data.date, memo: data.memo, @@ -76,6 +56,31 @@ export default { this.toastError(err.message) }) }, + getListContributions(data) { + this.$apollo + .query({ + fetchPolicy: 'no-cache', + query: listContributions, + variables: { + currentPage: this.currentPage, + pageSize: this.pageSize, + }, + }) + .then((result) => { + console.log('result', result.data) + const { + data: { listContributions }, + } = result + this.items = listContributions + // this.toastSuccess(result.data) + }) + .catch((err) => { + this.toastError(err.message) + }) + }, + }, + created() { + this.getListContributions() }, } From 802a629d2684d03647f1dd80b01cd9585a07fa2a Mon Sep 17 00:00:00 2001 From: ogerly Date: Wed, 13 Jul 2022 11:12:33 +0200 Subject: [PATCH 041/977] remove console statement --- .../src/components/Contributions/ContributionForm.vue | 10 +++++----- frontend/src/pages/Community.vue | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/frontend/src/components/Contributions/ContributionForm.vue b/frontend/src/components/Contributions/ContributionForm.vue index 5eae4718f..a788e1563 100644 --- a/frontend/src/components/Contributions/ContributionForm.vue +++ b/frontend/src/components/Contributions/ContributionForm.vue @@ -101,12 +101,12 @@ export default { return false }, lastMonthObject() { - // new Date().getMonth === 1 If the current month is January, then one year must be gone back in the previous month + // new Date().getMonth === 1 If the current month is January, then one year must be gone back in the previous month const obj = { - month: new Date(this.lastMonth).toLocaleString(this.$i18n.locale, { month: 'long' }), - year: new Date().getMonth === 1 ? new Date().getFullYear() - 1 : new Date().getFullYear(), - creation: this.$store.state.creation[1], - } + month: new Date(this.lastMonth).toLocaleString(this.$i18n.locale, { month: 'long' }), + year: new Date().getMonth === 1 ? new Date().getFullYear() - 1 : new Date().getFullYear(), + creation: this.$store.state.creation[1], + } return this.$t('contribution.formText.lastMonth', obj) }, thisMonthObject() { diff --git a/frontend/src/pages/Community.vue b/frontend/src/pages/Community.vue index dc7c22aa0..c639ec969 100644 --- a/frontend/src/pages/Community.vue +++ b/frontend/src/pages/Community.vue @@ -67,7 +67,7 @@ export default { }, }) .then((result) => { - console.log('result', result.data) + // console.log('result', result.data) const { data: { listContributions }, } = result From ffe8831d090557efd107e4499cfa29ec6b2567af Mon Sep 17 00:00:00 2001 From: ogerly Date: Wed, 13 Jul 2022 11:28:35 +0200 Subject: [PATCH 042/977] change listContributions query add confirmedBy and confirmedAt --- frontend/src/graphql/queries.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/frontend/src/graphql/queries.js b/frontend/src/graphql/queries.js index a25c4b4f4..a523d18a1 100644 --- a/frontend/src/graphql/queries.js +++ b/frontend/src/graphql/queries.js @@ -181,6 +181,8 @@ export const listContributions = gql` memo createdAt deletedAt + confirmedBy + confirmedAt } } ` From eb404cf8b3e0d106f18a12883a00bccb4e9dfc57 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Wed, 13 Jul 2022 14:30:46 +0200 Subject: [PATCH 043/977] add migrations to insert contributions to all transactions with type creation that do not have a contribution yet --- .../0043-insert_missing_contributions.ts | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 database/migrations/0043-insert_missing_contributions.ts diff --git a/database/migrations/0043-insert_missing_contributions.ts b/database/migrations/0043-insert_missing_contributions.ts new file mode 100644 index 000000000..a14141498 --- /dev/null +++ b/database/migrations/0043-insert_missing_contributions.ts @@ -0,0 +1,34 @@ +/* MIGRATION TO INSERT contributions for all transactions with type creation that do not have a contribution yet */ + +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +export async function upgrade(queryFn: (query: string, values?: any[]) => Promise>) { + await queryFn( + `INSERT INTO gradido_community.contributions + (user_id, created_at, contribution_date, memo, amount, moderator_id, confirmed_by, confirmed_at, transaction_id) +SELECT + user_id, + balance_date, + creation_date AS contribution_date, + memo, + amount, + 20 AS moderator_id, + 502 AS confirmed_by, + balance_date AS confirmed_at, + id +FROM + gradido_community.transactions +WHERE + type_id = 1 + AND NOT EXISTS( + SELECT * FROM gradido_community.contributions + WHERE gradido_community.contributions.transaction_id = gradido_community.transactions.id);`, + ) +} + +export async function downgrade(queryFn: (query: string, values?: any[]) => Promise>) { + await queryFn( + 'DELETE FROM `contributions` WHERE `contributions`.`moderator_id` = 20 AND `contributions`.`confirmed_by` = 502 AND `contributions`.`created_at` = `contributions`.`confirmed_at`;', + ) +} From bdcbb196b77fc16cd165e898c7d54bf9b5aef6f1 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Wed, 13 Jul 2022 14:31:31 +0200 Subject: [PATCH 044/977] update database version --- backend/src/config/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index 8b84c059d..208425792 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -10,7 +10,7 @@ Decimal.set({ }) const constants = { - DB_VERSION: '0042-update_transactions_for_blockchain', + DB_VERSION: '0043-insert_missing_contributions', DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0 LOG4JS_CONFIG: 'log4js-config.json', // default log level on production should be info From 84706e430b0d6fda8f818e18e512f5126b10ea57 Mon Sep 17 00:00:00 2001 From: ogerly Date: Thu, 14 Jul 2022 11:50:17 +0200 Subject: [PATCH 045/977] add slot ContributionListItem.vue, add verifyLogin, update store for creation --- .../Contributions/ContributionForm.vue | 1 + .../Contributions/ContributionList.vue | 52 ++++++++++++- .../Contributions/ContributionListItem.vue | 73 +++++++++++++++++++ frontend/src/pages/Community.vue | 51 ++++++++++--- 4 files changed, 164 insertions(+), 13 deletions(-) create mode 100644 frontend/src/components/Contributions/ContributionListItem.vue diff --git a/frontend/src/components/Contributions/ContributionForm.vue b/frontend/src/components/Contributions/ContributionForm.vue index a788e1563..20d7ff921 100644 --- a/frontend/src/components/Contributions/ContributionForm.vue +++ b/frontend/src/components/Contributions/ContributionForm.vue @@ -57,6 +57,7 @@ {{ $t('contribution.submit') }} + {{ $store.state }} diff --git a/frontend/src/components/Contributions/ContributionList.vue b/frontend/src/components/Contributions/ContributionList.vue index e3dc41b5f..e7fc930e6 100644 --- a/frontend/src/components/Contributions/ContributionList.vue +++ b/frontend/src/components/Contributions/ContributionList.vue @@ -1,17 +1,65 @@ diff --git a/frontend/src/components/Contributions/ContributionListItem.vue b/frontend/src/components/Contributions/ContributionListItem.vue new file mode 100644 index 000000000..11cb2266e --- /dev/null +++ b/frontend/src/components/Contributions/ContributionListItem.vue @@ -0,0 +1,73 @@ + + diff --git a/frontend/src/pages/Community.vue b/frontend/src/pages/Community.vue index c639ec969..6db97b5a0 100644 --- a/frontend/src/pages/Community.vue +++ b/frontend/src/pages/Community.vue @@ -6,12 +6,15 @@ - - - - - + + @@ -20,7 +23,7 @@ import ContributionForm from '@/components/Contributions/ContributionForm.vue' import ContributionList from '@/components/Contributions/ContributionList.vue' import { createContribution } from '@/graphql/mutations' -import { listContributions } from '@/graphql/queries' +import { listContributions, verifyLogin } from '@/graphql/queries' export default { name: 'Community', @@ -30,9 +33,10 @@ export default { }, data() { return { + items: [], currentPage: 1, pageSize: 25, - items: [], + contributionCount: 0, } }, methods: { @@ -51,19 +55,24 @@ export default { .then((result) => { // console.log('result', result.data) this.toastSuccess(result.data) + this.updateListContributions({ + currentPage: this.currentPage, + pageSize: this.pageSize, + }) + this.verifyLogin() }) .catch((err) => { this.toastError(err.message) }) }, - getListContributions(data) { + async updateListContributions(pagination) { this.$apollo .query({ fetchPolicy: 'no-cache', query: listContributions, variables: { - currentPage: this.currentPage, - pageSize: this.pageSize, + currentPage: pagination.currentPage, + pageSize: pagination.pageSize, }, }) .then((result) => { @@ -71,6 +80,7 @@ export default { const { data: { listContributions }, } = result + this.contributionCount = listContributions.length this.items = listContributions // this.toastSuccess(result.data) }) @@ -78,9 +88,28 @@ export default { this.toastError(err.message) }) }, + verifyLogin() { + this.$apollo + .query({ + query: verifyLogin, + fetchPolicy: 'network-only', + }) + .then((result) => { + const { + data: { verifyLogin }, + } = result + this.$store.dispatch('login', verifyLogin) + }) + .catch(() => { + this.$emit('logout') + }) + }, }, created() { - this.getListContributions() + this.updateListContributions({ + currentPage: this.currentPage, + pageSize: this.pageSize, + }) }, } From af0f434d011171ec08c464db8c354624b0ab9d14 Mon Sep 17 00:00:00 2001 From: ogerly Date: Thu, 14 Jul 2022 15:22:38 +0200 Subject: [PATCH 046/977] add updateContribution --- .../Contributions/ContributionForm.vue | 26 ++++++++++++++----- .../Contributions/ContributionList.vue | 5 +++- .../Contributions/ContributionListItem.vue | 21 ++++++++++++--- frontend/src/pages/Community.vue | 18 +++++++++++-- 4 files changed, 56 insertions(+), 14 deletions(-) diff --git a/frontend/src/components/Contributions/ContributionForm.vue b/frontend/src/components/Contributions/ContributionForm.vue index 20d7ff921..ff74786d6 100644 --- a/frontend/src/components/Contributions/ContributionForm.vue +++ b/frontend/src/components/Contributions/ContributionForm.vue @@ -16,7 +16,7 @@ {{ $t('contribution.activity') }} {{ $t('contribution.submit') }} - {{ $store.state }} + {{date}}, {{amount}}, {{ memo}} @@ -70,6 +70,12 @@ */ export default { name: 'ContributionForm', + props: { + id: { type: Number, required: false}, + date: { type: String, required: true}, + memo: { type: String, required: true}, + amount: { type: String, required: true}, + }, data() { return { minlength: 50, @@ -78,9 +84,9 @@ export default { min: new Date(new Date(new Date().setMonth(new Date().getMonth() - 1)).setDate(1)), max: new Date(), form: { - date: '', - memo: '', - amount: 0, + date: this.date, + memo: this.memo, + amount: this.amount, }, } }, @@ -119,5 +125,11 @@ export default { return this.$t('contribution.formText.thisMonth', obj) }, }, + watch: { + id(newId, oldId){ + console.log('eine id kommt mit') + } + + } } diff --git a/frontend/src/components/Contributions/ContributionList.vue b/frontend/src/components/Contributions/ContributionList.vue index e7fc930e6..c08d22c79 100644 --- a/frontend/src/components/Contributions/ContributionList.vue +++ b/frontend/src/components/Contributions/ContributionList.vue @@ -2,7 +2,7 @@
{{ items.length }}
- +
{{ $d(new Date(date), 'short') }}
{{ memo }}
-
+
-
- -
@@ -69,5 +77,10 @@ export default { return this.createdAt }, }, + methods: { + updateContribution(item) { + this.$emit('update-contribution', item) + }, + }, } diff --git a/frontend/src/pages/Community.vue b/frontend/src/pages/Community.vue index 6db97b5a0..b5907aefa 100644 --- a/frontend/src/pages/Community.vue +++ b/frontend/src/pages/Community.vue @@ -1,14 +1,15 @@ From c170c48ac4bb41b4e2f8e1621fbf1f348a00547a Mon Sep 17 00:00:00 2001 From: ogerly Date: Fri, 15 Jul 2022 10:11:07 +0200 Subject: [PATCH 052/977] change for tests --- .../Contributions/ContributionForm.spec.js | 6 ++++++ .../Contributions/ContributionList.spec.js | 19 ++++++++++--------- frontend/src/components/Menu/Sidebar.spec.js | 8 ++++---- frontend/src/pages/Community.spec.js | 8 +++++--- frontend/src/pages/Community.vue | 4 ++++ 5 files changed, 29 insertions(+), 16 deletions(-) diff --git a/frontend/src/components/Contributions/ContributionForm.spec.js b/frontend/src/components/Contributions/ContributionForm.spec.js index 4d39e2942..633d0e1ae 100644 --- a/frontend/src/components/Contributions/ContributionForm.spec.js +++ b/frontend/src/components/Contributions/ContributionForm.spec.js @@ -8,6 +8,12 @@ describe('ContributionForm', () => { const mocks = { $t: jest.fn((t) => t), + $d: jest.fn((d) => d), + $store: { + state: { + creation: ["1000","1000","1000"], + }, + }, } const Wrapper = () => { diff --git a/frontend/src/components/Contributions/ContributionList.spec.js b/frontend/src/components/Contributions/ContributionList.spec.js index 7accfcad9..ba6e15786 100644 --- a/frontend/src/components/Contributions/ContributionList.spec.js +++ b/frontend/src/components/Contributions/ContributionList.spec.js @@ -8,31 +8,32 @@ describe('ContributionList', () => { const mocks = { $t: jest.fn((t) => t), + $d: jest.fn((d) => d), } const propsData = { + contributionCount: 3, + showPagination: true, + pageSize: 25, items: [ { - id: '0', + id: 0, date: '07/06/2022', memo: 'Ich habe 10 Stunden die Elbwiesen von Müll befreit.', - amount: 200, - status: 'pending', + amount: '200', }, { - id: '1', + id: 1, date: '06/22/2022', memo: 'Ich habe 30 Stunden Frau Müller beim EInkaufen und im Haushalt geholfen.', - amount: 600, - status: 'pending', + amount: '600', }, { - id: '2', + id: 2, date: '05/04/2022', memo: 'Ich habe 50 Stunden den Nachbarkindern bei ihren Hausaufgaben geholfen und Nachhilfeunterricht gegeben.', - amount: 1000, - status: 'pending', + amount: '1000', }, ], } diff --git a/frontend/src/components/Menu/Sidebar.spec.js b/frontend/src/components/Menu/Sidebar.spec.js index 982192a8f..afee93def 100644 --- a/frontend/src/components/Menu/Sidebar.spec.js +++ b/frontend/src/components/Menu/Sidebar.spec.js @@ -47,11 +47,11 @@ describe('Sidebar', () => { it('has first nav-item "navigation.transactions" in navbar', () => { expect(wrapper.findAll('.nav-item').at(2).text()).toEqual('navigation.transactions') }) - it('has first nav-item "navigation.profile" in navbar', () => { - expect(wrapper.findAll('.nav-item').at(3).text()).toEqual('navigation.profile') - }) it('has a link to the community area', () => { - expect(wrapper.findAll('.nav-item').at(4).text()).toContain('navigation.community') + expect(wrapper.findAll('.nav-item').at(3).text()).toContain('navigation.community') + }) + it('has first nav-item "navigation.profile" in navbar', () => { + expect(wrapper.findAll('.nav-item').at(4).text()).toEqual('navigation.profile') }) it('has a link to the members area', () => { expect(wrapper.findAll('.nav-item').at(5).text()).toEqual('navigation.members_area') diff --git a/frontend/src/pages/Community.spec.js b/frontend/src/pages/Community.spec.js index 7f1540369..a90f035ee 100644 --- a/frontend/src/pages/Community.spec.js +++ b/frontend/src/pages/Community.spec.js @@ -1,11 +1,9 @@ import { mount } from '@vue/test-utils' import Community from './Community' -// import { createContribution } from '@/graphql/mutations' - -// import { toastErrorSpy } from '@test/testSetup' const localVue = global.localVue +const mockStoreDispach = jest.fn() const apolloMutationMock = jest.fn() apolloMutationMock.mockResolvedValue('success') @@ -14,9 +12,13 @@ describe('Community', () => { const mocks = { $t: jest.fn((t) => t), + $d: jest.fn((d) => d), $apollo: { mutate: apolloMutationMock, }, + $store: { + dispatch: mockStoreDispach, + }, } const Wrapper = () => { diff --git a/frontend/src/pages/Community.vue b/frontend/src/pages/Community.vue index 4774fc3c0..ddf4333bf 100644 --- a/frontend/src/pages/Community.vue +++ b/frontend/src/pages/Community.vue @@ -118,12 +118,16 @@ export default { this.form.memo = item.memo this.form.amount = item.amount }, + updateTransactions(pagination) { + this.$emit('update-transactions', pagination) + }, }, created() { this.updateListContributions({ currentPage: this.currentPage, pageSize: this.pageSize, }) + this.updateTransactions(0) }, } From 9efb83b2afe953d9e3b63811a65ec500b48de991 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Fri, 15 Jul 2022 11:01:36 +0200 Subject: [PATCH 053/977] fix tests --- .../Contributions/ContributionForm.spec.js | 2 +- .../Contributions/ContributionListItem.vue | 16 +++++++------- frontend/src/pages/Community.spec.js | 21 ++++++++++++++++++- frontend/src/pages/Community.vue | 2 +- 4 files changed, 30 insertions(+), 11 deletions(-) diff --git a/frontend/src/components/Contributions/ContributionForm.spec.js b/frontend/src/components/Contributions/ContributionForm.spec.js index 633d0e1ae..44fa170b1 100644 --- a/frontend/src/components/Contributions/ContributionForm.spec.js +++ b/frontend/src/components/Contributions/ContributionForm.spec.js @@ -11,7 +11,7 @@ describe('ContributionForm', () => { $d: jest.fn((d) => d), $store: { state: { - creation: ["1000","1000","1000"], + creation: ['1000', '1000', '1000'], }, }, } diff --git a/frontend/src/components/Contributions/ContributionListItem.vue b/frontend/src/components/Contributions/ContributionListItem.vue index 499c23e63..cbc986326 100644 --- a/frontend/src/components/Contributions/ContributionListItem.vue +++ b/frontend/src/components/Contributions/ContributionListItem.vue @@ -57,23 +57,23 @@ export default { }, computed: { type() { - if (this.deletedAt !== null) return 'deleted' - if (this.confirmedAt !== null) return 'confirmed' + if (this.deletedAt) return 'deleted' + if (this.confirmedAt) return 'confirmed' return 'pending' }, icon() { - if (this.deletedAt !== null) return 'x-circle' - if (this.confirmedAt !== null) return 'check' + if (this.deletedAt) return 'x-circle' + if (this.confirmedAt) return 'check' return 'bell-fill' }, variant() { - if (this.deletedAt !== null) return 'danger' - if (this.confirmedAt !== null) return 'success' + if (this.deletedAt) return 'danger' + if (this.confirmedAt) return 'success' return 'primary' }, date() { - if (this.deletedAt !== null) return this.deletedAt - if (this.confirmedAt !== null) return this.confirmedAt + if (this.deletedAt) return this.deletedAt + if (this.confirmedAt) return this.confirmedAt return this.createdAt }, }, diff --git a/frontend/src/pages/Community.spec.js b/frontend/src/pages/Community.spec.js index a90f035ee..efb96cc67 100644 --- a/frontend/src/pages/Community.spec.js +++ b/frontend/src/pages/Community.spec.js @@ -4,8 +4,23 @@ import Community from './Community' const localVue = global.localVue const mockStoreDispach = jest.fn() +const apolloQueryMock = jest.fn() const apolloMutationMock = jest.fn() -apolloMutationMock.mockResolvedValue('success') +apolloQueryMock.mockResolvedValue({ + data: { + listContributions: [ + { + id: 1555, + amount: '200', + memo: 'Fleisig, fleisig am Arbeiten mein Lieber Freund, 50 Zeichen sind viel', + createdAt: '2022-07-15T08:47:06.000Z', + deletedAt: null, + confirmedBy: null, + confirmedAt: null, + }, + ], + }, +}) describe('Community', () => { let wrapper @@ -14,10 +29,14 @@ describe('Community', () => { $t: jest.fn((t) => t), $d: jest.fn((d) => d), $apollo: { + query: apolloQueryMock, mutate: apolloMutationMock, }, $store: { dispatch: mockStoreDispach, + state: { + creation: ['1000', '1000', '1000'], + }, }, } diff --git a/frontend/src/pages/Community.vue b/frontend/src/pages/Community.vue index ddf4333bf..42102a005 100644 --- a/frontend/src/pages/Community.vue +++ b/frontend/src/pages/Community.vue @@ -73,7 +73,7 @@ export default { this.toastError(err.message) }) }, - async updateListContributions(pagination) { + updateListContributions(pagination) { this.$apollo .query({ fetchPolicy: 'no-cache', From 66f10df1d0d656758213eb83ed89b263c77e2ff7 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Fri, 15 Jul 2022 11:23:03 +0200 Subject: [PATCH 054/977] improve logic and date handling. use v-model for form --- .../Contributions/ContributionForm.vue | 21 ++++--------------- frontend/src/pages/Community.vue | 5 +++-- 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/frontend/src/components/Contributions/ContributionForm.vue b/frontend/src/components/Contributions/ContributionForm.vue index 1a43e87ef..777806c30 100644 --- a/frontend/src/components/Contributions/ContributionForm.vue +++ b/frontend/src/components/Contributions/ContributionForm.vue @@ -12,7 +12,6 @@ {{ $t('contribution.formText.text2') }} - {{ id }} diff --git a/frontend/src/pages/Community.vue b/frontend/src/pages/Community.vue index 42102a005..ee2cc0aff 100644 --- a/frontend/src/pages/Community.vue +++ b/frontend/src/pages/Community.vue @@ -3,7 +3,7 @@
- + Date: Fri, 15 Jul 2022 14:20:24 +0200 Subject: [PATCH 055/977] fix typo in POM file --- e2e-tests/cypress/tests/cypress/e2e/models/LoginPage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-tests/cypress/tests/cypress/e2e/models/LoginPage.js b/e2e-tests/cypress/tests/cypress/e2e/models/LoginPage.js index 6a0245aa2..38933942f 100644 --- a/e2e-tests/cypress/tests/cypress/e2e/models/LoginPage.js +++ b/e2e-tests/cypress/tests/cypress/e2e/models/LoginPage.js @@ -9,7 +9,7 @@ class LoginPage { } enterPassword(password) { - cy.get('[id=Passwors-input-field]').clear().type(password) + cy.get('[id=Password-input-field]').clear().type(password) return this } From d419462b7b4d916d9b72a5833cf949e393e3aa3a Mon Sep 17 00:00:00 2001 From: mahula Date: Fri, 15 Jul 2022 14:29:18 +0200 Subject: [PATCH 056/977] use yarn instead of npm with cypress tests --- e2e-tests/cypress/README.md | 2 +- e2e-tests/cypress/tests/package.json | 17 + e2e-tests/cypress/tests/yarn.lock | 1126 ++++++++++++++++++++++++++ 3 files changed, 1144 insertions(+), 1 deletion(-) create mode 100644 e2e-tests/cypress/tests/package.json create mode 100644 e2e-tests/cypress/tests/yarn.lock diff --git a/e2e-tests/cypress/README.md b/e2e-tests/cypress/README.md index 5cadedff4..69c1d7642 100644 --- a/e2e-tests/cypress/README.md +++ b/e2e-tests/cypress/README.md @@ -22,5 +22,5 @@ cd e2e-tests/cypress docker build -t gradido_e2e-tests-cypress . # run the Docker container and execute the given tests -docker run -it gradido_e2e-tests-cypress cypress run +docker run -it gradido_e2e-tests-cypress yarn run cypress-e2e-tests ``` diff --git a/e2e-tests/cypress/tests/package.json b/e2e-tests/cypress/tests/package.json new file mode 100644 index 000000000..c311cf407 --- /dev/null +++ b/e2e-tests/cypress/tests/package.json @@ -0,0 +1,17 @@ +{ + "name": "gradido-e2e-tests-cypress", + "version": "1.0.0", + "description": "End-to-end tests with Cypress", + "main": "yarn run cypress run", + "repository": "https://github.com/gradido/gradido/e2e-tests/cypress", + "author": "Mathias Lenz", + "license": "Apache-2.0", + "private": false, + "scripts": { + "cypress-e2e-tests": "yarn run cypress run", + "lint": "eslint --max-warnings=0 --ext .js,.ts ." + }, + "dependencies": { + "cypress": "^10.3.0" + } +} diff --git a/e2e-tests/cypress/tests/yarn.lock b/e2e-tests/cypress/tests/yarn.lock new file mode 100644 index 000000000..e106a617f --- /dev/null +++ b/e2e-tests/cypress/tests/yarn.lock @@ -0,0 +1,1126 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@colors/colors@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" + integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== + +"@cypress/request@^2.88.10": + version "2.88.10" + resolved "https://registry.yarnpkg.com/@cypress/request/-/request-2.88.10.tgz#b66d76b07f860d3a4b8d7a0604d020c662752cce" + integrity sha512-Zp7F+R93N0yZyG34GutyTNr+okam7s/Fzc1+i3kcqOP8vk6OuajuE9qZJ6Rs+10/1JFtXFYMdyarnU1rZuJesg== + dependencies: + aws-sign2 "~0.7.0" + aws4 "^1.8.0" + caseless "~0.12.0" + combined-stream "~1.0.6" + extend "~3.0.2" + forever-agent "~0.6.1" + form-data "~2.3.2" + http-signature "~1.3.6" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.19" + performance-now "^2.1.0" + qs "~6.5.2" + safe-buffer "^5.1.2" + tough-cookie "~2.5.0" + tunnel-agent "^0.6.0" + uuid "^8.3.2" + +"@cypress/xvfb@^1.2.4": + version "1.2.4" + resolved "https://registry.yarnpkg.com/@cypress/xvfb/-/xvfb-1.2.4.tgz#2daf42e8275b39f4aa53c14214e557bd14e7748a" + integrity sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q== + dependencies: + debug "^3.1.0" + lodash.once "^4.1.1" + +"@types/node@*": + version "18.0.4" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.0.4.tgz#48aedbf35efb3af1248e4cd4d792c730290cd5d6" + integrity sha512-M0+G6V0Y4YV8cqzHssZpaNCqvYwlCiulmm0PwpNLF55r/+cT8Ol42CHRU1SEaYFH2rTwiiE1aYg/2g2rrtGdPA== + +"@types/node@^14.14.31": + version "14.18.22" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.22.tgz#fd2a15dca290fc9ad565b672fde746191cd0c6e6" + integrity sha512-qzaYbXVzin6EPjghf/hTdIbnVW1ErMx8rPzwRNJhlbyJhu2SyqlvjGOY/tbUt6VFyzg56lROcOeSQRInpt63Yw== + +"@types/sinonjs__fake-timers@8.1.1": + version "8.1.1" + resolved "https://registry.yarnpkg.com/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz#b49c2c70150141a15e0fa7e79cf1f92a72934ce3" + integrity sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g== + +"@types/sizzle@^2.3.2": + version "2.3.3" + resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.3.tgz#ff5e2f1902969d305225a047c8a0fd5c915cebef" + integrity sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ== + +"@types/yauzl@^2.9.1": + version "2.10.0" + resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.10.0.tgz#b3248295276cf8c6f153ebe6a9aba0c988cb2599" + integrity sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw== + dependencies: + "@types/node" "*" + +aggregate-error@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + +ansi-colors@^4.1.1: + version "4.1.3" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" + integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== + +ansi-escapes@^4.3.0: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +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" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +arch@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11" + integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ== + +asn1@~0.2.3: + version "0.2.6" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" + integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== + dependencies: + safer-buffer "~2.1.0" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw== + +astral-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" + integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== + +async@^3.2.0: + version "3.2.4" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c" + integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ== + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +at-least-node@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" + integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== + +aws-sign2@~0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + integrity sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA== + +aws4@^1.8.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59" + integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base64-js@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +bcrypt-pbkdf@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + integrity sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w== + dependencies: + tweetnacl "^0.14.3" + +blob-util@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/blob-util/-/blob-util-2.0.2.tgz#3b4e3c281111bb7f11128518006cdc60b403a1eb" + integrity sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ== + +bluebird@^3.7.2: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +buffer-crc32@~0.2.3: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== + +buffer@^5.6.0: + version "5.7.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.1.13" + +cachedir@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/cachedir/-/cachedir-2.3.0.tgz#0c75892a052198f0b21c7c1804d8331edfcae0e8" + integrity sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw== + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw== + +chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +check-more-types@^2.24.0: + version "2.24.0" + resolved "https://registry.yarnpkg.com/check-more-types/-/check-more-types-2.24.0.tgz#1420ffb10fd444dcfc79b43891bbfffd32a84600" + integrity sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA== + +ci-info@^3.2.0: + version "3.3.2" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.2.tgz#6d2967ffa407466481c6c90b6e16b3098f080128" + integrity sha512-xmDt/QIAdeZ9+nfdPsaBCpMvHNLFiLdjj59qjqn+6iPe6YmHGQ35sBnQ8uslRBXFmXkiZQOJRjvQeoGppoTjjg== + +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== + +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + +cli-table3@~0.6.1: + version "0.6.2" + resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.2.tgz#aaf5df9d8b5bf12634dc8b3040806a0c07120d2a" + integrity sha512-QyavHCaIC80cMivimWu4aWHilIpiDpfm3hGmqAmXVL1UsnbLuBSMd21hTX6VY4ZSDSM73ESLeF8TOYId3rBTbw== + dependencies: + string-width "^4.2.0" + optionalDependencies: + "@colors/colors" "1.5.0" + +cli-truncate@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7" + integrity sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg== + dependencies: + slice-ansi "^3.0.0" + string-width "^4.2.0" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +colorette@^2.0.16: + version "2.0.19" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798" + integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ== + +combined-stream@^1.0.6, combined-stream@~1.0.6: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + +commander@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" + integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== + +common-tags@^1.8.0: + version "1.8.2" + resolved "https://registry.yarnpkg.com/common-tags/-/common-tags-1.8.2.tgz#94ebb3c076d26032745fd54face7f688ef5ac9c6" + integrity sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +core-util-is@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ== + +cross-spawn@^7.0.0: + version "7.0.3" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +cypress@10.3.0: + version "10.3.0" + resolved "https://registry.yarnpkg.com/cypress/-/cypress-10.3.0.tgz#fae8d32f0822fcfb938e79c7c31ef344794336ae" + integrity sha512-txkQWKzvBVnWdCuKs5Xc08gjpO89W2Dom2wpZgT9zWZT5jXxqPIxqP/NC1YArtkpmp3fN5HW8aDjYBizHLUFvg== + dependencies: + "@cypress/request" "^2.88.10" + "@cypress/xvfb" "^1.2.4" + "@types/node" "^14.14.31" + "@types/sinonjs__fake-timers" "8.1.1" + "@types/sizzle" "^2.3.2" + arch "^2.2.0" + blob-util "^2.0.2" + bluebird "^3.7.2" + buffer "^5.6.0" + cachedir "^2.3.0" + chalk "^4.1.0" + check-more-types "^2.24.0" + cli-cursor "^3.1.0" + cli-table3 "~0.6.1" + commander "^5.1.0" + common-tags "^1.8.0" + dayjs "^1.10.4" + debug "^4.3.2" + enquirer "^2.3.6" + eventemitter2 "^6.4.3" + execa "4.1.0" + executable "^4.1.1" + extract-zip "2.0.1" + figures "^3.2.0" + fs-extra "^9.1.0" + getos "^3.2.1" + is-ci "^3.0.0" + is-installed-globally "~0.4.0" + lazy-ass "^1.6.0" + listr2 "^3.8.3" + lodash "^4.17.21" + log-symbols "^4.0.0" + minimist "^1.2.6" + ospath "^1.2.2" + pretty-bytes "^5.6.0" + proxy-from-env "1.0.0" + request-progress "^3.0.0" + semver "^7.3.2" + supports-color "^8.1.1" + tmp "~0.2.1" + untildify "^4.0.0" + yauzl "^2.10.0" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + integrity sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g== + dependencies: + assert-plus "^1.0.0" + +dayjs@^1.10.4: + version "1.11.3" + resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.3.tgz#4754eb694a624057b9ad2224b67b15d552589258" + integrity sha512-xxwlswWOlGhzgQ4TKzASQkUhqERI3egRNqgV4ScR8wlANA/A9tZ7miXa44vTTKEq5l7vWoL5G57bG3zA+Kow0A== + +debug@^3.1.0: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +debug@^4.1.1, debug@^4.3.2: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +ecc-jsbn@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + integrity sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw== + dependencies: + jsbn "~0.1.0" + safer-buffer "^2.1.0" + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +end-of-stream@^1.1.0: + version "1.4.4" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== + dependencies: + once "^1.4.0" + +enquirer@^2.3.6: + version "2.3.6" + resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" + integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== + dependencies: + ansi-colors "^4.1.1" + +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 sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +eventemitter2@^6.4.3: + version "6.4.6" + resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-6.4.6.tgz#92d56569cc147a4d9b9da9e942e89b20ce236b0a" + integrity sha512-OHqo4wbHX5VbvlbB6o6eDwhYmiTjrpWACjF8Pmof/GTD6rdBNdZFNck3xlhqOiQFGCOoq3uzHvA0cQpFHIGVAQ== + +execa@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" + integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA== + dependencies: + cross-spawn "^7.0.0" + get-stream "^5.0.0" + human-signals "^1.1.1" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.0" + onetime "^5.1.0" + signal-exit "^3.0.2" + strip-final-newline "^2.0.0" + +executable@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/executable/-/executable-4.1.1.tgz#41532bff361d3e57af4d763b70582db18f5d133c" + integrity sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg== + dependencies: + pify "^2.2.0" + +extend@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + +extract-zip@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a" + integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg== + dependencies: + debug "^4.1.1" + get-stream "^5.1.0" + yauzl "^2.10.0" + optionalDependencies: + "@types/yauzl" "^2.9.1" + +extsprintf@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + integrity sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g== + +extsprintf@^1.2.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" + integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== + +fd-slicer@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" + integrity sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g== + dependencies: + pend "~1.2.0" + +figures@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" + integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== + dependencies: + escape-string-regexp "^1.0.5" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw== + +form-data@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.6" + mime-types "^2.1.12" + +fs-extra@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" + integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== + dependencies: + at-least-node "^1.0.0" + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +get-stream@^5.0.0, get-stream@^5.1.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== + dependencies: + pump "^3.0.0" + +getos@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/getos/-/getos-3.2.1.tgz#0134d1f4e00eb46144c5a9c0ac4dc087cbb27dc5" + integrity sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q== + dependencies: + async "^3.2.0" + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + integrity sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng== + dependencies: + assert-plus "^1.0.0" + +glob@^7.1.3: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +global-dirs@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-3.0.0.tgz#70a76fe84ea315ab37b1f5576cbde7d48ef72686" + integrity sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA== + dependencies: + ini "2.0.0" + +graceful-fs@^4.1.6, graceful-fs@^4.2.0: + version "4.2.10" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" + integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +http-signature@~1.3.6: + version "1.3.6" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.3.6.tgz#cb6fbfdf86d1c974f343be94e87f7fc128662cf9" + integrity sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw== + dependencies: + assert-plus "^1.0.0" + jsprim "^2.0.2" + sshpk "^1.14.1" + +human-signals@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" + integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== + +ieee754@^1.1.13: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +ini@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5" + integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA== + +is-ci@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-3.0.1.tgz#db6ecbed1bd659c43dac0f45661e7674103d1867" + integrity sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ== + dependencies: + ci-info "^3.2.0" + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-installed-globally@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.4.0.tgz#9a0fd407949c30f86eb6959ef1b7994ed0b7b520" + integrity sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ== + dependencies: + global-dirs "^3.0.0" + is-path-inside "^3.0.2" + +is-path-inside@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== + +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg== + +json-schema@0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" + integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== + +jsonfile@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" + integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + +jsprim@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-2.0.2.tgz#77ca23dbcd4135cd364800d22ff82c2185803d4d" + integrity sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ== + dependencies: + assert-plus "1.0.0" + extsprintf "1.3.0" + json-schema "0.4.0" + verror "1.10.0" + +lazy-ass@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/lazy-ass/-/lazy-ass-1.6.0.tgz#7999655e8646c17f089fdd187d150d3324d54513" + integrity sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw== + +listr2@^3.8.3: + version "3.14.0" + resolved "https://registry.yarnpkg.com/listr2/-/listr2-3.14.0.tgz#23101cc62e1375fd5836b248276d1d2b51fdbe9e" + integrity sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g== + dependencies: + cli-truncate "^2.1.0" + colorette "^2.0.16" + log-update "^4.0.0" + p-map "^4.0.0" + rfdc "^1.3.0" + rxjs "^7.5.1" + through "^2.3.8" + wrap-ansi "^7.0.0" + +lodash.once@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" + integrity sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg== + +lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + +log-symbols@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + +log-update@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1" + integrity sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg== + dependencies: + ansi-escapes "^4.3.0" + cli-cursor "^3.1.0" + slice-ansi "^4.0.0" + wrap-ansi "^6.2.0" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12, mime-types@~2.1.19: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +minimatch@^3.1.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +npm-run-path@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +once@^1.3.0, once@^1.3.1, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +onetime@^5.1.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +ospath@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/ospath/-/ospath-1.2.2.tgz#1276639774a3f8ef2572f7fe4280e0ea4550c07b" + integrity sha512-o6E5qJV5zkAbIDNhGSIlyOhScKXgQrSRMilfph0clDfM0nEnBOlKlH4sWDmG95BW/CvwNz0vmm7dJVtU2KlMiA== + +p-map@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== + dependencies: + aggregate-error "^3.0.0" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg== + +performance-now@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== + +pify@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== + +pretty-bytes@^5.6.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb" + integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg== + +proxy-from-env@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee" + integrity sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A== + +psl@^1.1.28: + version "1.9.0" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" + integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== + +pump@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +punycode@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + +qs@~6.5.2: + version "6.5.3" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" + integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== + +request-progress@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/request-progress/-/request-progress-3.0.0.tgz#4ca754081c7fec63f505e4faa825aa06cd669dbe" + integrity sha512-MnWzEHHaxHO2iWiQuHrUPBi/1WeBf5PkxQqNyNvLl9VAYSdXkP8tQ3pBSeCPD+yw0v0Aq1zosWLz0BdeXpWwZg== + dependencies: + throttleit "^1.0.0" + +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + +rfdc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" + integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== + +rimraf@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +rxjs@^7.5.1: + version "7.5.6" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.6.tgz#0446577557862afd6903517ce7cae79ecb9662bc" + integrity sha512-dnyv2/YsXhnm461G+R/Pe5bWP41Nm6LBXEYWI6eiFP4fiwx6WRI/CD0zbdVAudd9xwLEF2IDcKXLHit0FYjUzw== + dependencies: + tslib "^2.1.0" + +safe-buffer@^5.0.1, safe-buffer@^5.1.2: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +semver@^7.3.2: + version "7.3.7" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" + integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== + dependencies: + lru-cache "^6.0.0" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +signal-exit@^3.0.2: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +slice-ansi@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787" + integrity sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +slice-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +sshpk@^1.14.1: + version "1.17.0" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.17.0.tgz#578082d92d4fe612b13007496e543fa0fbcbe4c5" + integrity sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ== + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + bcrypt-pbkdf "^1.0.0" + dashdash "^1.12.0" + ecc-jsbn "~0.1.1" + getpass "^0.1.1" + jsbn "~0.1.0" + safer-buffer "^2.0.2" + tweetnacl "~0.14.0" + +string-width@^4.1.0, string-width@^4.2.0: + 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" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +throttleit@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c" + integrity sha512-rkTVqu6IjfQ/6+uNuuc3sZek4CEYxTJom3IktzgdSxcZqdARuebbA/f4QmAxMQIxqq9ZLEUkSYqvuk1I6VKq4g== + +through@^2.3.8: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== + +tmp@~0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" + integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== + dependencies: + rimraf "^3.0.0" + +tough-cookie@~2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== + dependencies: + psl "^1.1.28" + punycode "^2.1.1" + +tslib@^2.1.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" + integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w== + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +universalify@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" + integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== + +untildify@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" + integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== + +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +verror@1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + integrity sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw== + dependencies: + assert-plus "^1.0.0" + core-util-is "1.0.2" + extsprintf "^1.2.0" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wrap-ansi@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" + integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yauzl@^2.10.0: + version "2.10.0" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" + integrity sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g== + dependencies: + buffer-crc32 "~0.2.3" + fd-slicer "~1.1.0" From eaabed0bc35584a585f4f911059119618f2d6f8a Mon Sep 17 00:00:00 2001 From: mahula Date: Fri, 15 Jul 2022 14:33:38 +0200 Subject: [PATCH 057/977] add eslint to package config --- e2e-tests/cypress/tests/package.json | 3 +- e2e-tests/cypress/tests/yarn.lock | 379 ++++++++++++++++++++++++++- 2 files changed, 375 insertions(+), 7 deletions(-) diff --git a/e2e-tests/cypress/tests/package.json b/e2e-tests/cypress/tests/package.json index c311cf407..2b8f6f161 100644 --- a/e2e-tests/cypress/tests/package.json +++ b/e2e-tests/cypress/tests/package.json @@ -12,6 +12,7 @@ "lint": "eslint --max-warnings=0 --ext .js,.ts ." }, "dependencies": { - "cypress": "^10.3.0" + "cypress": "^10.3.0", + "eslint": "^8.19.0" } } diff --git a/e2e-tests/cypress/tests/yarn.lock b/e2e-tests/cypress/tests/yarn.lock index e106a617f..7ff7c56eb 100644 --- a/e2e-tests/cypress/tests/yarn.lock +++ b/e2e-tests/cypress/tests/yarn.lock @@ -39,6 +39,35 @@ debug "^3.1.0" lodash.once "^4.1.1" +"@eslint/eslintrc@^1.3.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.3.0.tgz#29f92c30bb3e771e4a2048c95fa6855392dfac4f" + integrity sha512-UWW0TMTmk2d7hLcWD1/e2g5HDM/HQ3csaLSqXCfqwh4uNDuNqlaKWXmEsL4Cs41Z0KnILNvwbHAah3C2yt06kw== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.3.2" + globals "^13.15.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@humanwhocodes/config-array@^0.9.2": + version "0.9.5" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.9.5.tgz#2cbaf9a89460da24b5ca6531b8bbfc23e1df50c7" + integrity sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw== + dependencies: + "@humanwhocodes/object-schema" "^1.2.1" + debug "^4.1.1" + minimatch "^3.0.4" + +"@humanwhocodes/object-schema@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" + integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== + "@types/node@*": version "18.0.4" resolved "https://registry.yarnpkg.com/@types/node/-/node-18.0.4.tgz#48aedbf35efb3af1248e4cd4d792c730290cd5d6" @@ -66,6 +95,16 @@ dependencies: "@types/node" "*" +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn@^8.7.1: + version "8.7.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30" + integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A== + aggregate-error@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" @@ -74,6 +113,16 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" +ajv@^6.10.0, ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + ansi-colors@^4.1.1: version "4.1.3" resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" @@ -103,6 +152,11 @@ arch@^2.2.0: resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11" integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ== +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + asn1@~0.2.3: version "0.2.6" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" @@ -198,12 +252,17 @@ cachedir@^2.3.0: resolved "https://registry.yarnpkg.com/cachedir/-/cachedir-2.3.0.tgz#0c75892a052198f0b21c7c1804d8331edfcae0e8" integrity sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw== +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + caseless@~0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw== -chalk@^4.1.0: +chalk@^4.0.0, chalk@^4.1.0: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -294,7 +353,7 @@ core-util-is@1.0.2: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ== -cross-spawn@^7.0.0: +cross-spawn@^7.0.0, cross-spawn@^7.0.2: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -303,7 +362,7 @@ cross-spawn@^7.0.0: shebang-command "^2.0.0" which "^2.0.1" -cypress@10.3.0: +cypress@^10.3.0: version "10.3.0" resolved "https://registry.yarnpkg.com/cypress/-/cypress-10.3.0.tgz#fae8d32f0822fcfb938e79c7c31ef344794336ae" integrity sha512-txkQWKzvBVnWdCuKs5Xc08gjpO89W2Dom2wpZgT9zWZT5jXxqPIxqP/NC1YArtkpmp3fN5HW8aDjYBizHLUFvg== @@ -377,11 +436,23 @@ debug@^4.1.1, debug@^4.3.2: dependencies: ms "2.1.2" +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -414,6 +485,110 @@ escape-string-regexp@^1.0.5: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-scope@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.1.1.tgz#fff34894c2f65e5226d3041ac480b4513a163642" + integrity sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-utils@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" + integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== + dependencies: + eslint-visitor-keys "^2.0.0" + +eslint-visitor-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" + integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== + +eslint-visitor-keys@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz#f6480fa6b1f30efe2d1968aa8ac745b862469826" + integrity sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA== + +eslint@^8.19.0: + version "8.19.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.19.0.tgz#7342a3cbc4fbc5c106a1eefe0fd0b50b6b1a7d28" + integrity sha512-SXOPj3x9VKvPe81TjjUJCYlV4oJjQw68Uek+AM0X4p+33dj2HY5bpTZOgnQHcG2eAm1mtCU9uNMnJi7exU/kYw== + dependencies: + "@eslint/eslintrc" "^1.3.0" + "@humanwhocodes/config-array" "^0.9.2" + ajv "^6.10.0" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.1.1" + eslint-utils "^3.0.0" + eslint-visitor-keys "^3.3.0" + espree "^9.3.2" + esquery "^1.4.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + functional-red-black-tree "^1.0.1" + glob-parent "^6.0.1" + globals "^13.15.0" + ignore "^5.2.0" + import-fresh "^3.0.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.1" + regexpp "^3.2.0" + strip-ansi "^6.0.1" + strip-json-comments "^3.1.0" + text-table "^0.2.0" + v8-compile-cache "^2.0.3" + +espree@^9.3.2: + version "9.3.2" + resolved "https://registry.yarnpkg.com/espree/-/espree-9.3.2.tgz#f58f77bd334731182801ced3380a8cc859091596" + integrity sha512-D211tC7ZwouTIuY5x9XnS0E9sWNChB7IYKX/Xp5eQj3nFXhqmiUDB9q27y76oFl8jTg3pXcQx/bpxMfs3CIZbA== + dependencies: + acorn "^8.7.1" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.3.0" + +esquery@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.4.0.tgz#2148ffc38b82e8c7057dfed48425b3e61f0f24a5" + integrity sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + eventemitter2@^6.4.3: version "6.4.6" resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-6.4.6.tgz#92d56569cc147a4d9b9da9e942e89b20ce236b0a" @@ -467,6 +642,21 @@ extsprintf@^1.2.0: resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + fd-slicer@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" @@ -481,6 +671,26 @@ figures@^3.2.0: dependencies: escape-string-regexp "^1.0.5" +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" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +flat-cache@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" + integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== + dependencies: + flatted "^3.1.0" + rimraf "^3.0.2" + +flatted@^3.1.0: + version "3.2.6" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.6.tgz#022e9218c637f9f3fc9c35ab9c9193f05add60b2" + integrity sha512-0sQoMh9s0BYsm+12Huy/rkKxVu4R1+r96YX5cG44rHV0pQ6iC3Q+mkoMFaGWObMFYQxCVT+ssG1ksneA2MI9KQ== + forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" @@ -510,6 +720,11 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== + get-stream@^5.0.0, get-stream@^5.1.0: version "5.2.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" @@ -531,6 +746,13 @@ getpass@^0.1.1: dependencies: assert-plus "^1.0.0" +glob-parent@^6.0.1: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + glob@^7.1.3: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" @@ -550,6 +772,13 @@ global-dirs@^3.0.0: dependencies: ini "2.0.0" +globals@^13.15.0: + version "13.16.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.16.0.tgz#9be4aca28f311aaeb974ea54978ebbb5e35ce46a" + integrity sha512-A1lrQfpNF+McdPOnnFqY3kSN0AFTy485bTi1bkLk4mVPODIUEcSfhHgRqA+QdXPksrSTTztYXx37NFV+GpGk3Q== + dependencies: + type-fest "^0.20.2" + graceful-fs@^4.1.6, graceful-fs@^4.2.0: version "4.2.10" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" @@ -579,6 +808,24 @@ ieee754@^1.1.13: resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== +ignore@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" + integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== + +import-fresh@^3.0.0, import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + indent-string@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" @@ -609,11 +856,23 @@ is-ci@^3.0.0: dependencies: ci-info "^3.2.0" +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + is-fullwidth-code-point@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== +is-glob@^4.0.0, is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + is-installed-globally@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.4.0.tgz#9a0fd407949c30f86eb6959ef1b7994ed0b7b520" @@ -652,16 +911,33 @@ isstream@~0.1.2: resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== +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== + dependencies: + argparse "^2.0.1" + jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg== +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + json-schema@0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" @@ -691,6 +967,14 @@ lazy-ass@^1.6.0: resolved "https://registry.yarnpkg.com/lazy-ass/-/lazy-ass-1.6.0.tgz#7999655e8646c17f089fdd187d150d3324d54513" integrity sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw== +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + listr2@^3.8.3: version "3.14.0" resolved "https://registry.yarnpkg.com/listr2/-/listr2-3.14.0.tgz#23101cc62e1375fd5836b248276d1d2b51fdbe9e" @@ -705,6 +989,11 @@ listr2@^3.8.3: through "^2.3.8" wrap-ansi "^7.0.0" +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + lodash.once@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" @@ -762,7 +1051,7 @@ mimic-fn@^2.1.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== -minimatch@^3.1.1: +minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -784,6 +1073,11 @@ ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + npm-run-path@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" @@ -805,6 +1099,18 @@ onetime@^5.1.0: dependencies: mimic-fn "^2.1.0" +optionator@^0.9.1: + version "0.9.1" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.1.tgz#4f236a6373dae0566a6d43e1326674f50c291499" + integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.3" + ospath@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/ospath/-/ospath-1.2.2.tgz#1276639774a3f8ef2572f7fe4280e0ea4550c07b" @@ -817,6 +1123,13 @@ p-map@^4.0.0: dependencies: aggregate-error "^3.0.0" +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" @@ -842,6 +1155,11 @@ pify@^2.2.0: resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + pretty-bytes@^5.6.0: version "5.6.0" resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb" @@ -865,7 +1183,7 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" -punycode@^2.1.1: +punycode@^2.1.0, punycode@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== @@ -875,6 +1193,11 @@ qs@~6.5.2: resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== +regexpp@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" + integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + request-progress@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/request-progress/-/request-progress-3.0.0.tgz#4ca754081c7fec63f505e4faa825aa06cd669dbe" @@ -882,6 +1205,11 @@ request-progress@^3.0.0: dependencies: throttleit "^1.0.0" +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + restore-cursor@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" @@ -895,7 +1223,7 @@ rfdc@^1.3.0: resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== -rimraf@^3.0.0: +rimraf@^3.0.0, rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== @@ -997,6 +1325,11 @@ strip-final-newline@^2.0.0: resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: + version "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@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" @@ -1011,6 +1344,11 @@ supports-color@^8.1.1: dependencies: has-flag "^4.0.0" +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + throttleit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c" @@ -1053,6 +1391,18 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + type-fest@^0.21.3: version "0.21.3" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" @@ -1068,11 +1418,23 @@ untildify@^4.0.0: resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + uuid@^8.3.2: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== +v8-compile-cache@^2.0.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" + integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== + verror@1.10.0: version "1.10.0" resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" @@ -1089,6 +1451,11 @@ which@^2.0.1: dependencies: isexe "^2.0.0" +word-wrap@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== + wrap-ansi@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" From 9860a0509d5050ac6d2369d1cf040806d9306b1a Mon Sep 17 00:00:00 2001 From: mahula Date: Fri, 15 Jul 2022 15:09:57 +0200 Subject: [PATCH 058/977] rework cypress tests dockerfile: - reduce to necessary dependencies - control browser installation (chromium, firefox) - use yarn for cypress installation --- e2e-tests/cypress/Dockerfile | 77 +++++++++++------------------------- 1 file changed, 22 insertions(+), 55 deletions(-) diff --git a/e2e-tests/cypress/Dockerfile b/e2e-tests/cypress/Dockerfile index 5251e071a..8119ea08d 100644 --- a/e2e-tests/cypress/Dockerfile +++ b/e2e-tests/cypress/Dockerfile @@ -2,64 +2,31 @@ # Dockerfile to create a ready-to-use Cypress Docker image for end-to-end # testing. # -# This Dockerfile is based on the Dockerfile using Node.js 16.14.2 and -# Cypress 10.3.0 -# (https://github.com/cypress-io/cypress-docker-images/blob/master/included/10.3.0/Dockerfile) -# from Cypress.io Docker images. +# Based on the images containing several browsers, provided by Cypress.io +# (https://github.com/cypress-io/cypress-docker-images/tree/master/browsers) +# this Dockerfile is based a slim Linux Dockerfile using Node.js 16.14.2. +# +# Here the latest stable versions of the browsers Chromium and Firefox are +# installed before installing Cypress. ############################################################################### -FROM cypress/browsers:node16.14.2-slim-chrome100-ff99-edge +FROM cypress/base:16.14.2-slim -# avoid too many progress messages -# https://github.com/cypress-io/cypress/issues/1243 -ENV CI=1 \ -# disable shared memory X11 affecting Cypress v4 and Chrome -# https://github.com/cypress-io/cypress-docker-images/issues/270 - QT_X11_NO_MITSHM=1 \ - _X11_NO_MITSHM=1 \ - _MITSHM=0 \ - # point Cypress at the /root/cache no matter what user account is used - # see https://on.cypress.io/caching - CYPRESS_CACHE_FOLDER=/root/.cache/Cypress \ - # Allow projects to reference globally installed cypress - NODE_PATH=/usr/local/lib/node_modules +# install dependencies +RUN apt-get -qq update > /dev/null && \ + apt-get -qq install -y bzip2 mplayer wget > /dev/null -# should be root user -RUN echo "whoami: $(whoami)" \ - && npm config -g set user $(whoami) \ - # command "id" should print: - # uid=0(root) gid=0(root) groups=0(root) - # which means the current user is root - && id \ - && npm install -g "cypress@10.3.0" \ - && cypress verify \ - # Cypress cache and installed version - # should be in the root user's home folder - && cypress cache path \ - && cypress cache list \ - && cypress info \ - && cypress version \ - # give every user read access to the "/root" folder where the binary is cached - # we really only need to worry about the top folder, fortunately - && ls -la /root \ - && chmod 755 /root \ - # always grab the latest Yarn - # otherwise the base image might have old versions - # NPM does not need to be installed as it is already included with Node. - && npm i -g yarn@latest \ - # Show where Node loads required modules from - && node -p 'module.paths' \ - # should print Cypress version - # plus Electron and bundled Node versions - && cypress version \ - && echo " node version: $(node -v) \n" \ - "npm version: $(npm -v) \n" \ - "yarn version: $(yarn -v) \n" \ - "debian version: $(cat /etc/debian_version) \n" \ - "user: $(whoami) \n" \ - "chrome: $(google-chrome --version || true) \n" \ - "firefox: $(firefox --version || true) \n" +# install Chromium browser +RUN apt-get -qq install -y chromium > /dev/null + +# install Firefox browser +RUN wget --no-verbose -O /tmp/firefox.tar.bz2 "https://download.mozilla.org/?product=firefox-latest&os=linux64&lang=en-US" && \ + tar -C /opt -xjf /tmp/firefox.tar.bz2 && \ + rm /tmp/firefox.tar.bz2 && \ + ln -fs /opt/firefox/firefox /usr/bin/firefox + +# clean up +RUN rm -rf /var/lib/apt/lists/* && apt-get -qq clean > /dev/null WORKDIR /tests COPY tests/ /tests - -# ENTRYPOINT ["cypress", "run"] +RUN yarn install From 4e9e834df497526b5a81f5e8d0e346114ab2f476 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Fri, 15 Jul 2022 16:37:32 +0200 Subject: [PATCH 059/977] adapt users table --- .../User.ts | 109 ++++++++++++++++++ database/entity/User.ts | 2 +- database/entity/index.ts | 2 + .../0044-adapt_users_table_for_gradidoid.ts | 2 +- 4 files changed, 113 insertions(+), 2 deletions(-) create mode 100644 database/entity/0044-adapt_users_table_for_gradidoid/User.ts diff --git a/database/entity/0044-adapt_users_table_for_gradidoid/User.ts b/database/entity/0044-adapt_users_table_for_gradidoid/User.ts new file mode 100644 index 000000000..658638b5e --- /dev/null +++ b/database/entity/0044-adapt_users_table_for_gradidoid/User.ts @@ -0,0 +1,109 @@ +import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, DeleteDateColumn } from 'typeorm' + +@Entity('users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) +export class User extends BaseEntity { + @PrimaryGeneratedColumn('increment', { unsigned: true }) + id: number + + @Column({ + name: 'gradido_id', + length: 36, + nullable: true, + default: null, + collation: 'utf8mb4_unicode_ci', + }) + gradidoID: string + + @Column({ + name: 'alias', + length: 20, + nullable: true, + default: null, + collation: 'utf8mb4_unicode_ci', + }) + alias: string + + @Column({ name: 'public_key', type: 'binary', length: 32, default: null, nullable: true }) + pubKey: Buffer + + @Column({ name: 'privkey', type: 'binary', length: 80, default: null, nullable: true }) + privKey: Buffer + + @Column({ + name: 'passphrase_encrypt_type', + length: 36, + nullable: true, + default: null, + collation: 'utf8mb4_unicode_ci', + }) + passphraseEncryptType: string + + @Column({ length: 255, unique: true, nullable: false, collation: 'utf8mb4_unicode_ci' }) + email: string + + @Column({ name: 'email_id', type: 'int', unsigned: true, nullable: true, default: null }) + emailId?: number | null + + @Column({ + name: 'first_name', + length: 255, + nullable: true, + default: null, + collation: 'utf8mb4_unicode_ci', + }) + firstName: string + + @Column({ + name: 'last_name', + length: 255, + nullable: true, + default: null, + collation: 'utf8mb4_unicode_ci', + }) + lastName: string + + @DeleteDateColumn() + deletedAt: Date | null + + @Column({ type: 'bigint', default: 0, unsigned: true }) + password: BigInt + + @Column({ name: 'email_hash', type: 'binary', length: 32, default: null, nullable: true }) + emailHash: Buffer + + @Column({ name: 'created', default: () => 'CURRENT_TIMESTAMP', nullable: false }) + createdAt: Date + + @Column({ name: 'email_checked', type: 'bool', nullable: false, default: false }) + emailChecked: boolean + + @Column({ length: 4, default: 'de', collation: 'utf8mb4_unicode_ci', nullable: false }) + language: string + + @Column({ name: 'is_admin', type: 'datetime', nullable: true, default: null }) + isAdmin: Date | null + + @Column({ name: 'referrer_id', type: 'int', unsigned: true, nullable: true, default: null }) + referrerId?: number | null + + @Column({ + name: 'contribution_link_id', + type: 'int', + unsigned: true, + nullable: true, + default: null, + }) + contributionLinkId?: number | null + + @Column({ name: 'publisher_id', default: 0 }) + publisherId: number + + @Column({ + type: 'text', + name: 'passphrase', + collation: 'utf8mb4_unicode_ci', + nullable: true, + default: null, + }) + passphrase: string +} diff --git a/database/entity/User.ts b/database/entity/User.ts index 99b8c8ca9..a29e87cd7 100644 --- a/database/entity/User.ts +++ b/database/entity/User.ts @@ -1 +1 @@ -export { User } from './0040-add_contribution_link_id_to_user/User' +export { User } from './0044-adapt_users_table_for_gradidoid/User' diff --git a/database/entity/index.ts b/database/entity/index.ts index 266c40740..76acba3fa 100644 --- a/database/entity/index.ts +++ b/database/entity/index.ts @@ -5,6 +5,7 @@ import { Migration } from './Migration' import { Transaction } from './Transaction' import { TransactionLink } from './TransactionLink' import { User } from './User' +import { UserContact } from './UserContact' import { Contribution } from './Contribution' export const entities = [ @@ -16,4 +17,5 @@ export const entities = [ Transaction, TransactionLink, User, + UserContact, ] diff --git a/database/migrations/0044-adapt_users_table_for_gradidoid.ts b/database/migrations/0044-adapt_users_table_for_gradidoid.ts index 29fae353e..eb5f8e2cf 100644 --- a/database/migrations/0044-adapt_users_table_for_gradidoid.ts +++ b/database/migrations/0044-adapt_users_table_for_gradidoid.ts @@ -1,6 +1,6 @@ /* MIGRATION TO ADD GRADIDO_ID * - * This migration adds new columns to the table `users` and creates the + * This migration adds new columns to the table `users` and creates the * new table `user_contacts` */ From 138891dfe36ad44f5375cabe388995195850f2e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Fri, 15 Jul 2022 16:37:49 +0200 Subject: [PATCH 060/977] add user_contacts table --- .../UserContact.ts | 40 +++++++++++++++++++ database/entity/UserContact.ts | 1 + 2 files changed, 41 insertions(+) create mode 100644 database/entity/0044-adapt_users_table_for_gradidoid/UserContact.ts create mode 100644 database/entity/UserContact.ts diff --git a/database/entity/0044-adapt_users_table_for_gradidoid/UserContact.ts b/database/entity/0044-adapt_users_table_for_gradidoid/UserContact.ts new file mode 100644 index 000000000..41f622722 --- /dev/null +++ b/database/entity/0044-adapt_users_table_for_gradidoid/UserContact.ts @@ -0,0 +1,40 @@ +import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, DeleteDateColumn } from 'typeorm' + +@Entity('user_contacts', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) +export class UserContact extends BaseEntity { + @PrimaryGeneratedColumn('increment', { unsigned: true }) + id: number + + @Column({ + name: 'type', + length: 100, + nullable: true, + default: null, + collation: 'utf8mb4_unicode_ci', + }) + type: string + + @Column({ name: 'users_id', type: 'int', unsigned: true, nullable: false }) + usersId?: number | null + + @Column({ length: 255, unique: true, nullable: false, collation: 'utf8mb4_unicode_ci' }) + email: string + + @Column({ name: 'email_hash', type: 'binary', length: 32, default: null, nullable: true }) + emailHash: Buffer + + @Column({ name: 'email_checked', type: 'bool', nullable: false, default: false }) + emailChecked: boolean + + @Column({ length: 255, unique: false, nullable: true, collation: 'utf8mb4_unicode_ci' }) + phone: string + + @Column({ name: 'created', default: () => 'CURRENT_TIMESTAMP', nullable: false }) + createdAt: Date + + @DeleteDateColumn() + updatedAt: Date | null + + @DeleteDateColumn() + deletedAt: Date | null +} diff --git a/database/entity/UserContact.ts b/database/entity/UserContact.ts new file mode 100644 index 000000000..dce775516 --- /dev/null +++ b/database/entity/UserContact.ts @@ -0,0 +1 @@ +export { UserContact } from './0044-adapt_users_table_for_gradidoid/UserContact' From 0b8e8988189f8c8a8a832e7102ae70e935e63185 Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 18 Jul 2022 11:12:21 +0200 Subject: [PATCH 061/977] refactor contribution form --- .../Contributions/ContributionForm.vue | 78 ++++++++++++++----- frontend/src/locales/de.json | 3 +- frontend/src/locales/en.json | 3 +- 3 files changed, 63 insertions(+), 21 deletions(-) diff --git a/frontend/src/components/Contributions/ContributionForm.vue b/frontend/src/components/Contributions/ContributionForm.vue index 777806c30..08bfa635e 100644 --- a/frontend/src/components/Contributions/ContributionForm.vue +++ b/frontend/src/components/Contributions/ContributionForm.vue @@ -12,14 +12,14 @@ {{ $t('contribution.formText.text2') }}
- +
+ {{ form.memo.length }} {{ $t('math.equalTo') }} {{ minlength }} {{ $t('math.divide') }} {{ maxlength }}
@@ -49,15 +51,39 @@ v-model="form.amount" type="number" min="1" - max="1000" + :max="isThisMonth ? maxGddThisMonth : maxGddLastMonth" > - -
- - {{ $t('contribution.submit') }} - +
+ {{ + isThisMonth && form.amount > maxGddThisMonth + ? $t('contribution.formText.maxGDDforMonth', { amount: maxGddThisMonth }) + : '' + }} + {{ + !isThisMonth && form.amount > maxGddLastMonth + ? $t('contribution.formText.maxGDDforMonth', { amount: maxGddLastMonth }) + : '' + }}
+ + + + {{ $t('form.reset') }} + + + + + {{ id === null ? $t('contribution.submit') : $t('form.edit') }} + + +
@@ -69,36 +95,47 @@ export default { }, data() { return { + maxGddLastMonth: this.$store.state.creation[1], + maxGddThisMonth: this.$store.state.creation[2], minlength: 50, maxlength: 255, - max: new Date(), + maximalDate: new Date(), form: this.value, + id: this.value.id, } }, methods: { submit() { - this.$emit('set-contribution', this.form) + if (this.id === null) { + this.$emit('set-contribution', this.form) + } else { + this.$emit('edit-contribution', this.value) + } + this.reset() + }, + reset() { this.$refs.form.reset() this.form.date = '' + this.id = null + this.form.memo = '' }, }, computed: { /* * lastMonth() = The date set back by one month. - * min() = The date is reset by one month to the 1st of the previous month. + * minimalDate() = The date is reset by one month to the 1st of the previous month. * */ - lastMonth() { - return new Date(this.max.getFullYear(), this.max.getMonth() - 1, 1) - }, - min() { - return new Date(this.max.getFullYear(), this.max.getMonth() - 1, 1) + minimalDate() { + return new Date(this.maximalDate.getFullYear(), this.maximalDate.getMonth() - 1, 1) }, disabled() { if ( this.form.memo.length < this.minlength || this.form.amount <= 0 || - this.form.amount > 1000 + this.form.amount > 1000 || + (this.isThisMonth && this.form.amount > this.maxGddThisMonth) || + (!this.isThisMonth && this.form.amount > this.maxGddlastMonth) ) return true return false @@ -106,7 +143,7 @@ export default { lastMonthObject() { // new Date().getMonth === 1 If the current month is January, then one year must be gone back in the previous month const obj = { - monthAndYear: this.$d(new Date(this.lastMonth), 'monthAndYear'), + monthAndYear: this.$d(new Date(this.minimalDate), 'monthAndYear'), creation: this.$store.state.creation[1], } return this.$t('contribution.formText.lastMonth', obj) @@ -118,6 +155,9 @@ export default { } return this.$t('contribution.formText.thisMonth', obj) }, + isThisMonth() { + return new Date(this.form.date).getMonth() === new Date().getMonth() + }, }, } diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index 5c8b8b366..bc27e4b3e 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -38,7 +38,8 @@ "lastMonth": "Für {monthAndYear} kannst du noch {creation} GDD einreichen.", "text1": "Bring dich mit deinen Talenten in die Gemeinschaft ein! Dein freiwilliges Engagement honorieren wir mit 20 GDD pro Stunde bis maximal 1.000 GDD im Monat.", "text2": "Beschreibe deine Gemeinwohl-Tätigkeit mit Angabe der Stunden und trage einen Betrag von 20 GDD pro Stunde ein! Nach Bestätigung durch einen Moderator wird der Betrag deinem Konto gutgeschrieben.", - "thisMonth": "Für {monthAndYear} kannst du noch {creation} GDD einreichen. " + "thisMonth": "Für {monthAndYear} kannst du noch {creation} GDD einreichen.", + "maxGDDforMonth":"Du kannst für den ausgewählten Monat nur noch maximal {amount} GDD einreichen." }, "noDateSelected": "Kein Datum ausgewählt", "submit": "Einreichen" diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index 8b0df2595..304cae4c7 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -38,7 +38,8 @@ "lastMonth": "For {monthAndYear}, you can still submit {creation} GDD.", "text1": "Bring your talents to the community! Your voluntary commitment will be rewarded with 20 GDD per hour up to a maximum of 1,000 GDD per month.", "text2": "Describe your community service activity with hours and enter an amount of 20 GDD per hour! After confirmation by a moderator, the amount will be credited to your account.", - "thisMonth": "For {monthAndYear}, you can still submit {creation} GDD." + "thisMonth": "For {monthAndYear}, you can still submit {creation} GDD.", + "maxGDDforMonth":"You can only submit a maximum of {amount} GDD for the selected month." }, "noDateSelected": "No date selected", "submit": "Submit" From 1e4540ef71a23919d99eb5d9335319911f88a29d Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 18 Jul 2022 11:13:11 +0200 Subject: [PATCH 062/977] fix locales --- frontend/src/locales/de.json | 4 ++-- frontend/src/locales/en.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index bc27e4b3e..8676eba9f 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -36,10 +36,10 @@ "formText": { "h3": "Dein Beitrag zum Gemeinwohl", "lastMonth": "Für {monthAndYear} kannst du noch {creation} GDD einreichen.", + "maxGDDforMonth": "Du kannst für den ausgewählten Monat nur noch maximal {amount} GDD einreichen.", "text1": "Bring dich mit deinen Talenten in die Gemeinschaft ein! Dein freiwilliges Engagement honorieren wir mit 20 GDD pro Stunde bis maximal 1.000 GDD im Monat.", "text2": "Beschreibe deine Gemeinwohl-Tätigkeit mit Angabe der Stunden und trage einen Betrag von 20 GDD pro Stunde ein! Nach Bestätigung durch einen Moderator wird der Betrag deinem Konto gutgeschrieben.", - "thisMonth": "Für {monthAndYear} kannst du noch {creation} GDD einreichen.", - "maxGDDforMonth":"Du kannst für den ausgewählten Monat nur noch maximal {amount} GDD einreichen." + "thisMonth": "Für {monthAndYear} kannst du noch {creation} GDD einreichen." }, "noDateSelected": "Kein Datum ausgewählt", "submit": "Einreichen" diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index 304cae4c7..4282c1086 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -36,10 +36,10 @@ "formText": { "h3": "Your contribution to the common good", "lastMonth": "For {monthAndYear}, you can still submit {creation} GDD.", + "maxGDDforMonth": "You can only submit a maximum of {amount} GDD for the selected month.", "text1": "Bring your talents to the community! Your voluntary commitment will be rewarded with 20 GDD per hour up to a maximum of 1,000 GDD per month.", "text2": "Describe your community service activity with hours and enter an amount of 20 GDD per hour! After confirmation by a moderator, the amount will be credited to your account.", - "thisMonth": "For {monthAndYear}, you can still submit {creation} GDD.", - "maxGDDforMonth":"You can only submit a maximum of {amount} GDD for the selected month." + "thisMonth": "For {monthAndYear}, you can still submit {creation} GDD." }, "noDateSelected": "No date selected", "submit": "Submit" From 45013efd8da7fb5c366ddb1592650a3e897f624b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Mon, 18 Jul 2022 12:02:56 +0200 Subject: [PATCH 063/977] Remove forgotten to delete lines in Docker Compose Apple M1 override --- docker-compose.apple-m1.override.yml | 9 --------- 1 file changed, 9 deletions(-) diff --git a/docker-compose.apple-m1.override.yml b/docker-compose.apple-m1.override.yml index 7cf3efd3e..72152f9ae 100644 --- a/docker-compose.apple-m1.override.yml +++ b/docker-compose.apple-m1.override.yml @@ -41,12 +41,3 @@ services: ######################################################### nginx: platform: linux/amd64 - -networks: - external-net: - internal-net: - internal: true - -volumes: - db_vol: - From b7c49b2410ce18c7fdf6eca4ab0fd94553717445 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Mon, 18 Jul 2022 12:24:29 +0200 Subject: [PATCH 064/977] Change Docker Compose image names and add comments wy --- docker-compose.override.yml | 19 ++++++++++++------- docker-compose.test.yml | 1 + docker-compose.yml | 13 +++++++++---- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/docker-compose.override.yml b/docker-compose.override.yml index 2583ea77c..9d3e0b8d4 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -1,11 +1,13 @@ version: "3.4" services: + ######################################################## # FRONTEND ############################################# ######################################################## frontend: - # image: gradido/frontend:development + # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there + image: gradido/frontend:local-development build: target: development environment: @@ -22,7 +24,8 @@ services: # ADMIN INTERFACE ###################################### ######################################################## admin: - # image: gradido/admin:development + # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there + image: gradido/admin:local-development build: target: development environment: @@ -39,7 +42,8 @@ services: # BACKEND ############################################## ######################################################## backend: - # image: gradido/backend:development + # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there + image: gradido/backend:local-development build: target: development networks: @@ -62,10 +66,11 @@ services: ######################################################## database: # we always run on production here since else the service lingers - # feel free to change this behaviour if it seems useful - # Due to problems with the volume caching the built files - # we changed this to test build. This keeps the service running. - # image: gradido/database:test_up + # feel free to change this behaviour if it seems useful + # Due to problems with the volume caching the built files + # we changed this to test build. This keeps the service running. + # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there + image: gradido/database:local-test_up build: target: test_up environment: diff --git a/docker-compose.test.yml b/docker-compose.test.yml index 221ecba20..7db318176 100644 --- a/docker-compose.test.yml +++ b/docker-compose.test.yml @@ -6,6 +6,7 @@ services: # BACKEND ############################################## ######################################################## backend: + # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there image: gradido/backend:test build: target: test diff --git a/docker-compose.yml b/docker-compose.yml index 26a1ecbe2..6c0dffe15 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -6,11 +6,13 @@ version: "3.4" services: + ######################################################## # FRONTEND ############################################# ######################################################## frontend: - # image: gradido/frontend:latest + # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there + image: gradido/frontend:local-production build: context: ./frontend target: production @@ -35,7 +37,8 @@ services: # ADMIN INTERFACE ###################################### ######################################################## admin: - # image: gradido/admin:latest + # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there + image: gradido/admin:local-production build: context: ./admin target: production @@ -77,7 +80,8 @@ services: # BACKEND ############################################## ######################################################## backend: - # image: gradido/backend:latest + # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there + image: gradido/backend:local-production build: # since we have to include the entities from ./database we cannot define the context as ./backend # this might blow build image size to the moon ?! @@ -108,7 +112,8 @@ services: # DATABASE ############################################# ######################################################## database: - #image: gradido/database:production_up + # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there + image: gradido/database:local-production_up build: context: ./database target: production_up From 4338328690bedc4087f058bc953ad8fd9ee2ba54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Mon, 18 Jul 2022 12:40:13 +0200 Subject: [PATCH 065/977] Add Docker documentation in DOCKER_MORE_CLOSELY.md --- DOCKER_MORE_CLOSELY.md | 44 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 DOCKER_MORE_CLOSELY.md diff --git a/DOCKER_MORE_CLOSELY.md b/DOCKER_MORE_CLOSELY.md new file mode 100644 index 000000000..f2aae81c7 --- /dev/null +++ b/DOCKER_MORE_CLOSELY.md @@ -0,0 +1,44 @@ +# Docker More Closely + +## Apple M1 Platform + +***Attention:** For using Docker commands in Apple M1 environments!* + +### Enviroment Variable For Apple M1 Platform + +To set the Docker platform environment variable in your terminal tab, run: + +```bash +# set env variable for your shell +$ export DOCKER_DEFAULT_PLATFORM=linux/amd64 +``` + +### Docker Compose Override File For Apple M1 Platform + +For Docker compose `up` or `build` commands, you can use our Apple M1 override file that specifies the M1 platform: + +```bash +# in main folder + +# for development +$ docker compose -f docker-compose.yml -f docker-compose.override.yml -f docker-compose.apple-m1.override.yml up + +# for production +$ docker compose -f docker-compose.yml -f docker-compose.apple-m1.override.yml up +``` + +## Analysing Docker Builds + +To analyze a Docker build, there is a wonderful tool called [dive](https://github.com/wagoodman/dive). Please sponsor if you're using it! + +The `dive build` command is exactly the right one to fulfill what we are looking for. +We can use it just like the `docker build` command and get an analysis afterwards. + +So, in our main folder, we use it in the following way: + +```bash +# in main folder +$ dive build --target -t "gradido/:local-" / +``` + +For the specific applications, see our [publish.yml](.github/workflows/publish.yml). From 951d7f2f884274b5d5ebe4de8285a82a7d76e61a Mon Sep 17 00:00:00 2001 From: elweyn Date: Mon, 18 Jul 2022 11:27:44 +0200 Subject: [PATCH 066/977] Change the listContribution query to give back ContributionListResult object with linkCount. --- backend/src/graphql/resolver/ContributionResolver.ts | 12 ++++++++---- backend/src/seeds/graphql/queries.ts | 9 ++++++--- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index d71ecac59..c834904d6 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -2,6 +2,7 @@ import { RIGHTS } from '@/auth/RIGHTS' import { Context, getUser } from '@/server/context' import { backendLogger as logger } from '@/server/logger' import { Contribution as dbContribution } from '@entity/Contribution' +import { User as dbUser } from '@entity/User' import { Arg, Args, Authorized, Ctx, Int, Mutation, Query, Resolver } from 'type-graphql' import { FindOperator, IsNull } from '@dbTools/typeorm' import ContributionArgs from '@arg/ContributionArgs' @@ -39,21 +40,21 @@ export class ContributionResolver { } @Authorized([RIGHTS.LIST_CONTRIBUTIONS]) - @Query(() => [Contribution]) + @Query(() => ContributionListResult) async listContributions( @Args() { currentPage = 1, pageSize = 5, order = Order.DESC }: Paginated, @Arg('filterConfirmed', () => Boolean) filterConfirmed: boolean | null, @Ctx() context: Context, - ): Promise { + ): Promise { const user = getUser(context) const where: { userId: number confirmedBy?: FindOperator | null } = { userId: user.id } if (filterConfirmed) where.confirmedBy = IsNull() - const contributions = await dbContribution.find({ + const [contributions, count] = await dbContribution.findAndCount({ where, order: { createdAt: order, @@ -62,7 +63,10 @@ export class ContributionResolver { skip: (currentPage - 1) * pageSize, take: pageSize, }) - return contributions.map((contribution) => new Contribution(contribution, new User(user))) + return new ContributionListResult( + count, + contributions.map((contribution) => new Contribution(contribution, new User(user))), + ) } @Authorized([RIGHTS.LIST_ALL_CONTRIBUTIONS]) diff --git a/backend/src/seeds/graphql/queries.ts b/backend/src/seeds/graphql/queries.ts index deae5f97b..e18d6b303 100644 --- a/backend/src/seeds/graphql/queries.ts +++ b/backend/src/seeds/graphql/queries.ts @@ -185,9 +185,12 @@ export const listContributions = gql` order: $order filterConfirmed: $filterConfirmed ) { - id - amount - memo + linkCount + linkList { + id + amount + memo + } } } ` From f1238957f9262b62323341e631d964a302a0c651 Mon Sep 17 00:00:00 2001 From: elweyn Date: Mon, 18 Jul 2022 11:31:04 +0200 Subject: [PATCH 067/977] Change linkCount to contributionCount and linkList to contributionList. --- backend/src/graphql/model/Contribution.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/src/graphql/model/Contribution.ts b/backend/src/graphql/model/Contribution.ts index 34bffd6d7..13c2d40d7 100644 --- a/backend/src/graphql/model/Contribution.ts +++ b/backend/src/graphql/model/Contribution.ts @@ -48,13 +48,13 @@ export class Contribution { @ObjectType() export class ContributionListResult { constructor(count: number, list: Contribution[]) { - this.linkCount = count - this.linkList = list + this.contributionCount = count + this.contributionList = list } @Field(() => Int) - linkCount: number + contributionCount: number @Field(() => [Contribution]) - linkList: Contribution[] + contributionList: Contribution[] } From b384782e63c83863dcce60540b3fe340e64384a5 Mon Sep 17 00:00:00 2001 From: elweyn Date: Mon, 18 Jul 2022 11:31:39 +0200 Subject: [PATCH 068/977] Change query of listContribution to get contributionCount and contributionList instead of link... --- backend/src/seeds/graphql/queries.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/seeds/graphql/queries.ts b/backend/src/seeds/graphql/queries.ts index e18d6b303..0d72c165d 100644 --- a/backend/src/seeds/graphql/queries.ts +++ b/backend/src/seeds/graphql/queries.ts @@ -185,8 +185,8 @@ export const listContributions = gql` order: $order filterConfirmed: $filterConfirmed ) { - linkCount - linkList { + contributionCount + contributionList { id amount memo From 7d5555c7e40ec621f1f9746a7a155cdecf745de0 Mon Sep 17 00:00:00 2001 From: elweyn Date: Mon, 18 Jul 2022 11:34:30 +0200 Subject: [PATCH 069/977] Change query listAllContributions now gets contributionCount and contributionList instead of linkCount and linkList. --- backend/src/seeds/graphql/queries.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/seeds/graphql/queries.ts b/backend/src/seeds/graphql/queries.ts index 0d72c165d..9f7a02e70 100644 --- a/backend/src/seeds/graphql/queries.ts +++ b/backend/src/seeds/graphql/queries.ts @@ -198,8 +198,8 @@ export const listContributions = gql` export const listAllContributions = ` query ($currentPage: Int = 1, $pageSize: Int = 5, $order: Order = DESC) { listAllContributions(currentPage: $currentPage, pageSize: $pageSize, order: $order) { - linkCount - linkList { + contributionCount + contributionList { id firstName lastName From a25d9f73991199607022911f5e450794ad79e2fe Mon Sep 17 00:00:00 2001 From: elweyn Date: Mon, 18 Jul 2022 11:38:58 +0200 Subject: [PATCH 070/977] Change query fields to new names. --- .../resolver/ContributionResolver.test.ts | 48 +++++++++++-------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index e6478ffc2..37ff45f25 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -193,18 +193,21 @@ describe('ContributionResolver', () => { ).resolves.toEqual( expect.objectContaining({ data: { - listContributions: expect.arrayContaining([ - expect.objectContaining({ - id: expect.any(Number), - memo: 'Herzlich Willkommen bei Gradido!', - amount: '1000', - }), - expect.objectContaining({ - id: expect.any(Number), - memo: 'Test env contribution', - amount: '100', - }), - ]), + listContributions: { + contributionCount: 2, + contributionList: expect.arrayContaining([ + expect.objectContaining({ + id: expect.any(Number), + memo: 'Herzlich Willkommen bei Gradido!', + amount: '1000', + }), + expect.objectContaining({ + id: expect.any(Number), + memo: 'Test env contribution', + amount: '100', + }), + ]), + }, }, }), ) @@ -226,13 +229,16 @@ describe('ContributionResolver', () => { ).resolves.toEqual( expect.objectContaining({ data: { - listContributions: expect.arrayContaining([ - expect.objectContaining({ - id: expect.any(Number), - memo: 'Test env contribution', - amount: '100', - }), - ]), + listContributions: { + contributionCount: 1, + contributionList: expect.arrayContaining([ + expect.objectContaining({ + id: expect.any(Number), + memo: 'Test env contribution', + amount: '100', + }), + ]), + }, }, }), ) @@ -496,8 +502,8 @@ describe('ContributionResolver', () => { expect.objectContaining({ data: { listAllContributions: { - linkCount: 2, - linkList: expect.arrayContaining([ + contributionCount: 2, + contributionList: expect.arrayContaining([ expect.objectContaining({ id: expect.any(Number), memo: 'Herzlich Willkommen bei Gradido!', From 93856482853f2f5c00c21ee0857993b7612a8875 Mon Sep 17 00:00:00 2001 From: elweyn Date: Mon, 18 Jul 2022 11:39:17 +0200 Subject: [PATCH 071/977] Remove unused import. --- backend/src/graphql/resolver/ContributionResolver.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index c834904d6..f21c65068 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -2,7 +2,6 @@ import { RIGHTS } from '@/auth/RIGHTS' import { Context, getUser } from '@/server/context' import { backendLogger as logger } from '@/server/logger' import { Contribution as dbContribution } from '@entity/Contribution' -import { User as dbUser } from '@entity/User' import { Arg, Args, Authorized, Ctx, Int, Mutation, Query, Resolver } from 'type-graphql' import { FindOperator, IsNull } from '@dbTools/typeorm' import ContributionArgs from '@arg/ContributionArgs' From 70a8f9b0ca06da047b9c645046bb4fff4e75132f Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 18 Jul 2022 11:50:07 +0200 Subject: [PATCH 072/977] change query to get contributionCount and contributionList --- .../Contributions/ContributionList.vue | 2 +- frontend/src/graphql/queries.js | 18 +++++++++++------- frontend/src/pages/Community.vue | 4 ++-- 3 files changed, 14 insertions(+), 10 deletions(-) diff --git a/frontend/src/components/Contributions/ContributionList.vue b/frontend/src/components/Contributions/ContributionList.vue index c08d22c79..f5aa536ba 100644 --- a/frontend/src/components/Contributions/ContributionList.vue +++ b/frontend/src/components/Contributions/ContributionList.vue @@ -1,6 +1,6 @@
@@ -145,6 +150,8 @@ export default { .then((result) => { this.$emit('set-tunneled-email', null) this.link = result.data.createTransactionLink.link + this.amount = this.transactionData.amount + this.memo = this.transactionData.memo this.transactionData = { ...EMPTY_TRANSACTION_DATA } this.currentTransactionStep = TRANSACTION_STEPS.transactionResultLink this.updateTransactions({}) From ae6c83becfa55fddcd8ce0e7c92c169f505a311c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Wed, 27 Jul 2022 00:34:50 +0200 Subject: [PATCH 196/977] add two variants to store a deny of a contribution --- .../UC_Contribution_Messaging.md | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/docu/Concepts/BusinessRequirements/UC_Contribution_Messaging.md b/docu/Concepts/BusinessRequirements/UC_Contribution_Messaging.md index ba54e631e..98ef7bd68 100644 --- a/docu/Concepts/BusinessRequirements/UC_Contribution_Messaging.md +++ b/docu/Concepts/BusinessRequirements/UC_Contribution_Messaging.md @@ -74,6 +74,16 @@ Mit diesem Service werden alle Contributions aber keine Messages, aller User gel Mit diesem Service kann eine Contribution im Status "eingereicht" und nur vom Ersteller selbst gelöscht werden. Dabei wird nur ein SoftDelete durchgeführt, indem das deletedAt-Datum auf den aktuellen Zeitpunkt gesetzt wird. +### confirmContribution + +Über diesen Service kann der Moderator im AdminInterface eine "eingereichte" Contribution bestätigen. Dabei wird implizit das Attribut "confirmed_by" auf die UserId des Moderators gesetzt und das Attribut "confirmed_at" auf den aktuellen Zeitpunkt. Bei der Migrations-Variante-1 der Contribution-Tabelle wird implizit das Attribut "confirmed_state" auf TRUE gesetzt. + +### denyContribution + +Über diesen Service kann der Moderator im AdminInterface eine "eingereichte" Contribution ablehnen. Dabei wird bei der Migrations-Variante-1 implizit das Attribut "confirmed_by" auf die UserId des Moderators gesetzt, das Attribut "confirmed_at" auf den aktuellen Zeitpunkt und das Attribut "confirmed_state" auf FALSE gesetzt. Zusätzlich gibt der Moderator eine Begründung der Ablehnung ein, die in dem Attribut "denied_reason" gespeichert wird. + +Bei der Migrations-Variante-2 wird bei einer Ablehnung das Attribut "denied_by" auf die UserId des Moderators gesetzt, das Attribut "denied_at" auf den aktuellen Zeitpunkt und in das Attribut "denied_reason" wird die Begründung der Ablehnung gespeichert. Die Attribute "confirmed_by", "confirmed_at" bleiben leer bzw auf null, das Attribut "confirm_state" existiert nicht. + ### searchContributionMessages Dieser Service liefert zu einer bestimmten Contribution alle gespeicherten Nachrichten chronologisch nach dem CreatedAt-Datum absteigend sortiert. Neben dem Nachrichtentext und dem CreatedAt-Datum wird auch der User, der die Nachricht erstellt hat, geliefert. Als User-Daten wird entweder der Vorname und Nachname oder falls vorhanden der Alias geliefert. @@ -92,8 +102,20 @@ Das Class-Diagramm der beteiligten Tabellen gibt einen ersten Eindruck: Die Contribution-Tabelle benötigt für die Confirmation ein zusätzliches Attribut, das das Ergebnis der Confirmation - bestätigt oder abgelehnt - speichert. +#### Variante 1: + confirmed_state: speichert das Ergebnis der Confirmation, das entweder true für bestätigt oder false für abgelehnt +denied_reason: speichert die Begründung der Ablehnung, die der Moderator als Argumentation formuliert + +#### Variante 2: + +denied_at: speichert den Zeitpunkt, wann die Ablehnung erfolgte + +denied_by: speichert die UserId des Moderators, der die Ablehnung durchgeführt hat + +denied_reason: speichert die Begründung der Ablehnung, die der Moderator als Argumentation formuliert + ### ContributionMessages Tabelle -Die ContributionMessages Tabelle ist gänzlich neu. +Die ContributionMessages Tabelle ist gänzlich neu mit allen Attributen. From afd123e133c5f02e4628f3f84fbd5eee13b7373c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Wed, 27 Jul 2022 01:09:55 +0200 Subject: [PATCH 197/977] correct the merge-conflict solving --- docker-compose.override.yml | 124 ------------------------------------ 1 file changed, 124 deletions(-) diff --git a/docker-compose.override.yml b/docker-compose.override.yml index fbd0cd734..f8fde0430 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -1,129 +1,5 @@ version: "3.4" -services: - - ######################################################## - # FRONTEND ############################################# - ######################################################## - frontend: - # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there - image: gradido/frontend:local-development - build: - target: development - environment: - - NODE_ENV="development" - # - DEBUG=true - volumes: - # This makes sure the docker container has its own node modules. - # Therefore it is possible to have a different node version on the host machine - - frontend_node_modules:/app/node_modules - # bind the local folder to the docker to allow live reload - - ./frontend:/app - - ######################################################## - # ADMIN INTERFACE ###################################### - ######################################################## - admin: - # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there - image: gradido/admin:local-development - build: - target: development - environment: - - NODE_ENV="development" - # - DEBUG=true - volumes: - # This makes sure the docker container has its own node modules. - # Therefore it is possible to have a different node version on the host machine - - admin_node_modules:/app/node_modules - # bind the local folder to the docker to allow live reload - - ./admin:/app - - ######################################################## - # BACKEND ############################################## - ######################################################## - backend: - # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there - image: gradido/backend:local-development - build: - target: development - networks: - - external-net - - internal-net - environment: - - NODE_ENV="development" - volumes: - # This makes sure the docker container has its own node modules. - # Therefore it is possible to have a different node version on the host machine - - backend_node_modules:/app/node_modules - - backend_database_node_modules:/database/node_modules - - backend_database_build:/database/build - # bind the local folder to the docker to allow live reload - - ./backend:/app - - ./database:/database - - ######################################################## - # DATABASE ############################################## - ######################################################## - database: - # we always run on production here since else the service lingers - # feel free to change this behaviour if it seems useful - # Due to problems with the volume caching the built files - # we changed this to test build. This keeps the service running. - # name the image so that it cannot be found in a DockerHub repository, otherwise it will not be built locally from the 'dockerfile' but pulled from there - image: gradido/database:local-test_up - build: - target: test_up - environment: - - NODE_ENV="development" - volumes: - # This makes sure the docker container has its own node modules. - # Therefore it is possible to have a different node version on the host machine - - database_node_modules:/app/node_modules - - database_build:/app/build - # bind the local folder to the docker to allow live reload - - ./database:/app - - ######################################################### - ## MARIADB ############################################## - ######################################################### - mariadb: - networks: - - internal-net - - external-net - - ######################################################### - ## NGINX ################################################ - ######################################################### - nginx: - volumes: - - ./logs/nginx:/var/log/nginx - - ######################################################### - ## PHPMYADMIN ########################################### - ######################################################### - phpmyadmin: - image: phpmyadmin - environment: - - PMA_ARBITRARY=1 - #restart: always - ports: - - 8074:80 - networks: - - internal-net - - external-net - volumes: - - /sessions - -volumes: - frontend_node_modules: - admin_node_modules: - backend_node_modules: - backend_database_node_modules: - backend_database_build: - database_node_modules: - database_build: -version: "3.4" - services: ######################################################## From 21c9bc22a710febd6d5d61aa5f43a11933981da5 Mon Sep 17 00:00:00 2001 From: mahula Date: Wed, 27 Jul 2022 10:13:00 +0200 Subject: [PATCH 198/977] adapt existing unit tests for copying a created transaction link --- frontend/src/pages/Send.spec.js | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/frontend/src/pages/Send.spec.js b/frontend/src/pages/Send.spec.js index 47a30ff65..79ba65133 100644 --- a/frontend/src/pages/Send.spec.js +++ b/frontend/src/pages/Send.spec.js @@ -20,6 +20,9 @@ describe('Send', () => { balance: 123.45, GdtBalance: 1234.56, pending: true, + amount: '15', + link: 'http://localhost/redeem/0123456789', + memo: 'Quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet.', } const mocks = { @@ -28,6 +31,7 @@ describe('Send', () => { $store: { state: { email: 'sender@example.org', + firstName: 'Testy', }, }, $apollo: { @@ -228,21 +232,26 @@ describe('Send', () => { navigator.clipboard = navigatorClipboard }) - describe('copy with success', () => { + describe('copy link with success', () => { beforeEach(async () => { navigatorClipboardMock.mockResolvedValue() - await wrapper.findAll('button').at(0).trigger('click') + await wrapper.findAll('button').at(1).trigger('click') }) + it('should call clipboard.writeText', () => { + expect(navigator.clipboard.writeText).toHaveBeenCalledWith( + 'http://localhost/redeem/0123456789', + ) + }) it('toasts success message', () => { expect(toastSuccessSpy).toBeCalledWith('gdd_per_link.link-copied') }) }) - describe('copy with error', () => { + describe('copy link with error', () => { beforeEach(async () => { navigatorClipboardMock.mockRejectedValue() - await wrapper.findAll('button').at(0).trigger('click') + await wrapper.findAll('button').at(1).trigger('click') }) it('toasts error message', () => { @@ -253,7 +262,7 @@ describe('Send', () => { describe('close button click', () => { beforeEach(async () => { - await wrapper.findAll('button').at(2).trigger('click') + await wrapper.findAll('button').at(3).trigger('click') }) it('Shows the TransactionForm', () => { From d1cc3115ba642ae9a20ec6c2af92995f4f050438 Mon Sep 17 00:00:00 2001 From: mahula Date: Wed, 27 Jul 2022 11:07:58 +0200 Subject: [PATCH 199/977] add unit tests for copying a created transaction link with username, amount and memo text --- frontend/src/pages/Send.spec.js | 43 ++++++++++++++++++++++++++++++--- 1 file changed, 40 insertions(+), 3 deletions(-) diff --git a/frontend/src/pages/Send.spec.js b/frontend/src/pages/Send.spec.js index 79ba65133..be63027b1 100644 --- a/frontend/src/pages/Send.spec.js +++ b/frontend/src/pages/Send.spec.js @@ -20,9 +20,6 @@ describe('Send', () => { balance: 123.45, GdtBalance: 1234.56, pending: true, - amount: '15', - link: 'http://localhost/redeem/0123456789', - memo: 'Quis auctor elit sed vulputate mi sit amet mauris commodo quis imperdiet.', } const mocks = { @@ -260,6 +257,46 @@ describe('Send', () => { }) }) + describe('copy link and text with success', () => { + const navigatorClipboard = navigator.clipboard + beforeAll(() => { + delete navigator.clipboard + navigator.clipboard = { writeText: navigatorClipboardMock } + }) + afterAll(() => { + navigator.clipboard = navigatorClipboard + }) + + describe('copy link and text with success', () => { + beforeEach(async () => { + navigatorClipboardMock.mockResolvedValue() + await wrapper.findAll('button').at(0).trigger('click') + }) + + it('should call clipboard.writeText', () => { + expect(navigator.clipboard.writeText).toHaveBeenCalledWith( + 'http://localhost/redeem/0123456789\n' + + 'Testy transaction-link.send_you 56.78 Gradido.\n' + + '"Make the best of the link!"', + ) + }) + it('toasts success message', () => { + expect(toastSuccessSpy).toBeCalledWith('gdd_per_link.link-and-text-copied') + }) + }) + + describe('copy link and text with error', () => { + beforeEach(async () => { + navigatorClipboardMock.mockRejectedValue() + await wrapper.findAll('button').at(0).trigger('click') + }) + + it('toasts error message', () => { + expect(toastErrorSpy).toBeCalledWith('gdd_per_link.not-copied') + }) + }) + }) + describe('close button click', () => { beforeEach(async () => { await wrapper.findAll('button').at(3).trigger('click') From 3c539a6edf0a2136470c12c530965462aaaee339 Mon Sep 17 00:00:00 2001 From: mahula Date: Wed, 27 Jul 2022 11:21:47 +0200 Subject: [PATCH 200/977] make the wording more precise wherever a link can be copied --- frontend/src/components/ClipboardCopy.vue | 4 ++-- frontend/src/components/TransactionLinks/TransactionLink.vue | 4 ++-- frontend/src/locales/de.json | 3 ++- frontend/src/locales/en.json | 4 +++- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/frontend/src/components/ClipboardCopy.vue b/frontend/src/components/ClipboardCopy.vue index 78af3c772..efddf8ab3 100644 --- a/frontend/src/components/ClipboardCopy.vue +++ b/frontend/src/components/ClipboardCopy.vue @@ -4,10 +4,10 @@ - {{ $t('gdd_per_link.copy-with-text') }} + {{ $t('gdd_per_link.copy-link-with-text') }} - {{ $t('gdd_per_link.copy') }} + {{ $t('gdd_per_link.copy-link') }} diff --git a/frontend/src/components/TransactionLinks/TransactionLink.vue b/frontend/src/components/TransactionLinks/TransactionLink.vue index 5618c8696..fe5e44658 100644 --- a/frontend/src/components/TransactionLinks/TransactionLink.vue +++ b/frontend/src/components/TransactionLinks/TransactionLink.vue @@ -20,7 +20,7 @@ - {{ $t('gdd_per_link.copy') }} + {{ $t('gdd_per_link.copy-link') }} - {{ $t('gdd_per_link.copy-with-text') }} + {{ $t('gdd_per_link.copy-link-with-text') }} Date: Wed, 27 Jul 2022 12:17:04 +0200 Subject: [PATCH 201/977] fix linting and locales --- frontend/src/locales/de.json | 1 - frontend/src/locales/en.json | 2 -- 2 files changed, 3 deletions(-) diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index aebbffab2..91e602990 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -150,7 +150,6 @@ "GDD": "GDD", "gdd_per_link": { "choose-amount": "Wähle einen Betrag aus, welchen du per Link versenden möchtest. Du kannst auch noch eine Nachricht eintragen. Beim Klick „Jetzt generieren“ wird ein Link erstellt, den du versenden kannst.", - "copy": "kopieren", "copy-link": "Link kopieren", "copy-link-with-text": "Link und Text kopieren", "created": "Der Link wurde erstellt!", diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index 4ace4e10b..fcd604fea 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -12,7 +12,6 @@ "hasAccount": "You already have an account?", "hereLogin": "Log in here", "learnMore": "Learn more …", - "oneDignity": "We gift to each other and give thanks with Gradido.", "oneDonation": "You are a gift for the community. 1000 thanks because you are with us.", "oneGratitude": "For each other, for all people, for nature." @@ -151,7 +150,6 @@ "GDD": "GDD", "gdd_per_link": { "choose-amount": "Select an amount that you would like to send via link. You can also enter a message. Click 'Generate now' to create a link that you can share.", - "copy": "copy", "copy-link": "Copy link", "copy-link-with-text": "Copy link and text", "created": "Link was created!", From dff0853bc7c55813b769e4f63431dc5d011240aa Mon Sep 17 00:00:00 2001 From: mahula Date: Wed, 27 Jul 2022 14:38:53 +0200 Subject: [PATCH 202/977] remove member area from menu, if user has no elopage account --- frontend/src/components/Menu/Sidebar.vue | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/frontend/src/components/Menu/Sidebar.vue b/frontend/src/components/Menu/Sidebar.vue index b54eb541e..a8850ed18 100644 --- a/frontend/src/components/Menu/Sidebar.vue +++ b/frontend/src/components/Menu/Sidebar.vue @@ -27,12 +27,9 @@
- + {{ $t('navigation.members_area') }} - - {{ $t('math.exclaim') }} - From 2c07ec98ab77f3c04adcdf80e3c42d9bc132a633 Mon Sep 17 00:00:00 2001 From: mahula Date: Wed, 27 Jul 2022 21:06:49 +0200 Subject: [PATCH 203/977] remove the member area entry from the footer and adjust the unit tests accordingly --- frontend/src/components/ContentFooter.spec.js | 24 ++++--------------- frontend/src/components/ContentFooter.vue | 6 ----- 2 files changed, 4 insertions(+), 26 deletions(-) diff --git a/frontend/src/components/ContentFooter.spec.js b/frontend/src/components/ContentFooter.spec.js index f67560e44..c578d3fac 100644 --- a/frontend/src/components/ContentFooter.spec.js +++ b/frontend/src/components/ContentFooter.spec.js @@ -97,24 +97,14 @@ describe('ContentFooter', () => { ) }) - it('has a link to the members area', () => { - expect(wrapper.findAll('a.nav-link').at(2).text()).toEqual('navigation.members_area') - }) - - it('links to the elopage', () => { - expect(wrapper.findAll('a.nav-link').at(2).attributes('href')).toEqual( - 'https://elopage.com/s/gradido/sign_in?locale=en', - ) - }) - it('links to the whitepaper', () => { - expect(wrapper.findAll('a.nav-link').at(3).attributes('href')).toEqual( + expect(wrapper.findAll('a.nav-link').at(2).attributes('href')).toEqual( 'https://docs.google.com/document/d/1kcX1guOi6tDgnFHD9tf7fB_MneKTx-0nHJxzdN8ygNs/edit?usp=sharing', ) }) it('links to the support', () => { - expect(wrapper.findAll('a.nav-link').at(4).attributes('href')).toEqual( + expect(wrapper.findAll('a.nav-link').at(3).attributes('href')).toEqual( 'https://gradido.net/en/contact/', ) }) @@ -142,20 +132,14 @@ describe('ContentFooter', () => { ) }) - it('links to the German elopage when locale is de', () => { - expect(wrapper.findAll('a.nav-link').at(2).attributes('href')).toEqual( - 'https://elopage.com/s/gradido/sign_in?locale=de', - ) - }) - it('links to the German whitepaper when locale is de', () => { - expect(wrapper.findAll('a.nav-link').at(3).attributes('href')).toEqual( + expect(wrapper.findAll('a.nav-link').at(2).attributes('href')).toEqual( 'https://docs.google.com/document/d/1jZp-DiiMPI9ZPNXmjsvOQ1BtnfDFfx8BX7CDmA8KKjY/edit?usp=sharing', ) }) it('links to the German support-page when locale is de', () => { - expect(wrapper.findAll('a.nav-link').at(4).attributes('href')).toEqual( + expect(wrapper.findAll('a.nav-link').at(3).attributes('href')).toEqual( 'https://gradido.net/de/contact/', ) }) diff --git a/frontend/src/components/ContentFooter.vue b/frontend/src/components/ContentFooter.vue index bdcb5b1a9..c563cc23d 100755 --- a/frontend/src/components/ContentFooter.vue +++ b/frontend/src/components/ContentFooter.vue @@ -34,12 +34,6 @@ {{ $t('footer.privacy_policy') }} - - {{ $t('navigation.members_area') }} - { expect(wrapper.findAll('.nav-item').at(6).text()).toEqual('navigation.profile') }) - + }) + describe('navigation Navbar (user has an elopage account)', () => { it('has a link to the members area', () => { expect(wrapper.findAll('.nav-item').at(7).text()).toContain('navigation.members_area') expect(wrapper.findAll('.nav-item').at(7).find('a').attributes('href')).toBe( @@ -81,6 +82,18 @@ describe('Navbar', () => { expect(wrapper.findAll('.nav-item').at(9).text()).toEqual('navigation.logout') }) }) + describe('navigation Navbar (user has no elopage account)', () => { + beforeAll(() => { + mocks.$store.state.hasElopage = false + wrapper = Wrapper() + }) + it('has first nav-item "navigation.admin_area" in navbar', () => { + expect(wrapper.findAll('.nav-item').at(7).text()).toEqual('navigation.admin_area') + }) + it('has first nav-item "navigation.logout" in navbar', () => { + expect(wrapper.findAll('.nav-item').at(8).text()).toEqual('navigation.logout') + }) + }) }) describe('check watch visible true', () => { beforeEach(async () => { diff --git a/frontend/src/components/Menu/Navbar.vue b/frontend/src/components/Menu/Navbar.vue index 2f26f381e..d8fc942fe 100644 --- a/frontend/src/components/Menu/Navbar.vue +++ b/frontend/src/components/Menu/Navbar.vue @@ -57,12 +57,9 @@ {{ $t('navigation.profile') }}
- + {{ $t('navigation.members_area') }} - - {{ $t('math.exclaim') }} - From 7fdba919ca93655d06844c96f9578ee324c2efac Mon Sep 17 00:00:00 2001 From: mahula Date: Wed, 27 Jul 2022 22:16:17 +0200 Subject: [PATCH 205/977] fix removal of exclamation mark in navbar --- frontend/src/components/Menu/Navbar.vue | 3 +++ 1 file changed, 3 insertions(+) diff --git a/frontend/src/components/Menu/Navbar.vue b/frontend/src/components/Menu/Navbar.vue index d8fc942fe..1c49a1aa3 100644 --- a/frontend/src/components/Menu/Navbar.vue +++ b/frontend/src/components/Menu/Navbar.vue @@ -60,6 +60,9 @@ {{ $t('navigation.members_area') }} + + {{ $t('math.exclaim') }} + From 67453c8a27ec60ee677e724c6a671aef09d76246 Mon Sep 17 00:00:00 2001 From: mahula Date: Wed, 27 Jul 2022 22:16:53 +0200 Subject: [PATCH 206/977] remove the member area entry from sidebar menu and adjust the unit tests accordingly --- frontend/src/components/Menu/Sidebar.spec.js | 28 +++++++++++++++----- frontend/src/components/Menu/Sidebar.vue | 10 ++++++- 2 files changed, 31 insertions(+), 7 deletions(-) diff --git a/frontend/src/components/Menu/Sidebar.spec.js b/frontend/src/components/Menu/Sidebar.spec.js index f6051c733..dd9511562 100644 --- a/frontend/src/components/Menu/Sidebar.spec.js +++ b/frontend/src/components/Menu/Sidebar.spec.js @@ -31,11 +31,7 @@ describe('Sidebar', () => { expect(wrapper.find('div#component-sidebar').exists()).toBeTruthy() }) - describe('navigation Navbar', () => { - it('has seven b-nav-item in the navbar', () => { - expect(wrapper.findAll('.nav-item')).toHaveLength(8) - }) - + describe('navigation Navbar (general elements)', () => { it('has first nav-item "navigation.overview" in navbar', () => { expect(wrapper.findAll('.nav-item').at(0).text()).toEqual('navigation.overview') }) @@ -55,7 +51,12 @@ describe('Sidebar', () => { it('has first nav-item "navigation.profile" in navbar', () => { expect(wrapper.findAll('.nav-item').at(4).text()).toEqual('navigation.profile') }) - + }) + // ---- + describe('navigation Navbar (user has an elopage account)', () => { + it('has seven b-nav-item in the navbar', () => { + expect(wrapper.findAll('.nav-item')).toHaveLength(8) + }) it('has a link to the members area', () => { expect(wrapper.findAll('.nav-item').at(5).text()).toEqual('navigation.members_area') expect(wrapper.findAll('.nav-item').at(5).find('a').attributes('href')).toBe('#') @@ -69,5 +70,20 @@ describe('Sidebar', () => { expect(wrapper.findAll('.nav-item').at(7).text()).toEqual('navigation.logout') }) }) + describe('navigation Navbar (user has no elopage account)', () => { + beforeAll(() => { + mocks.$store.state.hasElopage = false + wrapper = Wrapper() + }) + it('has six b-nav-item in the navbar', () => { + expect(wrapper.findAll('.nav-item')).toHaveLength(7) + }) + it('has first nav-item "navigation.admin_area" in navbar', () => { + expect(wrapper.findAll('.nav-item').at(5).text()).toEqual('navigation.admin_area') + }) + it('has first nav-item "navigation.logout" in navbar', () => { + expect(wrapper.findAll('.nav-item').at(6).text()).toEqual('navigation.logout') + }) + }) }) }) diff --git a/frontend/src/components/Menu/Sidebar.vue b/frontend/src/components/Menu/Sidebar.vue index a8850ed18..0cdab31c3 100644 --- a/frontend/src/components/Menu/Sidebar.vue +++ b/frontend/src/components/Menu/Sidebar.vue @@ -27,9 +27,17 @@

- + {{ $t('navigation.members_area') }} + + {{ $t('math.exclaim') }} + From bb120b8b82f9c25f5caa39cdd81064c1a36e4dc9 Mon Sep 17 00:00:00 2001 From: mahula Date: Thu, 28 Jul 2022 08:39:31 +0200 Subject: [PATCH 207/977] improve unit test structure for better readability --- frontend/src/components/Menu/Navbar.spec.js | 11 +++++++++++ frontend/src/components/Menu/Sidebar.spec.js | 8 +++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/Menu/Navbar.spec.js b/frontend/src/components/Menu/Navbar.spec.js index ef39fdc0e..109190e39 100644 --- a/frontend/src/components/Menu/Navbar.spec.js +++ b/frontend/src/components/Menu/Navbar.spec.js @@ -43,9 +43,11 @@ describe('Navbar', () => { it('has .navbar-brand in the navbar', () => { expect(wrapper.find('.navbar-brand').exists()).toBeTruthy() }) + it('has b-navbar-toggle in the navbar', () => { expect(wrapper.find('.navbar-toggler').exists()).toBeTruthy() }) + it('has ten b-nav-item in the navbar', () => { expect(wrapper.findAll('.nav-item')).toHaveLength(10) }) @@ -57,16 +59,20 @@ describe('Navbar', () => { it('has first nav-item "navigation.overview" in navbar', () => { expect(wrapper.findAll('.nav-item').at(3).text()).toEqual('navigation.overview') }) + it('has first nav-item "navigation.send" in navbar', () => { expect(wrapper.findAll('.nav-item').at(4).text()).toEqual('navigation.send') }) + it('has first nav-item "navigation.transactions" in navbar', () => { expect(wrapper.findAll('.nav-item').at(5).text()).toEqual('navigation.transactions') }) + it('has first nav-item "navigation.profile" in navbar', () => { expect(wrapper.findAll('.nav-item').at(6).text()).toEqual('navigation.profile') }) }) + describe('navigation Navbar (user has an elopage account)', () => { it('has a link to the members area', () => { expect(wrapper.findAll('.nav-item').at(7).text()).toContain('navigation.members_area') @@ -78,23 +84,28 @@ describe('Navbar', () => { it('has first nav-item "navigation.admin_area" in navbar', () => { expect(wrapper.findAll('.nav-item').at(8).text()).toEqual('navigation.admin_area') }) + it('has first nav-item "navigation.logout" in navbar', () => { expect(wrapper.findAll('.nav-item').at(9).text()).toEqual('navigation.logout') }) }) + describe('navigation Navbar (user has no elopage account)', () => { beforeAll(() => { mocks.$store.state.hasElopage = false wrapper = Wrapper() }) + it('has first nav-item "navigation.admin_area" in navbar', () => { expect(wrapper.findAll('.nav-item').at(7).text()).toEqual('navigation.admin_area') }) + it('has first nav-item "navigation.logout" in navbar', () => { expect(wrapper.findAll('.nav-item').at(8).text()).toEqual('navigation.logout') }) }) }) + describe('check watch visible true', () => { beforeEach(async () => { await wrapper.setProps({ visible: true }) diff --git a/frontend/src/components/Menu/Sidebar.spec.js b/frontend/src/components/Menu/Sidebar.spec.js index dd9511562..7be68363b 100644 --- a/frontend/src/components/Menu/Sidebar.spec.js +++ b/frontend/src/components/Menu/Sidebar.spec.js @@ -27,6 +27,7 @@ describe('Sidebar', () => { beforeEach(() => { wrapper = Wrapper() }) + it('renders the component', () => { expect(wrapper.find('div#component-sidebar').exists()).toBeTruthy() }) @@ -52,11 +53,12 @@ describe('Sidebar', () => { expect(wrapper.findAll('.nav-item').at(4).text()).toEqual('navigation.profile') }) }) - // ---- + describe('navigation Navbar (user has an elopage account)', () => { it('has seven b-nav-item in the navbar', () => { expect(wrapper.findAll('.nav-item')).toHaveLength(8) }) + it('has a link to the members area', () => { expect(wrapper.findAll('.nav-item').at(5).text()).toEqual('navigation.members_area') expect(wrapper.findAll('.nav-item').at(5).find('a').attributes('href')).toBe('#') @@ -70,17 +72,21 @@ describe('Sidebar', () => { expect(wrapper.findAll('.nav-item').at(7).text()).toEqual('navigation.logout') }) }) + describe('navigation Navbar (user has no elopage account)', () => { beforeAll(() => { mocks.$store.state.hasElopage = false wrapper = Wrapper() }) + it('has six b-nav-item in the navbar', () => { expect(wrapper.findAll('.nav-item')).toHaveLength(7) }) + it('has first nav-item "navigation.admin_area" in navbar', () => { expect(wrapper.findAll('.nav-item').at(5).text()).toEqual('navigation.admin_area') }) + it('has first nav-item "navigation.logout" in navbar', () => { expect(wrapper.findAll('.nav-item').at(6).text()).toEqual('navigation.logout') }) From a41385141902b7611c7fbde289d68cc3d2fe4c6b Mon Sep 17 00:00:00 2001 From: mahula Date: Thu, 28 Jul 2022 08:50:26 +0200 Subject: [PATCH 208/977] specify the wording of the unit tests regarding the number of nav items --- frontend/src/components/Menu/Sidebar.spec.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/Menu/Sidebar.spec.js b/frontend/src/components/Menu/Sidebar.spec.js index 7be68363b..1593a79a8 100644 --- a/frontend/src/components/Menu/Sidebar.spec.js +++ b/frontend/src/components/Menu/Sidebar.spec.js @@ -55,7 +55,7 @@ describe('Sidebar', () => { }) describe('navigation Navbar (user has an elopage account)', () => { - it('has seven b-nav-item in the navbar', () => { + it('has eight b-nav-item in the navbar', () => { expect(wrapper.findAll('.nav-item')).toHaveLength(8) }) @@ -79,7 +79,7 @@ describe('Sidebar', () => { wrapper = Wrapper() }) - it('has six b-nav-item in the navbar', () => { + it('has seven b-nav-item in the navbar', () => { expect(wrapper.findAll('.nav-item')).toHaveLength(7) }) From 6f081c4cc941ea6a242d17b2986d8cd98f6513da Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 28 Jul 2022 11:12:17 +0200 Subject: [PATCH 209/977] fix: Use Inner Join for Contribution and User --- .../graphql/resolver/ContributionResolver.ts | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index a22715fb4..3307252e4 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -3,7 +3,7 @@ import { Context, getUser } from '@/server/context' import { backendLogger as logger } from '@/server/logger' import { Contribution as dbContribution } from '@entity/Contribution' import { Arg, Args, Authorized, Ctx, Int, Mutation, Query, Resolver } from 'type-graphql' -import { FindOperator, IsNull } from '@dbTools/typeorm' +import { FindOperator, IsNull, getConnection } from '@dbTools/typeorm' import ContributionArgs from '@arg/ContributionArgs' import Paginated from '@arg/Paginated' import { Order } from '@enum/Order' @@ -106,14 +106,15 @@ export class ContributionResolver { @Args() { currentPage = 1, pageSize = 5, order = Order.DESC }: Paginated, ): Promise { - const [dbContributions, count] = await dbContribution.findAndCount({ - relations: ['user'], - order: { - createdAt: order, - }, - skip: (currentPage - 1) * pageSize, - take: pageSize, - }) + const [dbContributions, count] = await getConnection() + .createQueryBuilder() + .select('c') + .from(dbContribution, 'c') + .innerJoinAndSelect('c.user', 'u') + .orderBy('c.createdAt', order) + .limit(pageSize) + .offset((currentPage - 1) * pageSize) + .getManyAndCount() return new ContributionListResult( count, dbContributions.map( From 2d80c7029eae75fbda6c925cc8b0e5b54ef41e17 Mon Sep 17 00:00:00 2001 From: mahula Date: Thu, 28 Jul 2022 13:06:42 +0200 Subject: [PATCH 210/977] including validation date infos to link copying after transaction link creation - adapt transaction link creation mutation to get the validation date - add validation date and text to link copy - utilize mixins to avoid code doubling --- frontend/src/components/ClipboardCopy.vue | 42 ++----------------- .../GddSend/TransactionResultLink.vue | 4 +- frontend/src/graphql/mutations.js | 3 ++ frontend/src/pages/Send.vue | 13 ++++-- 4 files changed, 19 insertions(+), 43 deletions(-) diff --git a/frontend/src/components/ClipboardCopy.vue b/frontend/src/components/ClipboardCopy.vue index efddf8ab3..66e47a264 100644 --- a/frontend/src/components/ClipboardCopy.vue +++ b/frontend/src/components/ClipboardCopy.vue @@ -6,7 +6,7 @@ {{ $t('gdd_per_link.copy-link-with-text') }} - + {{ $t('gdd_per_link.copy-link') }} @@ -21,46 +21,10 @@ diff --git a/admin/src/components/ContributionMessages/slots/ContributionMessagesListItem.vue b/admin/src/components/ContributionMessages/slots/ContributionMessagesListItem.vue new file mode 100644 index 000000000..74d349d12 --- /dev/null +++ b/admin/src/components/ContributionMessages/slots/ContributionMessagesListItem.vue @@ -0,0 +1,16 @@ + + diff --git a/admin/src/components/ContributionMessages/slots/IsModerator.vue b/admin/src/components/ContributionMessages/slots/IsModerator.vue new file mode 100644 index 000000000..1fd284b65 --- /dev/null +++ b/admin/src/components/ContributionMessages/slots/IsModerator.vue @@ -0,0 +1,27 @@ + + + diff --git a/admin/src/components/ContributionMessages/slots/IsNotModerator.vue b/admin/src/components/ContributionMessages/slots/IsNotModerator.vue new file mode 100644 index 000000000..8554fdcf1 --- /dev/null +++ b/admin/src/components/ContributionMessages/slots/IsNotModerator.vue @@ -0,0 +1,33 @@ + + + diff --git a/admin/src/components/Tables/OpenCreationsTable.vue b/admin/src/components/Tables/OpenCreationsTable.vue index 2b8956206..649435798 100644 --- a/admin/src/components/Tables/OpenCreationsTable.vue +++ b/admin/src/components/Tables/OpenCreationsTable.vue @@ -51,12 +51,7 @@ />
- -
-
-
-
@@ -69,7 +64,7 @@ import { toggleRowDetails } from '../../mixins/toggleRowDetails' import RowDetails from '../RowDetails.vue' import EditCreationFormular from '../EditCreationFormular.vue' -import ContributionMessagesFormular from '../ContributionMessages/ContributionMessagesFormular.vue' + import ContributionMessagesList from '../ContributionMessages/ContributionMessagesList.vue' export default { @@ -78,7 +73,6 @@ export default { components: { EditCreationFormular, RowDetails, - ContributionMessagesFormular, ContributionMessagesList, }, props: { From 2a093c234f59294423ddb8b44b980d5c508d2726 Mon Sep 17 00:00:00 2001 From: ogerly Date: Thu, 18 Aug 2022 15:28:50 +0200 Subject: [PATCH 467/977] fix lint --- .../components/ContributionMessages/ContributionMessagesList.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/admin/src/components/ContributionMessages/ContributionMessagesList.vue b/admin/src/components/ContributionMessages/ContributionMessagesList.vue index 409ceb6b1..65484b14e 100644 --- a/admin/src/components/ContributionMessages/ContributionMessagesList.vue +++ b/admin/src/components/ContributionMessages/ContributionMessagesList.vue @@ -1,7 +1,6 @@ diff --git a/admin/src/components/ContributionMessages/slots/ContributionMessagesListItem.vue b/admin/src/components/ContributionMessages/slots/ContributionMessagesListItem.vue index 74d349d12..a1d9565c0 100644 --- a/admin/src/components/ContributionMessages/slots/ContributionMessagesListItem.vue +++ b/admin/src/components/ContributionMessages/slots/ContributionMessagesListItem.vue @@ -1,15 +1,37 @@ diff --git a/frontend/src/components/ContributionMessages/ContributionMessagesList.vue b/frontend/src/components/ContributionMessages/ContributionMessagesList.vue index c8d53868d..f8130f2bc 100644 --- a/frontend/src/components/ContributionMessages/ContributionMessagesList.vue +++ b/frontend/src/components/ContributionMessages/ContributionMessagesList.vue @@ -5,12 +5,11 @@ -
-
-
@@ -38,6 +37,11 @@ export default { required: true, }, }, + methods: { + toggleContributionMessagesBox(id) { + this.$emit('toggle-contribution-messages-box', id) + }, + }, } diff --git a/frontend/src/components/Contributions/ContributionListItem.vue b/frontend/src/components/Contributions/ContributionListItem.vue index 7e17ecbb5..be19822d2 100644 --- a/frontend/src/components/Contributions/ContributionListItem.vue +++ b/frontend/src/components/Contributions/ContributionListItem.vue @@ -2,55 +2,64 @@
-
-
-
{{ firstName }} {{ lastName }}
-
- {{ amount | GDD }} +
+
+
+ + +
+
{{ firstName }} {{ lastName }}
+
+ {{ amount | GDD }} +
+ {{ $t('math.minus') }} +
{{ $d(new Date(date), 'short') }}
- {{ $t('math.minus') }} -
{{ $d(new Date(date), 'short') }}
-
-
- {{ $t('contribution.date') }} - - {{ $d(new Date(contributionDate), 'monthAndYear') }} - -
-
{{ memo }}
-
+
+ {{ $t('contribution.date') }} + + {{ $d(new Date(contributionDate), 'monthAndYear') }} + +
+
{{ memo }}
- -
-
- -
-
- +
+ +
+
+ +
+
+ +
- - - Bitte beantworte die Nachfrage + + {{ $t('contribution.alert.answerQuestion') }} @@ -58,6 +67,7 @@ :messages="messages" :state="state" :contributionId="contributionId" + @toggle-contribution-messages-box="toggleContributionMessagesBox" /> @@ -140,6 +150,7 @@ export default { variant() { if (this.deletedAt) return 'danger' if (this.confirmedAt) return 'success' + if (this.state === 'IN_PROGRESS') return 'warning' return 'primary' }, date() { @@ -155,6 +166,9 @@ export default { if (value) this.$emit('delete-contribution', item) }) }, + toggleContributionMessagesBox(id) { + alert('toggleContributionMessagesBox(' + id + ')') + }, }, } diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index b107ca612..bbdc9886a 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -38,9 +38,10 @@ "communityNoteList": "Hier findest du alle eingereichten und bestätigten Beiträge von allen Mitgliedern aus dieser Gemeinschaft.", "confirm": "bestätigt", "myContributionNoteList": "Eingereichte Beiträge, die noch nicht bestätigt wurden, kannst du jederzeit bearbeiten oder löschen.", - "myContributionNoteSupport": "Es wird bald an dieser Stelle die Möglichkeit geben das ein Dialog zwischen Moderatoren und dir stattfinden kann. Solltest du jetzt Probleme haben bitte nimm Kontakt mit dem Support auf.", "pending": "Eingereicht und wartet auf Bestätigung", - "rejected": "abgelehnt" + "rejected": "abgelehnt", + "in_progress":"Es gibt eine Rückfrage der Moderatoren.", + "answerQuestion": "Bitte beantworte die Nachfrage" }, "date": "Beitrag für:", "delete": "Beitrag löschen! Bist du sicher?", diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index 2b1eb492e..4f7830f65 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -38,9 +38,10 @@ "communityNoteList": "Here you will find all submitted and confirmed contributions from all members of this community.", "confirm": "confirmed", "myContributionNoteList": "You can edit or delete entries that have not yet been confirmed at any time.", - "myContributionNoteSupport": "Soon there will be the possibility for a dialogue between moderators and you. If you have any problems now, please contact the support.", "pending": "Submitted and waiting for confirmation", - "rejected": "deleted" + "rejected": "deleted", + "in_progress":"Es gibt eine Rückfrage der Moderatoren.", + "answerQuestion": "Please answer the question" }, "date": "Contribution for:", "delete": "Delete Contribution! Are you sure?", diff --git a/frontend/src/locales/es.json b/frontend/src/locales/es.json index df32c3729..ffec649ed 100644 --- a/frontend/src/locales/es.json +++ b/frontend/src/locales/es.json @@ -38,9 +38,10 @@ "communityNoteList": "Aquí encontrarás todas las contribuciones enviadas y confirmadas de todos los miembros de esta comunidad.", "confirm": "confirmado", "myContributionNoteList": "Puedes editar o eliminar las contribuciones enviadas que aún no han sido confirmadas en cualquier momento.", - "myContributionNoteSupport": "Pronto existirá la posibilidad de que puedas dialogar con los moderadores. Si tienes algún problema ahora, ponte en contacto con el equipo de asistencia.", "pending": "Enviado y a la espera de confirmación", - "rejected": "rechazado" + "rejected": "rechazado", + "in_progress":"Es gibt eine Rückfrage der Moderatoren.", + "answerQuestion": "Please answer the question" }, "date": "Contribución para:", "delete": "Eliminar la contribución. ¿Estás seguro?", diff --git a/frontend/src/locales/fr.json b/frontend/src/locales/fr.json index c8a25d2fb..b1ff773d0 100644 --- a/frontend/src/locales/fr.json +++ b/frontend/src/locales/fr.json @@ -38,9 +38,10 @@ "communityNoteList": "Vous trouverez ci-contre toutes les contributions versées et certifiées de tous les membres de cette communauté.", "confirm": " Approuvé", "myContributionNoteList": "À tout moment vous pouvez éditer ou supprimer les données qui n´ont pas été confirmées.", - "myContributionNoteSupport": "Vous aurez bientôt la possibilité de dialoguer avec un médiateur. Si vous rencontrez un problème maintenant, merci de contacter l´aide en ligne.", "pending": "Inscription en attente de validation", - "rejected": "supprimé" + "rejected": "supprimé", + "in_progress":"Es gibt eine Rückfrage der Moderatoren.", + "answerQuestion": "Please answer the question" }, "date": "Contribution pour:", "delete": "Supprimer la contribution! Êtes-vous sûr?", diff --git a/frontend/src/locales/nl.json b/frontend/src/locales/nl.json index fe0e83839..edb2ec21b 100644 --- a/frontend/src/locales/nl.json +++ b/frontend/src/locales/nl.json @@ -38,9 +38,10 @@ "communityNoteList": "Hier vind je alle ingediende en bevestigde bijdragen van alle leden uit deze gemeenschap.", "confirm": "bevestigt", "myContributionNoteList": "Ingediende bijdragen, die nog niet bevestigd zijn, kun je op elk moment wijzigen of verwijderen.", - "myContributionNoteSupport": "Hier heb je binnenkort de mogelijkheid een gesprek met een moderator te voeren. Mocht je nu problemen hebben, dan neem alsjeblieft contact op met Support.", "pending": "Ingediend en wacht op bevestiging", - "rejected": "afgewezen" + "rejected": "afgewezen", + "in_progress":"Es gibt eine Rückfrage der Moderatoren.", + "answerQuestion": "Please answer the question" }, "date": "Bijdrage voor:", "delete": "Bijdrage verwijderen! Weet je het zeker?", diff --git a/frontend/src/pages/Community.vue b/frontend/src/pages/Community.vue index 64aca6156..5f9eb57f6 100644 --- a/frontend/src/pages/Community.vue +++ b/frontend/src/pages/Community.vue @@ -22,6 +22,10 @@ {{ $t('contribution.alert.pending') }} +
  • + + {{ $t('contribution.alert.in_progress') }} +
  • {{ $t('contribution.alert.confirm') }} @@ -32,9 +36,6 @@

  • -

    - {{ $t('contribution.alert.myContributionNoteSupport') }} -

    Date: Thu, 25 Aug 2022 18:46:16 +0200 Subject: [PATCH 580/977] fix lint && fix locales --- frontend/src/locales/de.json | 2 +- frontend/src/locales/en.json | 2 +- frontend/src/locales/es.json | 2 +- frontend/src/locales/fr.json | 2 +- frontend/src/locales/nl.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index bbdc9886a..1296616d3 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -40,7 +40,7 @@ "myContributionNoteList": "Eingereichte Beiträge, die noch nicht bestätigt wurden, kannst du jederzeit bearbeiten oder löschen.", "pending": "Eingereicht und wartet auf Bestätigung", "rejected": "abgelehnt", - "in_progress":"Es gibt eine Rückfrage der Moderatoren.", + "in_progress": "Es gibt eine Rückfrage der Moderatoren.", "answerQuestion": "Bitte beantworte die Nachfrage" }, "date": "Beitrag für:", diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index 4f7830f65..ee31350ce 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -40,7 +40,7 @@ "myContributionNoteList": "You can edit or delete entries that have not yet been confirmed at any time.", "pending": "Submitted and waiting for confirmation", "rejected": "deleted", - "in_progress":"Es gibt eine Rückfrage der Moderatoren.", + "in_progress": "Es gibt eine Rückfrage der Moderatoren.", "answerQuestion": "Please answer the question" }, "date": "Contribution for:", diff --git a/frontend/src/locales/es.json b/frontend/src/locales/es.json index ffec649ed..fa6613092 100644 --- a/frontend/src/locales/es.json +++ b/frontend/src/locales/es.json @@ -40,7 +40,7 @@ "myContributionNoteList": "Puedes editar o eliminar las contribuciones enviadas que aún no han sido confirmadas en cualquier momento.", "pending": "Enviado y a la espera de confirmación", "rejected": "rechazado", - "in_progress":"Es gibt eine Rückfrage der Moderatoren.", + "in_progress": "Es gibt eine Rückfrage der Moderatoren.", "answerQuestion": "Please answer the question" }, "date": "Contribución para:", diff --git a/frontend/src/locales/fr.json b/frontend/src/locales/fr.json index b1ff773d0..948f1b0fe 100644 --- a/frontend/src/locales/fr.json +++ b/frontend/src/locales/fr.json @@ -40,7 +40,7 @@ "myContributionNoteList": "À tout moment vous pouvez éditer ou supprimer les données qui n´ont pas été confirmées.", "pending": "Inscription en attente de validation", "rejected": "supprimé", - "in_progress":"Es gibt eine Rückfrage der Moderatoren.", + "in_progress": "Es gibt eine Rückfrage der Moderatoren.", "answerQuestion": "Please answer the question" }, "date": "Contribution pour:", diff --git a/frontend/src/locales/nl.json b/frontend/src/locales/nl.json index edb2ec21b..69896cbea 100644 --- a/frontend/src/locales/nl.json +++ b/frontend/src/locales/nl.json @@ -40,7 +40,7 @@ "myContributionNoteList": "Ingediende bijdragen, die nog niet bevestigd zijn, kun je op elk moment wijzigen of verwijderen.", "pending": "Ingediend en wacht op bevestiging", "rejected": "afgewezen", - "in_progress":"Es gibt eine Rückfrage der Moderatoren.", + "in_progress": "Es gibt eine Rückfrage der Moderatoren.", "answerQuestion": "Please answer the question" }, "date": "Bijdrage voor:", From 773207f80fd8a35f321dfc39c2d036e4e14a4454 Mon Sep 17 00:00:00 2001 From: ogerly Date: Thu, 25 Aug 2022 18:46:58 +0200 Subject: [PATCH 581/977] fix lint in adminarea --- admin/src/components/Tables/OpenCreationsTable.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/src/components/Tables/OpenCreationsTable.vue b/admin/src/components/Tables/OpenCreationsTable.vue index 6c0289ffe..50ae6df97 100644 --- a/admin/src/components/Tables/OpenCreationsTable.vue +++ b/admin/src/components/Tables/OpenCreationsTable.vue @@ -27,7 +27,7 @@ v-if="row.item.state === 'PENDING' && row.item.messageCount > 0" icon="exclamation-circle-fill" variant="warning" - > + > Date: Fri, 26 Aug 2022 02:28:04 +0200 Subject: [PATCH 582/977] adapt backend on database migration of UserContacts --- backend/src/event/Event.ts | 10 ++ backend/src/event/EventProtocolType.ts | 1 + .../graphql/model/UnconfirmedContribution.ts | 2 +- backend/src/graphql/model/User.ts | 12 +- backend/src/graphql/model/UserAdmin.ts | 4 +- backend/src/graphql/model/UserContact.ts | 56 +++++++++ backend/src/graphql/resolver/AdminResolver.ts | 83 +++++++++---- backend/src/graphql/resolver/GdtResolver.ts | 4 +- .../graphql/resolver/TransactionResolver.ts | 21 ++-- backend/src/graphql/resolver/UserResolver.ts | 115 ++++++++++-------- backend/src/typeorm/repository/User.ts | 8 +- backend/src/util/communityUser.ts | 1 + backend/src/webhook/elopage.ts | 4 +- .../0048-add_user_contacts_table/User.ts | 4 +- .../UserContact.ts | 15 ++- .../0048-add_user_contacts_table.ts | 2 +- 16 files changed, 245 insertions(+), 97 deletions(-) create mode 100644 backend/src/graphql/model/UserContact.ts diff --git a/backend/src/event/Event.ts b/backend/src/event/Event.ts index 6f07661f1..85fba896d 100644 --- a/backend/src/event/Event.ts +++ b/backend/src/event/Event.ts @@ -32,6 +32,7 @@ export class EventRegister extends EventBasicUserId {} export class EventRedeemRegister extends EventBasicRedeem {} export class EventInactiveAccount extends EventBasicUserId {} export class EventSendConfirmationEmail extends EventBasicUserId {} +export class EventSendAccountMultiRegistrationEmail extends EventBasicUserId {} export class EventConfirmationEmail extends EventBasicUserId {} export class EventRegisterEmailKlicktipp extends EventBasicUserId {} export class EventLogin extends EventBasicUserId {} @@ -113,6 +114,15 @@ export class Event { return this } + public setEventSendAccountMultiRegistrationEmail( + ev: EventSendAccountMultiRegistrationEmail, + ): Event { + this.setByBasicUser(ev.userId) + this.type = EventProtocolType.SEND_ACCOUNT_MULTI_REGISTRATION_EMAIL + + return this + } + public setEventConfirmationEmail(ev: EventConfirmationEmail): Event { this.setByBasicUser(ev.userId) this.type = EventProtocolType.CONFIRM_EMAIL diff --git a/backend/src/event/EventProtocolType.ts b/backend/src/event/EventProtocolType.ts index 0f61f787a..52bcf8349 100644 --- a/backend/src/event/EventProtocolType.ts +++ b/backend/src/event/EventProtocolType.ts @@ -5,6 +5,7 @@ export enum EventProtocolType { REDEEM_REGISTER = 'REDEEM_REGISTER', INACTIVE_ACCOUNT = 'INACTIVE_ACCOUNT', SEND_CONFIRMATION_EMAIL = 'SEND_CONFIRMATION_EMAIL', + SEND_ACCOUNT_MULTI_REGISTRATION_EMAIL = 'SEND_ACCOUNT_MULTI_REGISTRATION_EMAIL', CONFIRM_EMAIL = 'CONFIRM_EMAIL', REGISTER_EMAIL_KLICKTIPP = 'REGISTER_EMAIL_KLICKTIPP', LOGIN = 'LOGIN', diff --git a/backend/src/graphql/model/UnconfirmedContribution.ts b/backend/src/graphql/model/UnconfirmedContribution.ts index 1d697a971..a81bb4a49 100644 --- a/backend/src/graphql/model/UnconfirmedContribution.ts +++ b/backend/src/graphql/model/UnconfirmedContribution.ts @@ -13,7 +13,7 @@ export class UnconfirmedContribution { this.date = contribution.contributionDate this.firstName = user ? user.firstName : '' this.lastName = user ? user.lastName : '' - this.email = user ? user.email : '' + this.email = user ? user.emailContact.email : '' this.creation = creations } diff --git a/backend/src/graphql/model/User.ts b/backend/src/graphql/model/User.ts index 728851ec2..a28fe4b69 100644 --- a/backend/src/graphql/model/User.ts +++ b/backend/src/graphql/model/User.ts @@ -3,6 +3,7 @@ import { KlickTipp } from './KlickTipp' import { User as dbUser } from '@entity/User' import Decimal from 'decimal.js-light' import { FULL_CREATION_AVAILABLE } from '../resolver/const/const' +import { UserContact } from './UserContact' @ObjectType() export class User { @@ -10,8 +11,9 @@ export class User { this.id = user.id this.gradidoID = user.gradidoID this.alias = user.alias - // this.email = user.email + this.emailId = user.emailId this.email = user.emailContact.email + this.emailContact = user.emailContact this.firstName = user.firstName this.lastName = user.lastName this.deletedAt = user.deletedAt @@ -35,12 +37,18 @@ export class User { gradidoID: string @Field(() => String, { nullable: true }) - alias: string + alias?: string + + @Field(() => Number, { nullable: true }) + emailId: number | null // TODO privacy issue here @Field(() => String) email: string + @Field(() => UserContact) + emailContact: UserContact + @Field(() => String, { nullable: true }) firstName: string | null diff --git a/backend/src/graphql/model/UserAdmin.ts b/backend/src/graphql/model/UserAdmin.ts index cf3663e70..08dc405ac 100644 --- a/backend/src/graphql/model/UserAdmin.ts +++ b/backend/src/graphql/model/UserAdmin.ts @@ -6,11 +6,11 @@ import { User } from '@entity/User' export class UserAdmin { constructor(user: User, creation: Decimal[], hasElopage: boolean, emailConfirmationSend: string) { this.userId = user.id - this.email = user.email + this.email = user.emailContact.email this.firstName = user.firstName this.lastName = user.lastName this.creation = creation - this.emailChecked = user.emailChecked + this.emailChecked = user.emailContact.emailChecked this.hasElopage = hasElopage this.deletedAt = user.deletedAt this.emailConfirmationSend = emailConfirmationSend diff --git a/backend/src/graphql/model/UserContact.ts b/backend/src/graphql/model/UserContact.ts new file mode 100644 index 000000000..902e2f9f2 --- /dev/null +++ b/backend/src/graphql/model/UserContact.ts @@ -0,0 +1,56 @@ +import { ObjectType, Field } from 'type-graphql' +import { UserContact as dbUserCOntact} from '@entity/UserContact' + +@ObjectType() +export class UserContact { + constructor(userContact: dbUserCOntact) { + this.id = userContact.id + this.type = userContact.type + this.userId = userContact.userId + this.email = userContact.email + // this.emailVerificationCode = userContact.emailVerificationCode + this.emailOptInTypeId = userContact.emailOptInTypeId + this.emailResendCount = userContact.emailResendCount + this.emailChecked = userContact.emailChecked + this.phone = userContact.phone + this.createdAt = userContact.createdAt + this.updatedAt = userContact.updatedAt + this.deletedAt = userContact.deletedAt + } + + @Field(() => Number) + id: number + + @Field(() => String) + type: string + + @Field(() => Number) + userId: number + + @Field(() => String) + email: string + + // @Field(() => BigInt, { nullable: true }) + // emailVerificationCode: BigInt | null + + @Field(() => Number, { nullable: true }) + emailOptInTypeId: number | null + + @Field(() => Number, { nullable: true }) + emailResendCount: number | null + + @Field(() => Boolean) + emailChecked: boolean + + @Field(() => String, { nullable: true }) + phone: string | null + + @Field(() => Date) + createdAt: Date + + @Field(() => Date, { nullable: true }) + updatedAt: Date | null + + @Field(() => Date, { nullable: true }) + deletedAt: Date | null +} diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index e70fe71ee..5d283026d 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -44,7 +44,7 @@ import Paginated from '@arg/Paginated' import TransactionLinkFilters from '@arg/TransactionLinkFilters' import { Order } from '@enum/Order' import { communityUser } from '@/util/communityUser' -import { checkOptInCode, activationLink, printTimeDuration } from './UserResolver' +import { checkEmailVerificationCode, activationLink, printTimeDuration } from './UserResolver' import { sendAccountActivationEmail } from '@/mailer/sendAccountActivationEmail' import { transactionLinkCode as contributionLinkCode } from './TransactionLinkResolver' import CONFIG from '@/config' @@ -62,6 +62,7 @@ import { MEMO_MAX_CHARS, MEMO_MIN_CHARS, } from './const/const' +import { UserContact } from '@entity/UserContact' // const EMAIL_OPT_IN_REGISTER = 1 // const EMAIL_OPT_UNKNOWN = 3 // elopage? @@ -118,7 +119,8 @@ export class AdminResolver { const adminUsers = await Promise.all( users.map(async (user) => { let emailConfirmationSend = '' - if (!user.emailChecked) { + if (!user.emailContact.emailChecked) { + /* const emailOptIn = await LoginEmailOptIn.findOne( { userId: user.id, @@ -138,12 +140,18 @@ export class AdminResolver { emailConfirmationSend = emailOptIn.createdAt.toISOString() } } + */ + if (user.emailContact.updatedAt) { + emailConfirmationSend = user.emailContact.updatedAt.toISOString() + } else { + emailConfirmationSend = user.emailContact.createdAt.toISOString() + } } const userCreations = creations.find((c) => c.id === user.id) const adminUser = new UserAdmin( user, userCreations ? userCreations.creations : FULL_CREATION_AVAILABLE, - await hasElopageBuys(user.email), + await hasElopageBuys(user.emailContact.email), emailConfirmationSend, ) return adminUser @@ -239,24 +247,27 @@ export class AdminResolver { @Args() { email, amount, memo, creationDate }: AdminCreateContributionArgs, @Ctx() context: Context, ): Promise { - const user = await dbUser.findOne({ email }, { withDeleted: true }) - if (!user) { + const emailContact = await UserContact.findOne({ email }, { withDeleted: true }) + if (!emailContact) { + logger.error(`Could not find user with email: ${email}`) throw new Error(`Could not find user with email: ${email}`) } - if (user.deletedAt) { - throw new Error('This user was deleted. Cannot create a contribution.') + if (emailContact.deletedAt) { + logger.error('This emailContact was deleted. Cannot create a contribution.') + throw new Error('This emailContact was deleted. Cannot create a contribution.') } - if (!user.emailChecked) { + if (!emailContact.emailChecked) { + logger.error('Contribution could not be saved, Email is not activated') throw new Error('Contribution could not be saved, Email is not activated') } const moderator = getUser(context) logger.trace('moderator: ', moderator.id) - const creations = await getUserCreation(user.id) + const creations = await getUserCreation(emailContact.userId) logger.trace('creations', creations) const creationDateObj = new Date(creationDate) validateContribution(creations, amount, creationDateObj) const contribution = Contribution.create() - contribution.userId = user.id + contribution.userId = emailContact.userId contribution.amount = amount contribution.createdAt = new Date() contribution.contributionDate = creationDateObj @@ -267,7 +278,7 @@ export class AdminResolver { logger.trace('contribution to save', contribution) await Contribution.save(contribution) - return getUserCreation(user.id) + return getUserCreation(emailContact.userId) } @Authorized([RIGHTS.ADMIN_CREATE_CONTRIBUTIONS]) @@ -303,11 +314,18 @@ export class AdminResolver { @Args() { id, email, amount, memo, creationDate }: AdminUpdateContributionArgs, @Ctx() context: Context, ): Promise { - const user = await dbUser.findOne({ email }, { withDeleted: true }) + const emailContact = await UserContact.findOne({ email }, { withDeleted: true }) + if (!emailContact) { + logger.error(`Could not find UserContact with email: ${email}`) + throw new Error(`Could not find UserContact with email: ${email}`) + } + const user = await dbUser.findOne({ id: emailContact.userId }, { withDeleted: true }) if (!user) { - throw new Error(`Could not find user with email: ${email}`) + logger.error(`Could not find User to emailContact: ${email}`) + throw new Error(`Could not find User to emailContact: ${email}`) } if (user.deletedAt) { + logger.error(`User was deleted (${email})`) throw new Error(`User was deleted (${email})`) } @@ -318,14 +336,17 @@ export class AdminResolver { }) if (!contributionToUpdate) { + logger.error('No contribution found to given id.') throw new Error('No contribution found to given id.') } if (contributionToUpdate.userId !== user.id) { + logger.error('user of the pending contribution and send user does not correspond') throw new Error('user of the pending contribution and send user does not correspond') } if (contributionToUpdate.moderatorId === null) { + logger.error('An admin is not allowed to update a user contribution.') throw new Error('An admin is not allowed to update a user contribution.') } @@ -379,7 +400,7 @@ export class AdminResolver { moderator: contribution.moderatorId, firstName: user ? user.firstName : '', lastName: user ? user.lastName : '', - email: user ? user.email : '', + email: user ? user.emailContact.email : '', creation: creation ? creation.creations : FULL_CREATION_AVAILABLE, } }) @@ -390,10 +411,10 @@ export class AdminResolver { async adminDeleteContribution(@Arg('id', () => Int) id: number): Promise { const contribution = await Contribution.findOne(id) if (!contribution) { + logger.error(`Contribution not found for given id: ${id}`) throw new Error('Contribution not found for given id.') } contribution.contributionStatus = ContributionStatus.DELETED - await contribution.save() const res = await contribution.softRemove() return !!res } @@ -406,15 +427,19 @@ export class AdminResolver { ): Promise { const contribution = await Contribution.findOne(id) if (!contribution) { + logger.error(`Contribution not found for given id: ${id}`) throw new Error('Contribution not found to given id.') } const moderatorUser = getUser(context) - if (moderatorUser.id === contribution.userId) + if (moderatorUser.id === contribution.userId) { + logger.error('Moderator can not confirm own contribution') throw new Error('Moderator can not confirm own contribution') - + } const user = await dbUser.findOneOrFail({ id: contribution.userId }, { withDeleted: true }) - if (user.deletedAt) throw new Error('This user was deleted. Cannot confirm a contribution.') - + if (user.deletedAt) { + logger.error('This user was deleted. Cannot confirm a contribution.') + throw new Error('This user was deleted. Cannot confirm a contribution.') + } const creations = await getUserCreation(contribution.userId, false) validateContribution(creations, contribution.amount, contribution.contributionDate) @@ -501,6 +526,18 @@ export class AdminResolver { @Mutation(() => Boolean) async sendActivationEmail(@Arg('email') email: string): Promise { email = email.trim().toLowerCase() + const emailContact = await UserContact.findOne({ email: email }) + if (!emailContact) { + logger.error(`Could not find UserContact with email: ${email}`) + throw new Error(`Could not find UserContact with email: ${email}`) + } + const user = await dbUser.findOne({ id: emailContact.userId }) + if (!user) { + logger.error(`Could not find User to emailContact: ${email}`) + throw new Error(`Could not find User to emailContact: ${email}`) + } + + /* const user = await dbUser.findOneOrFail({ email: email }) // can be both types: REGISTER and RESET_PASSWORD @@ -510,23 +547,21 @@ export class AdminResolver { }) optInCode = await checkOptInCode(optInCode, user) + */ // eslint-disable-next-line @typescript-eslint/no-unused-vars const emailSent = await sendAccountActivationEmail({ - link: activationLink(optInCode), + link: activationLink(emailContact.emailVerificationCode), firstName: user.firstName, lastName: user.lastName, email, duration: printTimeDuration(CONFIG.EMAIL_CODE_VALID_TIME), }) - /* uncomment this, when you need the activation link on the console // In case EMails are disabled log the activation link for the user if (!emailSent) { - // eslint-disable-next-line no-console - console.log(`Account confirmation link: ${activationLink}`) + logger.info(`Account confirmation link: ${activationLink}`) } - */ return true } diff --git a/backend/src/graphql/resolver/GdtResolver.ts b/backend/src/graphql/resolver/GdtResolver.ts index 56a95c9f0..a1d75e946 100644 --- a/backend/src/graphql/resolver/GdtResolver.ts +++ b/backend/src/graphql/resolver/GdtResolver.ts @@ -20,7 +20,7 @@ export class GdtResolver { try { const resultGDT = await apiGet( - `${CONFIG.GDT_API_URL}/GdtEntries/listPerEmailApi/${userEntity.email}/${currentPage}/${pageSize}/${order}`, + `${CONFIG.GDT_API_URL}/GdtEntries/listPerEmailApi/${userEntity.emailContact.email}/${currentPage}/${pageSize}/${order}`, ) if (!resultGDT.success) { throw new Error(resultGDT.data) @@ -37,7 +37,7 @@ export class GdtResolver { const user = getUser(context) try { const resultGDTSum = await apiPost(`${CONFIG.GDT_API_URL}/GdtEntries/sumPerEmailApi`, { - email: user.email, + email: user.emailContact.email, }) if (!resultGDTSum.success) { throw new Error('Call not successful') diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index bc062a1f4..ae6445343 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -35,6 +35,7 @@ import Decimal from 'decimal.js-light' import { BalanceResolver } from './BalanceResolver' import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const' +import { UserContact } from '@entity/UserContact' export const executeTransaction = async ( amount: Decimal, @@ -148,8 +149,8 @@ export const executeTransaction = async ( senderLastName: sender.lastName, recipientFirstName: recipient.firstName, recipientLastName: recipient.lastName, - email: recipient.email, - senderEmail: sender.email, + email: recipient.emailContact.email, + senderEmail: sender.emailContact.email, amount, memo, overviewURL: CONFIG.EMAIL_LINK_OVERVIEW, @@ -171,7 +172,7 @@ export class TransactionResolver { const user = getUser(context) logger.addContext('user', user.id) - logger.info(`transactionList(user=${user.firstName}.${user.lastName}, ${user.email})`) + logger.info(`transactionList(user=${user.firstName}.${user.lastName}, ${user.emailId})`) // find current balance const lastTransaction = await dbTransaction.findOne( @@ -293,16 +294,22 @@ export class TransactionResolver { } // validate recipient user - const recipientUser = await dbUser.findOne({ email: email }, { withDeleted: true }) + const emailContact = await UserContact.findOne({ email }, { withDeleted: true }) + if (!emailContact) { + logger.error(`Could not find UserContact with email: ${email}`) + throw new Error(`Could not find UserContact with email: ${email}`) + } + + const recipientUser = await dbUser.findOne({ id: emailContact.userId }) if (!recipientUser) { - logger.error(`recipient not known: email=${email}`) - throw new Error('recipient not known') + logger.error(`unknown recipient to UserContact: email=${email}`) + throw new Error('unknown recipient') } if (recipientUser.deletedAt) { logger.error(`The recipient account was deleted: recipientUser=${recipientUser}`) throw new Error('The recipient account was deleted') } - if (!recipientUser.emailChecked) { + if (!emailContact.emailChecked) { logger.error(`The recipient account is not activated: recipientUser=${recipientUser}`) throw new Error('The recipient account is not activated') } diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 9aba4d6b1..37a9946a7 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -29,6 +29,7 @@ import { EventLogin, EventRedeemRegister, EventRegister, + EventSendAccountMultiRegistrationEmail, EventSendConfirmationEmail, } from '@/event/Event' import { getUserCreation } from './util/creations' @@ -417,50 +418,55 @@ export class UserResolver { ) // TODO: wrong default value (should be null), how does graphql work here? Is it an required field? // default int publisher_id = 0; + const event = new Event() // Validate Language (no throw) if (!language || !isLanguage(language)) { language = DEFAULT_LANGUAGE } - // Validate email unique + // check if user with email still exists? email = email.trim().toLowerCase() - const foundUser = await findUserByEmail(email) + if (await checkEmailExists(email)) { + const foundUser = await findUserByEmail(email) + logger.info(`DbUser.findOne(email=${email}) = ${foundUser}`) - // TODO we cannot use repository.count(), since it does not allow to specify if you want to include the soft deletes - // const userFound = await DbUser.findOne({ email }, { withDeleted: true }) - logger.info(`DbUser.findOne(email=${email}) = ${foundUser}`) + if (foundUser) { + // ATTENTION: this logger-message will be exactly expected during tests + logger.info(`User already exists with this email=${email}`) + // TODO: this is unsecure, but the current implementation of the login server. This way it can be queried if the user with given EMail is existent. - if (foundUser) { - // ATTENTION: this logger-message will be exactly expected during tests - logger.info(`User already exists with this email=${email}`) - // TODO: this is unsecure, but the current implementation of the login server. This way it can be queried if the user with given EMail is existent. + const user = new User(communityDbUser) + user.id = sodium.randombytes_random() % (2048 * 16) // TODO: for a better faking derive id from email so that it will be always the same id when the same email comes in? + user.gradidoID = uuidv4() + user.email = email + user.firstName = firstName + user.lastName = lastName + user.language = language + user.publisherId = publisherId + logger.debug('partly faked user=' + user) - const user = new User(communityDbUser) - user.id = sodium.randombytes_random() % (2048 * 16) // TODO: for a better faking derive id from email so that it will be always the same id when the same email comes in? - user.gradidoID = uuidv4() - user.email = email - user.firstName = firstName - user.lastName = lastName - user.language = language - user.publisherId = publisherId - logger.debug('partly faked user=' + user) + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const emailSent = await sendAccountMultiRegistrationEmail({ + firstName, + lastName, + email, + }) + const eventSendAccountMultiRegistrationEmail = new EventSendAccountMultiRegistrationEmail() + eventSendAccountMultiRegistrationEmail.userId = foundUser.id + eventProtocol.writeEvent( + event.setEventSendConfirmationEmail(eventSendAccountMultiRegistrationEmail), + ) + logger.info(`sendAccountMultiRegistrationEmail of ${firstName}.${lastName} to ${email}`) + /* uncomment this, when you need the activation link on the console */ + // In case EMails are disabled log the activation link for the user + if (!emailSent) { + logger.debug(`Email not send!`) + } + logger.info('createUser() faked and send multi registration mail...') - // eslint-disable-next-line @typescript-eslint/no-unused-vars - const emailSent = await sendAccountMultiRegistrationEmail({ - firstName, - lastName, - email, - }) - logger.info(`sendAccountMultiRegistrationEmail of ${firstName}.${lastName} to ${email}`) - /* uncomment this, when you need the activation link on the console */ - // In case EMails are disabled log the activation link for the user - if (!emailSent) { - logger.debug(`Email not send!`) + return user } - logger.info('createUser() faked and send multi registration mail...') - - return user } const passphrase = PassphraseGenerate() @@ -473,16 +479,11 @@ export class UserResolver { const eventRegister = new EventRegister() const eventRedeemRegister = new EventRedeemRegister() const eventSendConfirmEmail = new EventSendConfirmationEmail() - // const dbEmailContact = new DbUserContact() - // dbEmailContact.email = email - const dbUser = new DbUser() - // dbUser.emailContact = dbEmailContact + let dbUser = new DbUser() dbUser.gradidoID = gradidoID - // dbUser.email = email dbUser.firstName = firstName dbUser.lastName = lastName - // dbUser.emailHash = emailHash dbUser.language = language dbUser.publisherId = publisherId dbUser.passphrase = passphrase.join(' ') @@ -513,22 +514,22 @@ export class UserResolver { // loginUser.pubKey = keyPair[0] // loginUser.privKey = encryptedPrivkey - const event = new Event() const queryRunner = getConnection().createQueryRunner() await queryRunner.connect() await queryRunner.startTransaction('READ UNCOMMITTED') try { - await queryRunner.manager.save(dbUser).catch((error) => { + dbUser = await queryRunner.manager.save(dbUser).catch((error) => { logger.error('Error while saving dbUser', error) throw new Error('error saving user') }) - const emailContact = newEmailContact(email, dbUser.id) - await queryRunner.manager.save(emailContact).catch((error) => { + let emailContact = newEmailContact(email, dbUser.id) + emailContact = await queryRunner.manager.save(emailContact).catch((error) => { logger.error('Error while saving emailContact', error) throw new Error('error saving email user contact') }) dbUser.emailContact = emailContact + dbUser.emailId = emailContact.id await queryRunner.manager.save(dbUser).catch((error) => { logger.error('Error while updating dbUser', error) throw new Error('error updating user') @@ -559,8 +560,6 @@ export class UserResolver { eventSendConfirmEmail.userId = dbUser.id eventProtocol.writeEvent(event.setEventSendConfirmationEmail(eventSendConfirmEmail)) - /* uncomment this, when you need the activation link on the console */ - // In case EMails are disabled log the activation link for the user if (!emailSent) { logger.debug(`Account confirmation link: ${activationLink}`) } @@ -893,20 +892,30 @@ export class UserResolver { } async function findUserByEmail(email: string): Promise { - const dbUserContact = await DbUserContact.findOneOrFail(email, { withDeleted: true }).catch( - () => { - logger.error(`UserContact with email=${email} does not exists`) - throw new Error('No user with this credentials') - }, - ) - const userId = dbUserContact.userId - const dbUser = await DbUser.findOneOrFail(userId).catch(() => { - logger.error(`User with emeilContact=${email} connected per userId=${userId} does not exist`) + const dbUserContact = await DbUserContact.findOneOrFail( + { email: email }, + { withDeleted: true }, + ).catch(() => { + logger.error(`UserContact with email=${email} does not exists`) throw new Error('No user with this credentials') }) + const userId = dbUserContact.userId + const dbUser = await DbUser.findOneOrFail(userId).catch(() => { + logger.error(`User with emailContact=${email} connected per userId=${userId} does not exist`) + throw new Error('No user with this credentials') + }) + dbUser.emailContact = dbUserContact return dbUser } +async function checkEmailExists(email: string): Promise { + const userContact = await DbUserContact.findOne({ email: email }, { withDeleted: true }) + if (userContact) { + return true + } + return false +} + /* const isTimeExpired = (optIn: LoginEmailOptIn, duration: number): boolean => { const timeElapsed = Date.now() - new Date(optIn.updatedAt).getTime() diff --git a/backend/src/typeorm/repository/User.ts b/backend/src/typeorm/repository/User.ts index 01f61dcbc..21cafbb30 100644 --- a/backend/src/typeorm/repository/User.ts +++ b/backend/src/typeorm/repository/User.ts @@ -4,9 +4,15 @@ import { User } from '@entity/User' @EntityRepository(User) export class UserRepository extends Repository { async findByPubkeyHex(pubkeyHex: string): Promise { - return this.createQueryBuilder('user') + const user = await this.createQueryBuilder('user') .where('hex(user.pubKey) = :pubkeyHex', { pubkeyHex }) .getOneOrFail() + /* + user.emailContact = await this.createQueryBuilder('userContact') + .where('userContact.id = :user.emailId', { user.emailId }) + .getOneOrFail() + */ + return user } async findBySearchCriteriaPagedFiltered( diff --git a/backend/src/util/communityUser.ts b/backend/src/util/communityUser.ts index 2f0743270..e885b7043 100644 --- a/backend/src/util/communityUser.ts +++ b/backend/src/util/communityUser.ts @@ -12,6 +12,7 @@ const communityDbUser: dbUser = { alias: '', // email: 'support@gradido.net', emailContact: new UserContact(), + emailId: -1, firstName: 'Gradido', lastName: 'Akademie', pubKey: Buffer.from(''), diff --git a/backend/src/webhook/elopage.ts b/backend/src/webhook/elopage.ts index d5eaef521..6c8ca7e49 100644 --- a/backend/src/webhook/elopage.ts +++ b/backend/src/webhook/elopage.ts @@ -30,6 +30,7 @@ import { LoginElopageBuys } from '@entity/LoginElopageBuys' import { UserResolver } from '@/graphql/resolver/UserResolver' import { User as dbUser } from '@entity/User' +import { UserContact as dbUserContact } from '@entity/UserContact' export const elopageWebhook = async (req: any, res: any): Promise => { // eslint-disable-next-line no-console @@ -127,7 +128,8 @@ export const elopageWebhook = async (req: any, res: any): Promise => { } // Do we already have such a user? - if ((await dbUser.count({ email })) !== 0) { + // if ((await dbUser.count({ email })) !== 0) { + if ((await dbUserContact.count({ email })) !== 0) { // eslint-disable-next-line no-console console.log(`Did not create User - already exists with email: ${email}`) return diff --git a/database/entity/0048-add_user_contacts_table/User.ts b/database/entity/0048-add_user_contacts_table/User.ts index 010cb0c20..40bfa601a 100644 --- a/database/entity/0048-add_user_contacts_table/User.ts +++ b/database/entity/0048-add_user_contacts_table/User.ts @@ -43,12 +43,12 @@ export class User extends BaseEntity { @Column({ length: 255, unique: true, nullable: false, collation: 'utf8mb4_unicode_ci' }) email: string */ - @OneToOne(() => UserContact, { primary: true, cascade: true }) + @OneToOne(() => UserContact) @JoinColumn({ name: 'email_id' }) emailContact: UserContact @Column({ name: 'email_id', type: 'int', unsigned: true, nullable: true, default: null }) - emailId?: number | null + emailId: number | null @Column({ name: 'first_name', diff --git a/database/entity/0048-add_user_contacts_table/UserContact.ts b/database/entity/0048-add_user_contacts_table/UserContact.ts index 7c2dff3db..936e433a6 100644 --- a/database/entity/0048-add_user_contacts_table/UserContact.ts +++ b/database/entity/0048-add_user_contacts_table/UserContact.ts @@ -1,4 +1,13 @@ -import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, DeleteDateColumn } from 'typeorm' +import { + BaseEntity, + Entity, + PrimaryGeneratedColumn, + Column, + DeleteDateColumn, + OneToOne, + JoinColumn, +} from 'typeorm' +import { User } from './User' @Entity('user_contacts', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) export class UserContact extends BaseEntity { @@ -14,6 +23,10 @@ export class UserContact extends BaseEntity { }) type: string + @OneToOne(() => User) + @JoinColumn({ name: 'user_id' }) + user: User + @Column({ name: 'user_id', type: 'int', unsigned: true, nullable: false }) userId: number diff --git a/database/migrations/0048-add_user_contacts_table.ts b/database/migrations/0048-add_user_contacts_table.ts index 49f647e39..d1b35a400 100644 --- a/database/migrations/0048-add_user_contacts_table.ts +++ b/database/migrations/0048-add_user_contacts_table.ts @@ -22,7 +22,7 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis \`email_checked\` tinyint(4) NOT NULL DEFAULT 0, \`phone\` varchar(255) COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, \`created_at\` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, - \`updated_at\` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + \`updated_at\` datetime NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP, \`deleted_at\` datetime NULL DEFAULT NULL, PRIMARY KEY (\`id\`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;`) From 0f90f960ceb83570ed00b3609b73740c94052c9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Fri, 26 Aug 2022 02:40:44 +0200 Subject: [PATCH 583/977] remove unused code --- backend/src/typeorm/repository/User.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/backend/src/typeorm/repository/User.ts b/backend/src/typeorm/repository/User.ts index 21cafbb30..04a30de8f 100644 --- a/backend/src/typeorm/repository/User.ts +++ b/backend/src/typeorm/repository/User.ts @@ -4,15 +4,9 @@ import { User } from '@entity/User' @EntityRepository(User) export class UserRepository extends Repository { async findByPubkeyHex(pubkeyHex: string): Promise { - const user = await this.createQueryBuilder('user') + return await this.createQueryBuilder('user') .where('hex(user.pubKey) = :pubkeyHex', { pubkeyHex }) .getOneOrFail() - /* - user.emailContact = await this.createQueryBuilder('userContact') - .where('userContact.id = :user.emailId', { user.emailId }) - .getOneOrFail() - */ - return user } async findBySearchCriteriaPagedFiltered( From 1090d17fdb365da3e592c20ea86b7f2062c0535c Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 26 Aug 2022 08:32:15 +0200 Subject: [PATCH 584/977] Remove OneToMany import. --- database/entity/0047-messages_tables/ContributionMessage.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/database/entity/0047-messages_tables/ContributionMessage.ts b/database/entity/0047-messages_tables/ContributionMessage.ts index 3d9c04d89..e5226043d 100644 --- a/database/entity/0047-messages_tables/ContributionMessage.ts +++ b/database/entity/0047-messages_tables/ContributionMessage.ts @@ -5,7 +5,6 @@ import { Entity, JoinColumn, ManyToOne, - OneToMany, PrimaryGeneratedColumn, } from 'typeorm' import { Contribution } from '../Contribution' From 894140b41837e8ab2a0a3c7a7d1dcfcb97ed456a Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 26 Aug 2022 08:50:08 +0200 Subject: [PATCH 585/977] Remove unused imports. --- backend/src/graphql/resolver/ContributionResolver.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 1b7a8f630..f8300f164 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -11,10 +11,8 @@ import { ContributionType } from '@enum/ContributionType' import { ContributionStatus } from '@enum/ContributionStatus' import { Contribution, ContributionListResult } from '@model/Contribution' import { UnconfirmedContribution } from '@model/UnconfirmedContribution' -import { User } from '@model/User' import { validateContribution, getUserCreation, updateCreations } from './util/creations' import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const' -import { ContributionMessage } from '@entity/ContributionMessage' @Resolver() export class ContributionResolver { From 1184666fe2062694d3a96c397181fdeb8d2a1fa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Fri, 26 Aug 2022 14:42:37 +0200 Subject: [PATCH 586/977] try to solve problem of dbUser-entity with emailContact in context --- backend/src/graphql/directive/isAuthorized.ts | 2 +- backend/src/typeorm/repository/User.ts | 20 +++++++++++++------ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/backend/src/graphql/directive/isAuthorized.ts b/backend/src/graphql/directive/isAuthorized.ts index 065c01957..c24cde47a 100644 --- a/backend/src/graphql/directive/isAuthorized.ts +++ b/backend/src/graphql/directive/isAuthorized.ts @@ -31,7 +31,7 @@ const isAuthorized: AuthChecker = async ({ context }, rights) => { // TODO - load from database dynamically & admin - maybe encode this in the token to prevent many database requests // TODO this implementation is bullshit - two database queries cause our user identifiers are not aligned and vary between email, id and pubKey - const userRepository = await getCustomRepository(UserRepository) + const userRepository = getCustomRepository(UserRepository) try { const user = await userRepository.findByPubkeyHex(context.pubKey) context.user = user diff --git a/backend/src/typeorm/repository/User.ts b/backend/src/typeorm/repository/User.ts index 04a30de8f..3c859ce0c 100644 --- a/backend/src/typeorm/repository/User.ts +++ b/backend/src/typeorm/repository/User.ts @@ -1,12 +1,20 @@ import { Brackets, EntityRepository, ObjectLiteral, Repository } from '@dbTools/typeorm' -import { User } from '@entity/User' +import { User as DbUser } from '@entity/User' -@EntityRepository(User) -export class UserRepository extends Repository { - async findByPubkeyHex(pubkeyHex: string): Promise { - return await this.createQueryBuilder('user') +@EntityRepository(DbUser) +export class UserRepository extends Repository { + async findByPubkeyHex(pubkeyHex: string): Promise { + const dbUser = await this.createQueryBuilder('user') .where('hex(user.pubKey) = :pubkeyHex', { pubkeyHex }) .getOneOrFail() + /* + const dbUser = await this.findOneOrFail(`hex(user.pubKey) = { pubkeyHex }`) + const emailContact = await this.query( + `SELECT * from user_contacts where id = { dbUser.emailId }`, + ) + dbUser.emailContact = emailContact + */ + return dbUser } async findBySearchCriteriaPagedFiltered( @@ -15,7 +23,7 @@ export class UserRepository extends Repository { filterCriteria: ObjectLiteral[], currentPage: number, pageSize: number, - ): Promise<[User[], number]> { + ): Promise<[DbUser[], number]> { const query = await this.createQueryBuilder('user') .select(select) .withDeleted() From 1d1de2011a1f2bfc3691382da53f434232b6d877 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Fri, 26 Aug 2022 20:00:29 +0200 Subject: [PATCH 587/977] failed try to load OneToOne relation of user to userConmtact as emailConact-attribut... grrrrrr... --- backend/src/graphql/model/User.ts | 8 +++++--- backend/src/typeorm/repository/User.ts | 3 ++- database/entity/0048-add_user_contacts_table/User.ts | 2 +- .../entity/0048-add_user_contacts_table/UserContact.ts | 3 +-- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/backend/src/graphql/model/User.ts b/backend/src/graphql/model/User.ts index a28fe4b69..e64df8294 100644 --- a/backend/src/graphql/model/User.ts +++ b/backend/src/graphql/model/User.ts @@ -12,13 +12,15 @@ export class User { this.gradidoID = user.gradidoID this.alias = user.alias this.emailId = user.emailId - this.email = user.emailContact.email - this.emailContact = user.emailContact + if (user.emailContact) { + this.email = user.emailContact.email + this.emailContact = user.emailContact + this.emailChecked = user.emailContact.emailChecked + } this.firstName = user.firstName this.lastName = user.lastName this.deletedAt = user.deletedAt this.createdAt = user.createdAt - this.emailChecked = user.emailContact.emailChecked this.language = user.language this.publisherId = user.publisherId this.isAdmin = user.isAdmin diff --git a/backend/src/typeorm/repository/User.ts b/backend/src/typeorm/repository/User.ts index 3c859ce0c..b347fae40 100644 --- a/backend/src/typeorm/repository/User.ts +++ b/backend/src/typeorm/repository/User.ts @@ -5,6 +5,7 @@ import { User as DbUser } from '@entity/User' export class UserRepository extends Repository { async findByPubkeyHex(pubkeyHex: string): Promise { const dbUser = await this.createQueryBuilder('user') + .leftJoinAndSelect('user.emailContact', 'emailContact') .where('hex(user.pubKey) = :pubkeyHex', { pubkeyHex }) .getOneOrFail() /* @@ -24,7 +25,7 @@ export class UserRepository extends Repository { currentPage: number, pageSize: number, ): Promise<[DbUser[], number]> { - const query = await this.createQueryBuilder('user') + const query = this.createQueryBuilder('user') .select(select) .withDeleted() .where( diff --git a/database/entity/0048-add_user_contacts_table/User.ts b/database/entity/0048-add_user_contacts_table/User.ts index 40bfa601a..6c4bf52f1 100644 --- a/database/entity/0048-add_user_contacts_table/User.ts +++ b/database/entity/0048-add_user_contacts_table/User.ts @@ -43,7 +43,7 @@ export class User extends BaseEntity { @Column({ length: 255, unique: true, nullable: false, collation: 'utf8mb4_unicode_ci' }) email: string */ - @OneToOne(() => UserContact) + @OneToOne(() => UserContact, (emailContact) => emailContact.userId) @JoinColumn({ name: 'email_id' }) emailContact: UserContact diff --git a/database/entity/0048-add_user_contacts_table/UserContact.ts b/database/entity/0048-add_user_contacts_table/UserContact.ts index 936e433a6..942a7de4f 100644 --- a/database/entity/0048-add_user_contacts_table/UserContact.ts +++ b/database/entity/0048-add_user_contacts_table/UserContact.ts @@ -23,8 +23,7 @@ export class UserContact extends BaseEntity { }) type: string - @OneToOne(() => User) - @JoinColumn({ name: 'user_id' }) + @OneToOne(() => User, (user) => user.emailContact) user: User @Column({ name: 'user_id', type: 'int', unsigned: true, nullable: false }) From 5dc74b9cb8d7dd1854f613e2f35f9916aefbd96e Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 26 Aug 2022 08:32:15 +0200 Subject: [PATCH 588/977] Remove OneToMany import. --- database/entity/0047-messages_tables/ContributionMessage.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/database/entity/0047-messages_tables/ContributionMessage.ts b/database/entity/0047-messages_tables/ContributionMessage.ts index 3d9c04d89..e5226043d 100644 --- a/database/entity/0047-messages_tables/ContributionMessage.ts +++ b/database/entity/0047-messages_tables/ContributionMessage.ts @@ -5,7 +5,6 @@ import { Entity, JoinColumn, ManyToOne, - OneToMany, PrimaryGeneratedColumn, } from 'typeorm' import { Contribution } from '../Contribution' From c6f2e9fb0d4c9f7d1acb58d9a92e967bed66b265 Mon Sep 17 00:00:00 2001 From: ogerly Date: Sat, 27 Aug 2022 11:20:14 +0200 Subject: [PATCH 589/977] reload messages if submited --- .../ContributionMessagesFormular.vue | 2 ++ .../ContributionMessagesList.vue | 4 +++ .../Contributions/ContributionList.vue | 1 + .../Contributions/ContributionListItem.vue | 25 +++++++++++++++++-- frontend/src/graphql/queries.js | 23 +++++++++++++++++ 5 files changed, 53 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/ContributionMessages/ContributionMessagesFormular.vue b/frontend/src/components/ContributionMessages/ContributionMessagesFormular.vue index e27989b12..5fed6ebd6 100644 --- a/frontend/src/components/ContributionMessages/ContributionMessagesFormular.vue +++ b/frontend/src/components/ContributionMessages/ContributionMessagesFormular.vue @@ -51,6 +51,8 @@ export default { }, }) .then((result) => { + this.$emit('get-list-contribution-messages', this.contributionId) + this.form.text = '' this.toastSuccess(result) }) .catch((error) => { diff --git a/frontend/src/components/ContributionMessages/ContributionMessagesList.vue b/frontend/src/components/ContributionMessages/ContributionMessagesList.vue index f8130f2bc..1b8e36cae 100644 --- a/frontend/src/components/ContributionMessages/ContributionMessagesList.vue +++ b/frontend/src/components/ContributionMessages/ContributionMessagesList.vue @@ -10,6 +10,7 @@ class="mt-5" :contributionId="contributionId" @toggle-contribution-messages-box="toggleContributionMessagesBox" + @get-list-contribution-messages="getListContributionMessages" />
    @@ -41,6 +42,9 @@ export default { toggleContributionMessagesBox(id) { this.$emit('toggle-contribution-messages-box', id) }, + getListContributionMessages() { + this.$emit('get-list-contribution-messages', this.contributionId) + }, }, } diff --git a/frontend/src/components/Contributions/ContributionList.vue b/frontend/src/components/Contributions/ContributionList.vue index cffee360b..724a69281 100644 --- a/frontend/src/components/Contributions/ContributionList.vue +++ b/frontend/src/components/Contributions/ContributionList.vue @@ -47,6 +47,7 @@ export default { data() { return { currentPage: 1, + messages: [], } }, methods: { diff --git a/frontend/src/components/Contributions/ContributionListItem.vue b/frontend/src/components/Contributions/ContributionListItem.vue index be19822d2..6e95093db 100644 --- a/frontend/src/components/Contributions/ContributionListItem.vue +++ b/frontend/src/components/Contributions/ContributionListItem.vue @@ -2,7 +2,7 @@
    -
    +
    @@ -78,6 +79,7 @@ diff --git a/frontend/src/graphql/queries.js b/frontend/src/graphql/queries.js index f701ad8cf..d7fc0ce98 100644 --- a/frontend/src/graphql/queries.js +++ b/frontend/src/graphql/queries.js @@ -265,3 +265,26 @@ export const searchAdminUsers = gql` } } ` + +export const listContributionMessages = gql` + query($contributionId: Float!, $pageSize: Int = 25, $currentPage: Int = 1, $order: Order = ASC) { + listContributionMessages( + contributionId: $contributionId + pageSize: $pageSize + currentPage: $currentPage + order: $order + ) { + count + messages { + id + message + createdAt + updatedAt + type + userFirstName + userLastName + userId + } + } + } +` From fd74a2e67105b45a28041e28022b1fcaecb09e9c Mon Sep 17 00:00:00 2001 From: ogerly Date: Sat, 27 Aug 2022 11:20:30 +0200 Subject: [PATCH 590/977] reload messages if submited adminarea --- .../ContributionMessagesFormular.vue | 30 +++++++------------ .../ContributionMessagesList.vue | 6 +++- .../slots/ContributionMessagesListItem.vue | 6 ---- .../slots/IsModerator.vue | 24 ++++++++------- .../slots/IsNotModerator.vue | 7 +---- 5 files changed, 30 insertions(+), 43 deletions(-) diff --git a/admin/src/components/ContributionMessages/ContributionMessagesFormular.vue b/admin/src/components/ContributionMessages/ContributionMessagesFormular.vue index b7e706d5c..c04f8a573 100644 --- a/admin/src/components/ContributionMessages/ContributionMessagesFormular.vue +++ b/admin/src/components/ContributionMessages/ContributionMessagesFormular.vue @@ -1,23 +1,5 @@ From ef52c8b6d560d30d551e92ba2619e741488c4975 Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 29 Aug 2022 08:08:30 +0200 Subject: [PATCH 591/977] delete unused toggleContributionMessagesBox function --- .../ContributionMessages/ContributionMessagesFormular.vue | 3 --- .../src/components/Contributions/ContributionListItem.vue | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/frontend/src/components/ContributionMessages/ContributionMessagesFormular.vue b/frontend/src/components/ContributionMessages/ContributionMessagesFormular.vue index 5fed6ebd6..80708726c 100644 --- a/frontend/src/components/ContributionMessages/ContributionMessagesFormular.vue +++ b/frontend/src/components/ContributionMessages/ContributionMessagesFormular.vue @@ -63,9 +63,6 @@ export default { event.preventDefault() this.form.text = '' }, - toggleContributionMessagesBox() { - this.$emit('toggle-contribution-messages-box', this.contributionId) - }, }, } diff --git a/frontend/src/components/Contributions/ContributionListItem.vue b/frontend/src/components/Contributions/ContributionListItem.vue index 6e95093db..976730384 100644 --- a/frontend/src/components/Contributions/ContributionListItem.vue +++ b/frontend/src/components/Contributions/ContributionListItem.vue @@ -173,7 +173,7 @@ export default { alert('toggleContributionMessagesBox(' + id + ')') }, getListContributionMessages() { - console.log('getListContributionMessages', this.contributionId) + // console.log('getListContributionMessages', this.contributionId) this.$apollo .query({ query: listContributionMessages, @@ -183,7 +183,7 @@ export default { fetchPolicy: 'no-cache', }) .then((result) => { - console.log('result', result.data.listContributionMessages.messages) + // console.log('result', result.data.listContributionMessages.messages) this.messages_get = result.data.listContributionMessages.messages }) .catch((error) => { From 14ca1378bf4505882646b26c8070572a830b470f Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 29 Aug 2022 08:15:48 +0200 Subject: [PATCH 592/977] delete unused toggleContributionMessagesBox function --- .../ContributionMessages/ContributionMessagesList.vue | 4 ---- .../src/components/Contributions/ContributionListItem.vue | 4 ---- 2 files changed, 8 deletions(-) diff --git a/frontend/src/components/ContributionMessages/ContributionMessagesList.vue b/frontend/src/components/ContributionMessages/ContributionMessagesList.vue index 1b8e36cae..98e92e6e7 100644 --- a/frontend/src/components/ContributionMessages/ContributionMessagesList.vue +++ b/frontend/src/components/ContributionMessages/ContributionMessagesList.vue @@ -9,7 +9,6 @@ v-if="state === 'PENDING' || state === 'IN_PROGRESS'" class="mt-5" :contributionId="contributionId" - @toggle-contribution-messages-box="toggleContributionMessagesBox" @get-list-contribution-messages="getListContributionMessages" />
    @@ -39,9 +38,6 @@ export default { }, }, methods: { - toggleContributionMessagesBox(id) { - this.$emit('toggle-contribution-messages-box', id) - }, getListContributionMessages() { this.$emit('get-list-contribution-messages', this.contributionId) }, diff --git a/frontend/src/components/Contributions/ContributionListItem.vue b/frontend/src/components/Contributions/ContributionListItem.vue index 976730384..8fc742cd3 100644 --- a/frontend/src/components/Contributions/ContributionListItem.vue +++ b/frontend/src/components/Contributions/ContributionListItem.vue @@ -67,7 +67,6 @@ :messages="messages_get" :state="state" :contributionId="contributionId" - @toggle-contribution-messages-box="toggleContributionMessagesBox" @get-list-contribution-messages="getListContributionMessages" /> @@ -169,9 +168,6 @@ export default { if (value) this.$emit('delete-contribution', item) }) }, - toggleContributionMessagesBox(id) { - alert('toggleContributionMessagesBox(' + id + ')') - }, getListContributionMessages() { // console.log('getListContributionMessages', this.contributionId) this.$apollo From 15af14a2331616c9053453e9433b652007d1dec6 Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 29 Aug 2022 10:00:41 +0200 Subject: [PATCH 593/977] add methods updateState and emits --- .../ContributionMessages/ContributionMessagesFormular.vue | 1 + .../ContributionMessages/ContributionMessagesList.vue | 4 ++++ frontend/src/components/Contributions/ContributionList.vue | 4 ++++ .../src/components/Contributions/ContributionListItem.vue | 4 ++++ frontend/src/pages/Community.vue | 4 ++++ 5 files changed, 17 insertions(+) diff --git a/frontend/src/components/ContributionMessages/ContributionMessagesFormular.vue b/frontend/src/components/ContributionMessages/ContributionMessagesFormular.vue index 80708726c..7ec3c4ff9 100644 --- a/frontend/src/components/ContributionMessages/ContributionMessagesFormular.vue +++ b/frontend/src/components/ContributionMessages/ContributionMessagesFormular.vue @@ -52,6 +52,7 @@ export default { }) .then((result) => { this.$emit('get-list-contribution-messages', this.contributionId) + this.$emit('update-state', this.contributionId) this.form.text = '' this.toastSuccess(result) }) diff --git a/frontend/src/components/ContributionMessages/ContributionMessagesList.vue b/frontend/src/components/ContributionMessages/ContributionMessagesList.vue index 98e92e6e7..896487160 100644 --- a/frontend/src/components/ContributionMessages/ContributionMessagesList.vue +++ b/frontend/src/components/ContributionMessages/ContributionMessagesList.vue @@ -10,6 +10,7 @@ class="mt-5" :contributionId="contributionId" @get-list-contribution-messages="getListContributionMessages" + @update-state="updateState" />
    @@ -41,6 +42,9 @@ export default { getListContributionMessages() { this.$emit('get-list-contribution-messages', this.contributionId) }, + updateState(id) { + this.$emit('update-state', id) + }, }, } diff --git a/frontend/src/components/Contributions/ContributionList.vue b/frontend/src/components/Contributions/ContributionList.vue index 724a69281..11cc0f9dd 100644 --- a/frontend/src/components/Contributions/ContributionList.vue +++ b/frontend/src/components/Contributions/ContributionList.vue @@ -6,6 +6,7 @@ :contributionId="item.id" @update-contribution-form="updateContributionForm" @delete-contribution="deleteContribution" + @update-state="updateState" />
    @@ -186,6 +187,9 @@ export default { this.toastError(error.message) }) }, + updateState(id) { + this.$emit('update-state', id) + }, }, } diff --git a/frontend/src/pages/Community.vue b/frontend/src/pages/Community.vue index 5f9eb57f6..1753ca5d2 100644 --- a/frontend/src/pages/Community.vue +++ b/frontend/src/pages/Community.vue @@ -43,6 +43,7 @@ @update-list-contributions="updateListContributions" @update-contribution-form="updateContributionForm" @delete-contribution="deleteContribution" + @update-state="updateState" :contributionCount="contributionCount" :showPagination="true" :pageSize="pageSize" @@ -259,6 +260,9 @@ export default { updateTransactions(pagination) { this.$emit('update-transactions', pagination) }, + updateState(id) { + this.items.find((item) => item.id === id).state = 'PENDING' + }, }, created() { // verifyLogin is important at this point so that creation is updated on reload if they are deleted in a session in the admin area. From 40475ecb37953b3a06f0ee655235a57b85316466 Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 29 Aug 2022 10:20:12 +0200 Subject: [PATCH 594/977] add locales key form.replay --- frontend/src/locales/de.json | 1 + frontend/src/locales/en.json | 1 + frontend/src/locales/es.json | 1 + frontend/src/locales/fr.json | 1 + frontend/src/locales/nl.json | 1 + 5 files changed, 5 insertions(+) diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index 1296616d3..008dc7705 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -132,6 +132,7 @@ "password_new_repeat": "Neues Passwort wiederholen", "password_old": "Altes Passwort", "recipient": "Empfänger", + "reply": "Antworten", "reset": "Zurücksetzen", "save": "Speichern", "scann_code": "QR Code Scanner - Scanne den QR Code deines Partners", diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index ee31350ce..394f74a7a 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -132,6 +132,7 @@ "password_new_repeat": "Repeat new password", "password_old": "Old password", "recipient": "Recipient", + "reply": "Reply", "reset": "Reset", "save": "Save", "scann_code": "QR Code Scanner - Scan the QR Code of your partner", diff --git a/frontend/src/locales/es.json b/frontend/src/locales/es.json index fa6613092..b871e7168 100644 --- a/frontend/src/locales/es.json +++ b/frontend/src/locales/es.json @@ -132,6 +132,7 @@ "password_new_repeat": "Repetir contraseña nueva", "password_old": "contraseña antigua", "recipient": "Destinatario", + "reply": "Respuesta", "reset": "Restablecer", "save": "Guardar", "scann_code": "QR Code Scanner - Escanea el código QR de tu pareja", diff --git a/frontend/src/locales/fr.json b/frontend/src/locales/fr.json index 948f1b0fe..eea99d57c 100644 --- a/frontend/src/locales/fr.json +++ b/frontend/src/locales/fr.json @@ -132,6 +132,7 @@ "password_new_repeat": "Répétez le nouveau mot de passe", "password_old": "Ancien mot de passe", "recipient": "Destinataire", + "reply": "Répondre", "reset": "Réinitialiser", "save": "Sauvegarder", "scann_code": "QR Code Scanner - Scannez le QR code de votre partenaire", diff --git a/frontend/src/locales/nl.json b/frontend/src/locales/nl.json index 69896cbea..13a1b2124 100644 --- a/frontend/src/locales/nl.json +++ b/frontend/src/locales/nl.json @@ -132,6 +132,7 @@ "password_new_repeat": "Nieuw wachtwoord herhalen", "password_old": "Oud wachtwoord", "recipient": "Ontvanger", + "reply": "Antwoord", "reset": "Resetten", "save": "Opslaan", "scann_code": "QR Code Scanner - Scan de QR Code van uw partner", From 0cfd0f00977c766a4a073055e043ad103bc5891c Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 29 Aug 2022 10:21:50 +0200 Subject: [PATCH 595/977] add locales key form.reply --- .../ContributionMessages/ContributionMessagesFormular.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/ContributionMessages/ContributionMessagesFormular.vue b/frontend/src/components/ContributionMessages/ContributionMessagesFormular.vue index 7ec3c4ff9..440f9781a 100644 --- a/frontend/src/components/ContributionMessages/ContributionMessagesFormular.vue +++ b/frontend/src/components/ContributionMessages/ContributionMessagesFormular.vue @@ -14,7 +14,7 @@ {{ $t('form.reset') }} - {{ $t('form.submit') }} + {{ $t('form.reply') }} From 6bd02a2d4bf298d909b1532ff1010e212f397add Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 29 Aug 2022 11:12:31 +0200 Subject: [PATCH 596/977] add method updateState and emits --- .../ContributionMessagesFormular.vue | 1 + .../ContributionMessagesList.vue | 15 ++++----------- .../src/components/Tables/OpenCreationsTable.vue | 10 ++++++++-- admin/src/pages/CreationConfirm.vue | 7 +++++++ 4 files changed, 20 insertions(+), 13 deletions(-) diff --git a/admin/src/components/ContributionMessages/ContributionMessagesFormular.vue b/admin/src/components/ContributionMessages/ContributionMessagesFormular.vue index c04f8a573..06085dec7 100644 --- a/admin/src/components/ContributionMessages/ContributionMessagesFormular.vue +++ b/admin/src/components/ContributionMessages/ContributionMessagesFormular.vue @@ -52,6 +52,7 @@ export default { }) .then((result) => { this.$emit('get-list-contribution-messages', this.contributionId) + this.$emit('update-state', this.contributionId) this.form.text = '' this.toastSuccess(result) }) diff --git a/admin/src/components/ContributionMessages/ContributionMessagesList.vue b/admin/src/components/ContributionMessages/ContributionMessagesList.vue index 15762b18d..c5863cdc3 100644 --- a/admin/src/components/ContributionMessages/ContributionMessagesList.vue +++ b/admin/src/components/ContributionMessages/ContributionMessagesList.vue @@ -4,21 +4,13 @@ {{ messages.lenght }}
    - -
    @@ -46,7 +38,6 @@ export default { }, methods: { getListContributionMessages(id) { - // console.log('getListContributionMessages', id) this.messages = [] this.$apollo .query({ @@ -57,13 +48,15 @@ export default { fetchPolicy: 'no-cache', }) .then((result) => { - // console.log('result', result.data.listContributionMessages) this.messages = result.data.listContributionMessages.messages }) .catch((error) => { this.toastError(error.message) }) }, + updateState(id) { + this.$emit('update-state', id) + }, }, created() { this.getListContributionMessages(this.contributionId) diff --git a/admin/src/components/Tables/OpenCreationsTable.vue b/admin/src/components/Tables/OpenCreationsTable.vue index 50ae6df97..86c5ecce6 100644 --- a/admin/src/components/Tables/OpenCreationsTable.vue +++ b/admin/src/components/Tables/OpenCreationsTable.vue @@ -57,11 +57,14 @@ :row="row" :creationUserData="creationUserData" @update-creation-data="updateCreationData" - @update-user-data="updateUserData" />
    - +
    @@ -116,6 +119,9 @@ export default { updateUserData(rowItem, newCreation) { rowItem.creation = newCreation }, + updateState(id) { + this.$emit('update-state', id) + }, }, } diff --git a/admin/src/pages/CreationConfirm.vue b/admin/src/pages/CreationConfirm.vue index c07e6b351..c94d84cbd 100644 --- a/admin/src/pages/CreationConfirm.vue +++ b/admin/src/pages/CreationConfirm.vue @@ -9,6 +9,7 @@ :fields="fields" @remove-creation="removeCreation" @show-overlay="showOverlay" + @update-state="updateState" />
    @@ -79,6 +80,7 @@ export default { .then((result) => { this.$store.commit('resetOpenCreations') this.pendingCreations = result.data.listUnconfirmedContributions + console.log(this.pendingCreations) this.$store.commit('setOpenCreations', result.data.listUnconfirmedContributions.length) }) .catch((error) => { @@ -93,6 +95,11 @@ export default { this.overlay = true this.item = item }, + updateState(id) { + console.log('admin updateState', id) + console.log(this.pendingCreations) + this.pendingCreations.find((item) => item.id === id).state = 'IN_PROGRESS' + }, }, computed: { fields() { From 6acb944ac05a63b871b789eaa1526218c03c9a2d Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 29 Aug 2022 11:17:45 +0200 Subject: [PATCH 597/977] delete unused local keys --- admin/src/locales/de.json | 3 +-- admin/src/locales/en.json | 3 +-- admin/src/pages/CreationConfirm.vue | 3 --- 3 files changed, 2 insertions(+), 7 deletions(-) diff --git a/admin/src/locales/de.json b/admin/src/locales/de.json index a9e18f165..b3b587e9a 100644 --- a/admin/src/locales/de.json +++ b/admin/src/locales/de.json @@ -159,6 +159,5 @@ }, "user_deleted": "Nutzer ist gelöscht.", "user_recovered": "Nutzer ist wiederhergestellt.", - "user_search": "Nutzer-Suche", - "preview": "Vorschau" + "user_search": "Nutzer-Suche" } diff --git a/admin/src/locales/en.json b/admin/src/locales/en.json index 9b5ab107a..ee6ca1b63 100644 --- a/admin/src/locales/en.json +++ b/admin/src/locales/en.json @@ -159,6 +159,5 @@ }, "user_deleted": "User is deleted.", "user_recovered": "User is recovered.", - "user_search": "User search", - "preview": "Preview" + "user_search": "User search" } diff --git a/admin/src/pages/CreationConfirm.vue b/admin/src/pages/CreationConfirm.vue index c94d84cbd..595bd56b2 100644 --- a/admin/src/pages/CreationConfirm.vue +++ b/admin/src/pages/CreationConfirm.vue @@ -80,7 +80,6 @@ export default { .then((result) => { this.$store.commit('resetOpenCreations') this.pendingCreations = result.data.listUnconfirmedContributions - console.log(this.pendingCreations) this.$store.commit('setOpenCreations', result.data.listUnconfirmedContributions.length) }) .catch((error) => { @@ -96,8 +95,6 @@ export default { this.item = item }, updateState(id) { - console.log('admin updateState', id) - console.log(this.pendingCreations) this.pendingCreations.find((item) => item.id === id).state = 'IN_PROGRESS' }, }, From c76a58b59b041a1803c1563aae38e638de8e7a30 Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 29 Aug 2022 11:18:31 +0200 Subject: [PATCH 598/977] delete v-toogle from element --- frontend/src/components/Contributions/ContributionListItem.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/Contributions/ContributionListItem.vue b/frontend/src/components/Contributions/ContributionListItem.vue index 56f71bb66..78ba6f0fe 100644 --- a/frontend/src/components/Contributions/ContributionListItem.vue +++ b/frontend/src/components/Contributions/ContributionListItem.vue @@ -2,7 +2,7 @@
    -
    +
    Date: Mon, 29 Aug 2022 11:49:12 +0200 Subject: [PATCH 599/977] fix locales --- frontend/src/locales/de.json | 6 +++--- frontend/src/locales/en.json | 6 +++--- frontend/src/locales/es.json | 6 +++--- frontend/src/locales/fr.json | 6 +++--- frontend/src/locales/nl.json | 6 +++--- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index 008dc7705..4ebedf0a5 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -35,13 +35,13 @@ "contribution": { "activity": "Tätigkeit", "alert": { + "answerQuestion": "Bitte beantworte die Nachfrage", "communityNoteList": "Hier findest du alle eingereichten und bestätigten Beiträge von allen Mitgliedern aus dieser Gemeinschaft.", "confirm": "bestätigt", + "in_progress": "Es gibt eine Rückfrage der Moderatoren.", "myContributionNoteList": "Eingereichte Beiträge, die noch nicht bestätigt wurden, kannst du jederzeit bearbeiten oder löschen.", "pending": "Eingereicht und wartet auf Bestätigung", - "rejected": "abgelehnt", - "in_progress": "Es gibt eine Rückfrage der Moderatoren.", - "answerQuestion": "Bitte beantworte die Nachfrage" + "rejected": "abgelehnt" }, "date": "Beitrag für:", "delete": "Beitrag löschen! Bist du sicher?", diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index 394f74a7a..f0cb341c0 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -35,13 +35,13 @@ "contribution": { "activity": "Activity", "alert": { + "answerQuestion": "Please answer the question", "communityNoteList": "Here you will find all submitted and confirmed contributions from all members of this community.", "confirm": "confirmed", + "in_progress": "Es gibt eine Rückfrage der Moderatoren.", "myContributionNoteList": "You can edit or delete entries that have not yet been confirmed at any time.", "pending": "Submitted and waiting for confirmation", - "rejected": "deleted", - "in_progress": "Es gibt eine Rückfrage der Moderatoren.", - "answerQuestion": "Please answer the question" + "rejected": "deleted" }, "date": "Contribution for:", "delete": "Delete Contribution! Are you sure?", diff --git a/frontend/src/locales/es.json b/frontend/src/locales/es.json index b871e7168..4cefe2905 100644 --- a/frontend/src/locales/es.json +++ b/frontend/src/locales/es.json @@ -35,13 +35,13 @@ "contribution": { "activity": "Actividad", "alert": { + "answerQuestion": "Please answer the question", "communityNoteList": "Aquí encontrarás todas las contribuciones enviadas y confirmadas de todos los miembros de esta comunidad.", "confirm": "confirmado", + "in_progress": "Es gibt eine Rückfrage der Moderatoren.", "myContributionNoteList": "Puedes editar o eliminar las contribuciones enviadas que aún no han sido confirmadas en cualquier momento.", "pending": "Enviado y a la espera de confirmación", - "rejected": "rechazado", - "in_progress": "Es gibt eine Rückfrage der Moderatoren.", - "answerQuestion": "Please answer the question" + "rejected": "rechazado" }, "date": "Contribución para:", "delete": "Eliminar la contribución. ¿Estás seguro?", diff --git a/frontend/src/locales/fr.json b/frontend/src/locales/fr.json index eea99d57c..a35e6ce30 100644 --- a/frontend/src/locales/fr.json +++ b/frontend/src/locales/fr.json @@ -35,13 +35,13 @@ "contribution": { "activity": "Activité", "alert": { + "answerQuestion": "Please answer the question", "communityNoteList": "Vous trouverez ci-contre toutes les contributions versées et certifiées de tous les membres de cette communauté.", "confirm": " Approuvé", + "in_progress": "Es gibt eine Rückfrage der Moderatoren.", "myContributionNoteList": "À tout moment vous pouvez éditer ou supprimer les données qui n´ont pas été confirmées.", "pending": "Inscription en attente de validation", - "rejected": "supprimé", - "in_progress": "Es gibt eine Rückfrage der Moderatoren.", - "answerQuestion": "Please answer the question" + "rejected": "supprimé" }, "date": "Contribution pour:", "delete": "Supprimer la contribution! Êtes-vous sûr?", diff --git a/frontend/src/locales/nl.json b/frontend/src/locales/nl.json index 13a1b2124..c301b9201 100644 --- a/frontend/src/locales/nl.json +++ b/frontend/src/locales/nl.json @@ -35,13 +35,13 @@ "contribution": { "activity": "Activiteit", "alert": { + "answerQuestion": "Please answer the question", "communityNoteList": "Hier vind je alle ingediende en bevestigde bijdragen van alle leden uit deze gemeenschap.", "confirm": "bevestigt", + "in_progress": "Es gibt eine Rückfrage der Moderatoren.", "myContributionNoteList": "Ingediende bijdragen, die nog niet bevestigd zijn, kun je op elk moment wijzigen of verwijderen.", "pending": "Ingediend en wacht op bevestiging", - "rejected": "afgewezen", - "in_progress": "Es gibt eine Rückfrage der Moderatoren.", - "answerQuestion": "Please answer the question" + "rejected": "afgewezen" }, "date": "Bijdrage voor:", "delete": "Bijdrage verwijderen! Weet je het zeker?", From efaf02facc9f06cecd2f7f4c3869bd3a6de17e91 Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 29 Aug 2022 11:49:38 +0200 Subject: [PATCH 600/977] fix locales adminarea --- admin/src/locales/de.json | 4 ++-- admin/src/locales/en.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/admin/src/locales/de.json b/admin/src/locales/de.json index b3b587e9a..b8ad45af1 100644 --- a/admin/src/locales/de.json +++ b/admin/src/locales/de.json @@ -70,8 +70,8 @@ "short_hash": "({shortHash})" }, "form": { - "submit": "absenden", - "reset": "löschen" + "reset": "löschen", + "submit": "absenden" }, "GDD": "GDD", "hide_details": "Details verbergen", diff --git a/admin/src/locales/en.json b/admin/src/locales/en.json index ee6ca1b63..bc8c297f5 100644 --- a/admin/src/locales/en.json +++ b/admin/src/locales/en.json @@ -70,8 +70,8 @@ "short_hash": "({shortHash})" }, "form": { - "submit": "submit", - "reset": "reset" + "reset": "reset", + "submit": "submit" }, "GDD": "GDD", "hide_details": "Hide details", From 423989777b91898b5a9b698956c72537aacd1a8f Mon Sep 17 00:00:00 2001 From: elweyn Date: Mon, 29 Aug 2022 12:19:25 +0200 Subject: [PATCH 601/977] Remove leftJoin on user, changed ContributionMessage array to count of ContributionMessage. --- backend/src/graphql/model/Contribution.ts | 9 +++------ backend/src/graphql/resolver/ContributionResolver.ts | 1 - 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/backend/src/graphql/model/Contribution.ts b/backend/src/graphql/model/Contribution.ts index c0e6d66f3..1f690a3d8 100644 --- a/backend/src/graphql/model/Contribution.ts +++ b/backend/src/graphql/model/Contribution.ts @@ -2,7 +2,6 @@ import { ObjectType, Field, Int } from 'type-graphql' import Decimal from 'decimal.js-light' import { Contribution as dbContribution } from '@entity/Contribution' import { User } from '@entity/User' -import { ContributionMessage } from './ContributionMessage' @ObjectType() export class Contribution { @@ -18,9 +17,7 @@ export class Contribution { this.confirmedBy = contribution.confirmedBy this.contributionDate = contribution.contributionDate this.state = contribution.contributionStatus - this.messages = contribution.messages - ? contribution.messages.map((message) => new ContributionMessage(message, message.user)) - : [] + this.messagesCount = contribution.messages ? contribution.messages.length : 0 } @Field(() => Number) @@ -53,8 +50,8 @@ export class Contribution { @Field(() => Date) contributionDate: Date - @Field(() => [ContributionMessage]) - messages: ContributionMessage[] + @Field(() => Number) + messagesCount: number @Field(() => String) state: string diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index f8300f164..fc93880f1 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -97,7 +97,6 @@ export class ContributionResolver { .select('c') .from(dbContribution, 'c') .leftJoinAndSelect('c.messages', 'm') - .leftJoinAndSelect('m.user', 'u') .where(where) .orderBy('c.createdAt', order) .limit(pageSize) From 214f85544b64c82911c1a5c85d8ac09578bb61ae Mon Sep 17 00:00:00 2001 From: elweyn Date: Mon, 29 Aug 2022 12:24:09 +0200 Subject: [PATCH 602/977] ContributionMessage is only defined in 0047 so remove the OneToMany relation from 0046 User and add it to 0047 User. --- .../User.ts | 5 - database/entity/0047-messages_tables/User.ts | 116 ++++++++++++++++++ database/entity/User.ts | 2 +- 3 files changed, 117 insertions(+), 6 deletions(-) create mode 100644 database/entity/0047-messages_tables/User.ts diff --git a/database/entity/0046-adapt_users_table_for_gradidoid/User.ts b/database/entity/0046-adapt_users_table_for_gradidoid/User.ts index a772a3c99..3f2547cad 100644 --- a/database/entity/0046-adapt_users_table_for_gradidoid/User.ts +++ b/database/entity/0046-adapt_users_table_for_gradidoid/User.ts @@ -8,7 +8,6 @@ import { JoinColumn, } from 'typeorm' import { Contribution } from '../Contribution' -import { ContributionMessage } from '../ContributionMessage' @Entity('users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) export class User extends BaseEntity { @@ -109,8 +108,4 @@ export class User extends BaseEntity { @OneToMany(() => Contribution, (contribution) => contribution.user) @JoinColumn({ name: 'user_id' }) contributions?: Contribution[] - - @OneToMany(() => ContributionMessage, (message) => message.user) - @JoinColumn({ name: 'user_id' }) - messages?: ContributionMessage[] } diff --git a/database/entity/0047-messages_tables/User.ts b/database/entity/0047-messages_tables/User.ts new file mode 100644 index 000000000..a772a3c99 --- /dev/null +++ b/database/entity/0047-messages_tables/User.ts @@ -0,0 +1,116 @@ +import { + BaseEntity, + Entity, + PrimaryGeneratedColumn, + Column, + DeleteDateColumn, + OneToMany, + JoinColumn, +} from 'typeorm' +import { Contribution } from '../Contribution' +import { ContributionMessage } from '../ContributionMessage' + +@Entity('users', { engine: 'InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci' }) +export class User extends BaseEntity { + @PrimaryGeneratedColumn('increment', { unsigned: true }) + id: number + + @Column({ + name: 'gradido_id', + length: 36, + nullable: false, + unique: true, + collation: 'utf8mb4_unicode_ci', + }) + gradidoID: string + + @Column({ + name: 'alias', + length: 20, + nullable: true, + unique: true, + default: null, + collation: 'utf8mb4_unicode_ci', + }) + alias: string + + @Column({ name: 'public_key', type: 'binary', length: 32, default: null, nullable: true }) + pubKey: Buffer + + @Column({ name: 'privkey', type: 'binary', length: 80, default: null, nullable: true }) + privKey: Buffer + + @Column({ length: 255, unique: true, nullable: false, collation: 'utf8mb4_unicode_ci' }) + email: string + + @Column({ + name: 'first_name', + length: 255, + nullable: true, + default: null, + collation: 'utf8mb4_unicode_ci', + }) + firstName: string + + @Column({ + name: 'last_name', + length: 255, + nullable: true, + default: null, + collation: 'utf8mb4_unicode_ci', + }) + lastName: string + + @DeleteDateColumn() + deletedAt: Date | null + + @Column({ type: 'bigint', default: 0, unsigned: true }) + password: BigInt + + @Column({ name: 'email_hash', type: 'binary', length: 32, default: null, nullable: true }) + emailHash: Buffer + + @Column({ name: 'created', default: () => 'CURRENT_TIMESTAMP', nullable: false }) + createdAt: Date + + @Column({ name: 'email_checked', type: 'bool', nullable: false, default: false }) + emailChecked: boolean + + @Column({ length: 4, default: 'de', collation: 'utf8mb4_unicode_ci', nullable: false }) + language: string + + @Column({ name: 'is_admin', type: 'datetime', nullable: true, default: null }) + isAdmin: Date | null + + @Column({ name: 'referrer_id', type: 'int', unsigned: true, nullable: true, default: null }) + referrerId?: number | null + + @Column({ + name: 'contribution_link_id', + type: 'int', + unsigned: true, + nullable: true, + default: null, + }) + contributionLinkId?: number | null + + @Column({ name: 'publisher_id', default: 0 }) + publisherId: number + + @Column({ + type: 'text', + name: 'passphrase', + collation: 'utf8mb4_unicode_ci', + nullable: true, + default: null, + }) + passphrase: string + + @OneToMany(() => Contribution, (contribution) => contribution.user) + @JoinColumn({ name: 'user_id' }) + contributions?: Contribution[] + + @OneToMany(() => ContributionMessage, (message) => message.user) + @JoinColumn({ name: 'user_id' }) + messages?: ContributionMessage[] +} diff --git a/database/entity/User.ts b/database/entity/User.ts index 02a99fcd1..7d15bf559 100644 --- a/database/entity/User.ts +++ b/database/entity/User.ts @@ -1 +1 @@ -export { User } from './0046-adapt_users_table_for_gradidoid/User' +export { User } from './0047-messages_tables/User' From 61d763030af88ffb0dc409659ec50ac6dd43bcda Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 29 Aug 2022 12:54:32 +0200 Subject: [PATCH 603/977] change state if messagesCount 0 --- admin/src/pages/CreationConfirm.vue | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/admin/src/pages/CreationConfirm.vue b/admin/src/pages/CreationConfirm.vue index 595bd56b2..f518e1f00 100644 --- a/admin/src/pages/CreationConfirm.vue +++ b/admin/src/pages/CreationConfirm.vue @@ -95,7 +95,10 @@ export default { this.item = item }, updateState(id) { - this.pendingCreations.find((item) => item.id === id).state = 'IN_PROGRESS' + this.pendingCreations.find((value) => { + value.state = 'IN_PROGRESS' + value.messageCount = value.messageCount + 1 + }) }, }, computed: { From 7156f1afd5a0c9a3166acc441eaf7fc61bd286d6 Mon Sep 17 00:00:00 2001 From: elweyn Date: Mon, 29 Aug 2022 12:58:01 +0200 Subject: [PATCH 604/977] Setup Test file for ContributionMessageResolver. --- .../ContributionMessageResolver.test.ts | 47 +++++++++++++++++++ backend/src/seeds/graphql/mutations.ts | 28 +++++++++++ backend/src/seeds/graphql/queries.ts | 23 +++++++++ 3 files changed, 98 insertions(+) create mode 100644 backend/src/graphql/resolver/ContributionMessageResolver.test.ts diff --git a/backend/src/graphql/resolver/ContributionMessageResolver.test.ts b/backend/src/graphql/resolver/ContributionMessageResolver.test.ts new file mode 100644 index 000000000..f98e4f211 --- /dev/null +++ b/backend/src/graphql/resolver/ContributionMessageResolver.test.ts @@ -0,0 +1,47 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ + +import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' +import { cleanDB, resetToken, testEnvironment } from '@test/helpers' +import { GraphQLError } from 'graphql' +import { userFactory } from '@/seeds/factory/user' +import { creationFactory } from '@/seeds/factory/creation' +import { creations } from '@/seeds/creation/index' +import { peterLustig } from '@/seeds/users/peter-lustig' +import { createContributionMessage } from '@/seeds/graphql/mutations' + +let mutate: any, query: any, con: any +let testEnv: any +let result: any + +beforeAll(async () => { + testEnv = await testEnvironment() + mutate = testEnv.mutate + query = testEnv.query + con = testEnv.con + await cleanDB() +}) + +afterAll(async () => { + await cleanDB() + await con.close() +}) + +describe('ContributionMessageResolver', () => { + describe('createContributionMessage', () => { + describe('unauthenticated', () => { + it('returns an error', async () => { + await expect( + mutate({ + mutation: createContributionMessage, + variables: { contributionId: 1, message: 'This is a test message' }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('401 Unauthorized')], + }), + ) + }) + }) + }) +}) diff --git a/backend/src/seeds/graphql/mutations.ts b/backend/src/seeds/graphql/mutations.ts index bf898bd7d..e5f290645 100644 --- a/backend/src/seeds/graphql/mutations.ts +++ b/backend/src/seeds/graphql/mutations.ts @@ -261,3 +261,31 @@ export const deleteContribution = gql` deleteContribution(id: $id) } ` + +export const createContributionMessage = gql` + mutation ($contributionId: Float!, $message: String!) { + createContributionMessage(contributionId: $contributionId, message: $message) { + id + message + createdAt + updatedAt + type + userFirstName + userLastName + } + } +` + +export const adminCreateContributionMessage = gql` + mutation ($contributionId: Float!, $message: String!) { + adminCreateContributionMessage(contributionId: $contributionId, message: $message) { + id + message + createdAt + updatedAt + type + userFirstName + userLastName + } + } +` diff --git a/backend/src/seeds/graphql/queries.ts b/backend/src/seeds/graphql/queries.ts index 3bd042ac2..60dffa21b 100644 --- a/backend/src/seeds/graphql/queries.ts +++ b/backend/src/seeds/graphql/queries.ts @@ -292,3 +292,26 @@ export const searchAdminUsers = gql` } } ` + +export const listContributionMessages = gql` + query ($contributionId: Float!, $pageSize: Int = 25, $currentPage: Int = 1, $order: Order = ASC) { + listContributionMessages( + contributionId: $contributionId + pageSize: $pageSize + currentPage: $currentPage + order: $order + ) { + count + messages { + id + message + createdAt + updatedAt + type + userFirstName + userLastName + userId + } + } + } +` From 8b62696c91aaa8116dc5960360d586f99a6dc136 Mon Sep 17 00:00:00 2001 From: elweyn Date: Mon, 29 Aug 2022 13:07:24 +0200 Subject: [PATCH 605/977] Add test that listContributionMessages throws error for non authenticated user. --- .../ContributionMessageResolver.test.ts | 26 ++++++++++++++----- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionMessageResolver.test.ts b/backend/src/graphql/resolver/ContributionMessageResolver.test.ts index f98e4f211..8d65db306 100644 --- a/backend/src/graphql/resolver/ContributionMessageResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionMessageResolver.test.ts @@ -1,18 +1,13 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' -import { cleanDB, resetToken, testEnvironment } from '@test/helpers' +import { cleanDB, testEnvironment } from '@test/helpers' import { GraphQLError } from 'graphql' -import { userFactory } from '@/seeds/factory/user' -import { creationFactory } from '@/seeds/factory/creation' -import { creations } from '@/seeds/creation/index' -import { peterLustig } from '@/seeds/users/peter-lustig' import { createContributionMessage } from '@/seeds/graphql/mutations' +import { listContributionMessages } from '@/seeds/graphql/queries' let mutate: any, query: any, con: any let testEnv: any -let result: any beforeAll(async () => { testEnv = await testEnvironment() @@ -44,4 +39,21 @@ describe('ContributionMessageResolver', () => { }) }) }) + + describe('listContributionMessages', () => { + describe('unauthenticated', () => { + it('returns an error', async () => { + await expect( + mutate({ + mutation: listContributionMessages, + variables: { contributionId: 1 }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('401 Unauthorized')], + }), + ) + }) + }) + }) }) From ac4f7dc04a193b4594cbf37740d3e81bf85d4794 Mon Sep 17 00:00:00 2001 From: elweyn Date: Mon, 29 Aug 2022 13:16:44 +0200 Subject: [PATCH 606/977] Add test with non existing contributionId. --- .../ContributionMessageResolver.test.ts | 54 ++++++++++++++++++- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionMessageResolver.test.ts b/backend/src/graphql/resolver/ContributionMessageResolver.test.ts index 8d65db306..c66a85700 100644 --- a/backend/src/graphql/resolver/ContributionMessageResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionMessageResolver.test.ts @@ -1,10 +1,12 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -import { cleanDB, testEnvironment } from '@test/helpers' +import { cleanDB, resetToken, testEnvironment } from '@test/helpers' import { GraphQLError } from 'graphql' import { createContributionMessage } from '@/seeds/graphql/mutations' -import { listContributionMessages } from '@/seeds/graphql/queries' +import { listContributionMessages, login } from '@/seeds/graphql/queries' +import { userFactory } from '@/seeds/factory/user' +import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg' let mutate: any, query: any, con: any let testEnv: any @@ -38,6 +40,39 @@ describe('ContributionMessageResolver', () => { ) }) }) + + describe('authenticated', () => { + beforeAll(async () => { + await userFactory(testEnv, bibiBloxberg) + await query({ + query: login, + variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, + }) + }) + + afterAll(async () => { + await cleanDB() + resetToken() + }) + + describe('input not valid', () => { + it('throws error when contribution does not exist', async () => { + await expect( + mutate({ + mutation: createContributionMessage, + variables: { + contributionId: -1, + message: 'Test', + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('Contribution not found')], + }), + ) + }) + }) + }) }) describe('listContributionMessages', () => { @@ -55,5 +90,20 @@ describe('ContributionMessageResolver', () => { ) }) }) + + describe('authenticated', () => { + beforeAll(async () => { + await userFactory(testEnv, bibiBloxberg) + await query({ + query: login, + variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' }, + }) + }) + + afterAll(async () => { + await cleanDB() + resetToken() + }) + }) }) }) From 4f02fcc9900875a4b1b7579e592268f23d300241 Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 29 Aug 2022 13:18:28 +0200 Subject: [PATCH 607/977] add close on contribution messages list box --- admin/src/pages/CreationConfirm.vue | 1 + .../ContributionMessagesList.vue | 4 ++++ .../Contributions/ContributionListItem.vue | 16 +++++++++++++--- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/admin/src/pages/CreationConfirm.vue b/admin/src/pages/CreationConfirm.vue index f518e1f00..ffefe5d3f 100644 --- a/admin/src/pages/CreationConfirm.vue +++ b/admin/src/pages/CreationConfirm.vue @@ -98,6 +98,7 @@ export default { this.pendingCreations.find((value) => { value.state = 'IN_PROGRESS' value.messageCount = value.messageCount + 1 + return null }) }, }, diff --git a/frontend/src/components/ContributionMessages/ContributionMessagesList.vue b/frontend/src/components/ContributionMessages/ContributionMessagesList.vue index 896487160..5303b1f11 100644 --- a/frontend/src/components/ContributionMessages/ContributionMessagesList.vue +++ b/frontend/src/components/ContributionMessages/ContributionMessagesList.vue @@ -12,6 +12,10 @@ @get-list-contribution-messages="getListContributionMessages" @update-state="updateState" /> +
    + + {{ $t('form.close') }} +
    From 52524120ba257d8bb77e7ab407a98aeafa89e31c Mon Sep 17 00:00:00 2001 From: ogerly Date: Thu, 22 Sep 2022 15:11:55 +0200 Subject: [PATCH 820/977] style: deleted max-rows 6 from all forms textareas --- .../ContributionMessages/ContributionMessagesFormular.vue | 1 - frontend/src/components/Contributions/ContributionForm.vue | 1 - 2 files changed, 2 deletions(-) diff --git a/admin/src/components/ContributionMessages/ContributionMessagesFormular.vue b/admin/src/components/ContributionMessages/ContributionMessagesFormular.vue index a0e790abe..c9c285eef 100644 --- a/admin/src/components/ContributionMessages/ContributionMessagesFormular.vue +++ b/admin/src/components/ContributionMessages/ContributionMessagesFormular.vue @@ -7,7 +7,6 @@ v-model="form.text" :placeholder="$t('contributionLink.memo')" rows="3" - max-rows="6" > diff --git a/frontend/src/components/Contributions/ContributionForm.vue b/frontend/src/components/Contributions/ContributionForm.vue index 3a9010ec2..47f2be4c4 100644 --- a/frontend/src/components/Contributions/ContributionForm.vue +++ b/frontend/src/components/Contributions/ContributionForm.vue @@ -42,7 +42,6 @@ id="contribution-memo" v-model="form.memo" rows="3" - max-rows="6" :placeholder="$t('contribution.yourActivity')" required > From 8b2a781be15ba34305e8ce755157acc6817be3d3 Mon Sep 17 00:00:00 2001 From: ogerly Date: Thu, 22 Sep 2022 15:14:58 +0200 Subject: [PATCH 821/977] style: deleted max-rows 6 from all forms textareas --- .../ContributionMessages/ContributionMessagesFormular.vue | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/components/ContributionMessages/ContributionMessagesFormular.vue b/frontend/src/components/ContributionMessages/ContributionMessagesFormular.vue index e3f9fd5e7..1a5928cc3 100644 --- a/frontend/src/components/ContributionMessages/ContributionMessagesFormular.vue +++ b/frontend/src/components/ContributionMessages/ContributionMessagesFormular.vue @@ -7,7 +7,6 @@ v-model="form.text" :placeholder="$t('form.memo')" rows="3" - max-rows="6" > From 79f7ebce57d2179d1b365de8dfb6f6118fde103f Mon Sep 17 00:00:00 2001 From: joseji Date: Thu, 22 Sep 2022 17:35:41 +0200 Subject: [PATCH 822/977] updated event working, deletion is not working properly (deeper than the event itself) --- backend/src/event/Event.ts | 16 ++++++++++++ backend/src/event/EventProtocolType.ts | 2 ++ .../resolver/ContributionResolver.test.ts | 21 ++++++++++++++++ .../graphql/resolver/ContributionResolver.ts | 25 ++++++++++++++++++- 4 files changed, 63 insertions(+), 1 deletion(-) diff --git a/backend/src/event/Event.ts b/backend/src/event/Event.ts index 6f07661f1..40eb333fd 100644 --- a/backend/src/event/Event.ts +++ b/backend/src/event/Event.ts @@ -48,6 +48,8 @@ export class EventTransactionCreation extends EventBasicUserId { export class EventTransactionReceive extends EventBasicTx {} export class EventTransactionReceiveRedeem extends EventBasicTx {} export class EventContributionCreate extends EventBasicCt {} +export class EventContributionDelete extends EventBasicCt {} +export class EventContributionUpdate extends EventBasicCt {} export class EventContributionConfirm extends EventBasicCt { xUserId: number xCommunityId: number @@ -206,6 +208,20 @@ export class Event { return this } + public setEventContributionDelete(ev: EventContributionDelete): Event { + this.setByBasicCt(ev.userId, ev.contributionId, ev.amount) + this.type = EventProtocolType.CONTRIBUTION_DELETE + + return this + } + + public setEventContributionUpdate(ev: EventContributionUpdate): Event { + this.setByBasicCt(ev.userId, ev.contributionId, ev.amount) + this.type = EventProtocolType.CONTRIBUTION_UPDATE + + return this + } + public setEventContributionConfirm(ev: EventContributionConfirm): Event { this.setByBasicCt(ev.userId, ev.contributionId, ev.amount) if (ev.xUserId) this.xUserId = ev.xUserId diff --git a/backend/src/event/EventProtocolType.ts b/backend/src/event/EventProtocolType.ts index 0f61f787a..c0fc1bb8e 100644 --- a/backend/src/event/EventProtocolType.ts +++ b/backend/src/event/EventProtocolType.ts @@ -21,4 +21,6 @@ export enum EventProtocolType { CONTRIBUTION_CONFIRM = 'CONTRIBUTION_CONFIRM', CONTRIBUTION_LINK_DEFINE = 'CONTRIBUTION_LINK_DEFINE', CONTRIBUTION_LINK_ACTIVATE_REDEEM = 'CONTRIBUTION_LINK_ACTIVATE_REDEEM', + CONTRIBUTION_DELETE = 'CONTRIBUTION_DELETE', + CONTRIBUTION_UPDATE = 'CONTRIBUTION_UPDATE', } diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index d08396285..683946633 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -19,6 +19,7 @@ import { peterLustig } from '@/seeds/users/peter-lustig' import { EventProtocol } from '@entity/EventProtocol' import { EventProtocolType } from '@/event/EventProtocolType' import { logger } from '@test/testSetup' +import { Contribution } from '@entity/Contribution' let mutate: any, query: any, con: any let testEnv: any @@ -587,6 +588,15 @@ describe('ContributionResolver', () => { }), ) }) + + it('stores the update contribution event in the database', async () => { + await expect(EventProtocol.find()).resolves.toContainEqual( + expect.objectContaining({ + type: EventProtocolType.CONTRIBUTION_UPDATE, + contributionId: result.data.createContribution.id, + }), + ) + }) }) }) }) @@ -763,6 +773,7 @@ describe('ContributionResolver', () => { describe('User deletes own contribution', () => { it('deletes successfully', async () => { + console.log(await Contribution.find({ id: result.data.createContribution.id })) await expect( mutate({ mutation: deleteContribution, @@ -772,6 +783,16 @@ describe('ContributionResolver', () => { }), ).resolves.toBeTruthy() }) + + it('stores the delete contribution event in the database', async () => { + console.log(await Contribution.find({ id: result.data.createContribution.id })) + await expect(EventProtocol.find()).resolves.toContainEqual( + expect.objectContaining({ + type: EventProtocolType.CONTRIBUTION_DELETE, + // id: result.data.createContribution.id, + }), + ) + }) }) describe('User deletes already confirmed contribution', () => { diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index 3c33a4e0f..9886eeb05 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -13,7 +13,12 @@ import { Contribution, ContributionListResult } from '@model/Contribution' import { UnconfirmedContribution } from '@model/UnconfirmedContribution' import { validateContribution, getUserCreation, updateCreations } from './util/creations' import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const' -import { Event, EventContributionCreate } from '@/event/Event' +import { + Event, + EventContributionCreate, + EventContributionDelete, + EventContributionUpdate, +} from '@/event/Event' import { eventProtocol } from '@/event/EventProtocolEmitter' @Resolver() @@ -56,6 +61,8 @@ export class ContributionResolver { const eventCreateContribution = new EventContributionCreate() eventCreateContribution.userId = user.id + eventCreateContribution.amount = amount + eventCreateContribution.contributionId = contribution.id await eventProtocol.writeEvent(event.setEventContributionCreate(eventCreateContribution)) return new UnconfirmedContribution(contribution, user, creations) @@ -67,6 +74,7 @@ export class ContributionResolver { @Arg('id', () => Int) id: number, @Ctx() context: Context, ): Promise { + const event = new Event() const user = getUser(context) const contribution = await dbContribution.findOne(id) if (!contribution) { @@ -81,8 +89,16 @@ export class ContributionResolver { logger.error('A confirmed contribution can not be deleted') throw new Error('A confirmed contribution can not be deleted') } + contribution.contributionStatus = ContributionStatus.DELETED + contribution.deletedAt = new Date() await contribution.save() + + const eventDeleteContribution = new EventContributionDelete() + eventDeleteContribution.userId = user.id + eventDeleteContribution.contributionId = contribution.id + await eventProtocol.writeEvent(event.setEventContributionDelete(eventDeleteContribution)) + const res = await contribution.softRemove() return !!res } @@ -188,6 +204,13 @@ export class ContributionResolver { contributionToUpdate.contributionStatus = ContributionStatus.PENDING dbContribution.save(contributionToUpdate) + const event = new Event() + + const eventUpdateContribution = new EventContributionUpdate() + eventUpdateContribution.userId = user.id + eventUpdateContribution.contributionId = contributionId + await eventProtocol.writeEvent(event.setEventContributionUpdate(eventUpdateContribution)) + return new UnconfirmedContribution(contributionToUpdate, user, creations) } } From de234cc7df28e4ba6795302b504cbe938fc1885e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Thu, 22 Sep 2022 23:29:51 +0200 Subject: [PATCH 823/977] rework PR remarks --- backend/.env.dist | 2 +- backend/.env.template | 1 - backend/src/config/index.ts | 3 +-- backend/src/server/createServer.ts | 6 +----- deployment/bare_metal/setup.md | 3 --- deployment/bare_metal/start.sh | 12 ++++++------ 6 files changed, 9 insertions(+), 18 deletions(-) diff --git a/backend/.env.dist b/backend/.env.dist index 06e0c3a64..648a2054c 100644 --- a/backend/.env.dist +++ b/backend/.env.dist @@ -38,7 +38,7 @@ LOGIN_SERVER_KEY=a51ef8ac7ef1abf162fb7a65261acd7a # EMail EMAIL=false EMAIL_TEST_MODUS=false -EMAIL_TEST_RECEIVER=test_team@gradido.net +EMAIL_TEST_RECEIVER=stage1@gradido.net EMAIL_USERNAME=gradido_email EMAIL_SENDER=info@gradido.net EMAIL_PASSWORD=xxx diff --git a/backend/.env.template b/backend/.env.template index bace78673..dddf845dc 100644 --- a/backend/.env.template +++ b/backend/.env.template @@ -5,7 +5,6 @@ JWT_SECRET=$JWT_SECRET JWT_EXPIRES_IN=$JWT_EXPIRES_IN GRAPHIQL=false GDT_API_URL=$GDT_API_URL -ENV_NAME=$ENV_NAME # Database DB_HOST=localhost diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index 462620b14..edda4fbbb 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -28,7 +28,6 @@ const server = { JWT_EXPIRES_IN: process.env.JWT_EXPIRES_IN || '10m', GRAPHIQL: process.env.GRAPHIQL === 'true' || false, GDT_API_URL: process.env.GDT_API_URL || 'https://gdt.gradido.net', - ENV_NAME: process.env.NODE_ENV || 'production', PRODUCTION: process.env.NODE_ENV === 'production' || false, } @@ -69,7 +68,7 @@ const loginServer = { const email = { EMAIL: process.env.EMAIL === 'true' || false, EMAIL_TEST_MODUS: process.env.EMAIL_TEST_MODUS === 'true' || 'false', - EMAIL_TEST_RECEIVER: process.env.EMAIL_TEST_RECEIVER || 'test_team@gradido.net', + EMAIL_TEST_RECEIVER: process.env.EMAIL_TEST_RECEIVER || 'stage1@gradido.net', EMAIL_USERNAME: process.env.EMAIL_USERNAME || 'gradido_email', EMAIL_SENDER: process.env.EMAIL_SENDER || 'info@gradido.net', EMAIL_PASSWORD: process.env.EMAIL_PASSWORD || 'xxx', diff --git a/backend/src/server/createServer.ts b/backend/src/server/createServer.ts index 3d89f7737..d1153cdb6 100644 --- a/backend/src/server/createServer.ts +++ b/backend/src/server/createServer.ts @@ -76,12 +76,8 @@ const createServer = async ( }) apollo.applyMiddleware({ app, path: '/' }) logger.info( - `running in GRADIDO_ENV_NAME=${CONFIG.ENV_NAME} as PRODUCTION=${CONFIG.PRODUCTION} and EMAIL_TEST_MODUS=${CONFIG.EMAIL_TEST_MODUS} ...`, + `running with PRODUCTION=${CONFIG.PRODUCTION}, sending EMAIL enabled=${CONFIG.EMAIL} and EMAIL_TEST_MODUS=${CONFIG.EMAIL_TEST_MODUS} ...`, ) - if (CONFIG.PRODUCTION && CONFIG.EMAIL_TEST_MODUS === 'true') { - logger.error(`### RUNNING ENVIRONMENT Production IN EMAIL_TEST_MODE IS NOT ALLOWED ###`) - throw new Error(`### RUNNING ENVIRONMENT Production IN EMAIL_TEST_MODE IS NOT ALLOWED ###`) - } logger.debug('createServer...successful') return { apollo, app, con } } diff --git a/deployment/bare_metal/setup.md b/deployment/bare_metal/setup.md index 2f9a702e3..652a0a5ce 100644 --- a/deployment/bare_metal/setup.md +++ b/deployment/bare_metal/setup.md @@ -95,9 +95,6 @@ > cp .env.dist .env > nano .env >> Adjust values accordingly -# Define name of gradido environment -> the env variable GRADIDO_ENV_NAME have to be set during system installation manually to "development, stage1, stage2, stage3, production" -> export GRADIDO_ENV_NAME=development # Define cronjob to compensate yarn output in /tmp > yarn creates output in /tmp directory, which must be deleted regularly and will be done per cronjob > on stage1 a hourly job is necessary by setting the following job in the crontab for the gradido user diff --git a/deployment/bare_metal/start.sh b/deployment/bare_metal/start.sh index 8b0277fa7..95b89241f 100755 --- a/deployment/bare_metal/start.sh +++ b/deployment/bare_metal/start.sh @@ -120,8 +120,8 @@ yarn build if [ "$DEPLOY_SEED_DATA" = "true" ]; then yarn seed fi -# the env variable GRADIDO_ENV_NAME have to be set during system installation manually (development, stage1, stage2, stage3) if it should differ from production -export NODE_ENV="${GRADIDO_ENV_NAME:=production}" +# TODO maybe handle this differently? +export NODE_ENV=production pm2 delete gradido-backend pm2 start --name gradido-backend "yarn --cwd $PROJECT_ROOT/backend start" -l $GRADIDO_LOG_PATH/pm2.backend.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS' pm2 save @@ -133,8 +133,8 @@ cd $PROJECT_ROOT/frontend unset NODE_ENV yarn install yarn build -# the env variable GRADIDO_ENV_NAME have to be set during system installation manually (development, stage1, stage2, stage3) if it should differ from production -export NODE_ENV="${GRADIDO_ENV_NAME:=production}" +# TODO maybe handle this differently? +export NODE_ENV=production pm2 delete gradido-frontend pm2 start --name gradido-frontend "yarn --cwd $PROJECT_ROOT/frontend start" -l $GRADIDO_LOG_PATH/pm2.frontend.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS' pm2 save @@ -146,8 +146,8 @@ cd $PROJECT_ROOT/admin unset NODE_ENV yarn install yarn build -# the env variable GRADIDO_ENV_NAME have to be set during system installation manually (development, stage1, stage2, stage3) if it should differ from production -export NODE_ENV="${GRADIDO_ENV_NAME:=production}" +# TODO maybe handle this differently? +export NODE_ENV=production pm2 delete gradido-admin pm2 start --name gradido-admin "yarn --cwd $PROJECT_ROOT/admin start" -l $GRADIDO_LOG_PATH/pm2.admin.$TODAY.log --log-date-format 'YYYY-MM-DD HH:mm:ss.SSS' pm2 save From 3dd66b4527cc37953c2fa6968153b40dc2b10084 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Fri, 23 Sep 2022 00:31:33 +0200 Subject: [PATCH 824/977] small changes in log-pattern Merge remote-tracking branch 'origin/master' into 2220-feature-reconfigure-log4js --- backend/log4js-config.json | 22 ++++++++++---------- backend/src/graphql/resolver/UserResolver.ts | 1 + 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/backend/log4js-config.json b/backend/log4js-config.json index a096713ec..e595e7c52 100644 --- a/backend/log4js-config.json +++ b/backend/log4js-config.json @@ -8,7 +8,7 @@ "pattern": "yyyy-MM-dd", "layout": { - "type": "pattern", "pattern": "%d{ISO8601} %p %c [%X{user}] %m" + "type": "pattern", "pattern": "%d{ISO8601} %p %c [%X{user}] [%f : %l] - %m" }, "keepFileExt" : true, "fileNameSep" : "_", @@ -21,7 +21,7 @@ "pattern": "yyyy-MM-dd", "layout": { - "type": "pattern", "pattern": "%d{ISO8601} %p %c [%X{user}] %m" + "type": "pattern", "pattern": "%d{ISO8601} %p %c [%X{user}] [%f : %l] - %m" }, "keepFileExt" : true, "fileNameSep" : "_", @@ -34,7 +34,7 @@ "pattern": "yyyy-MM-dd", "layout": { - "type": "pattern", "pattern": "%d{ISO8601} %p %c [%X{user}] %m" + "type": "pattern", "pattern": "%d{ISO8601} %p %c [%X{user}] [%f : %l] - %m" }, "keepFileExt" : true, "fileNameSep" : "_", @@ -47,7 +47,7 @@ "pattern": "yyyy-MM-dd", "layout": { - "type": "pattern", "pattern": "%d{ISO8601} %p %c [%X{user}] %m" + "type": "pattern", "pattern": "%d{ISO8601} %p %c [%X{user}] [%f : %l] - %m" }, "keepFileExt" : true, "fileNameSep" : "_", @@ -60,7 +60,7 @@ "pattern": "yyyy-MM-dd", "layout": { - "type": "pattern", "pattern": "%d{ISO8601} %p %c [%X{user}] %m" + "type": "pattern", "pattern": "%d{ISO8601} %p %c [%X{user}] [%f : %l] - %m" }, "keepFileExt" : true, "fileNameSep" : "_", @@ -77,7 +77,7 @@ "type": "stdout", "layout": { - "type": "pattern", "pattern": "%d{ISO8601} %p %c [%X{user}] %m" + "type": "pattern", "pattern": "%d{ISO8601} %p %c [%X{user}] [%f : %l] - %m" } }, "apolloOut": @@ -85,7 +85,7 @@ "type": "stdout", "layout": { - "type": "pattern", "pattern": "%d{ISO8601} %p %c [%X{user}] %m" + "type": "pattern", "pattern": "%d{ISO8601} %p %c [%X{user}] [%f : %l] - %m" } } }, @@ -99,7 +99,7 @@ "errors" ], "level": "debug", - "enableCallStack": false + "enableCallStack": true }, "apollo": { @@ -110,7 +110,7 @@ "errors" ], "level": "debug", - "enableCallStack": false + "enableCallStack": true }, "backend": { @@ -121,7 +121,7 @@ "errors" ], "level": "debug", - "enableCallStack": false + "enableCallStack": true }, "klicktipp": { @@ -132,7 +132,7 @@ "errors" ], "level": "debug", - "enableCallStack": false + "enableCallStack": true }, "http": { diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 647bf4fc1..1f05a5162 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -510,6 +510,7 @@ export class UserResolver { @Authorized([RIGHTS.SEND_RESET_PASSWORD_EMAIL]) @Mutation(() => Boolean) async forgotPassword(@Arg('email') email: string): Promise { + logger.addContext('user', 'unknown') logger.info(`forgotPassword(${email})...`) email = email.trim().toLowerCase() const user = await DbUser.findOne({ email }) From 0b410fd5fd67c51266550edb86da4bf998118f0d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Fri, 23 Sep 2022 00:50:07 +0200 Subject: [PATCH 825/977] oel convert --- docker-compose.override.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker-compose.override.yml b/docker-compose.override.yml index f8fde0430..fe2f68a8d 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -90,7 +90,7 @@ services: networks: - internal-net - external-net - + ######################################################### ## NGINX ################################################ ######################################################### From 62446bd2f0218f484aa70ecabc4081a088c1796c Mon Sep 17 00:00:00 2001 From: clauspeterhuebner <86960882+clauspeterhuebner@users.noreply.github.com> Date: Fri, 23 Sep 2022 00:56:36 +0200 Subject: [PATCH 826/977] Update backend/src/graphql/resolver/AdminResolver.test.ts Co-authored-by: Moriz Wahl --- backend/src/graphql/resolver/AdminResolver.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/AdminResolver.test.ts b/backend/src/graphql/resolver/AdminResolver.test.ts index 2f72155de..b1b4e469e 100644 --- a/backend/src/graphql/resolver/AdminResolver.test.ts +++ b/backend/src/graphql/resolver/AdminResolver.test.ts @@ -1498,7 +1498,7 @@ describe('AdminResolver', () => { }) // In the futrue this should not throw anymore - it('and throws an error for the second confirmation', async () => { + it('throws an error for the second confirmation', async () => { const r1 = mutate({ mutation: confirmContribution, variables: { From b0781bce88066fc887578852964376d93426af4b Mon Sep 17 00:00:00 2001 From: clauspeterhuebner <86960882+clauspeterhuebner@users.noreply.github.com> Date: Fri, 23 Sep 2022 01:03:07 +0200 Subject: [PATCH 827/977] Update backend/src/graphql/resolver/UserResolver.test.ts Co-authored-by: Moriz Wahl --- backend/src/graphql/resolver/UserResolver.test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index 5fef81ef1..7b59cb134 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -214,8 +214,7 @@ describe('UserResolver', () => { mutation: createUser, variables: { ...variables, email: 'bibi@bloxberg.de', language: 'it' }, }) - await expect(User.find({ relations: ['emailContact'] })).resolves.toEqual( - expect.arrayContaining([ + await expect(User.find({ relations: ['emailContact'] })).resolves.toContain( expect.objectContaining({ emailContact: expect.objectContaining({ email: 'bibi@bloxberg.de', From e701f995536ee764d83ecbd0bb2f3ce27de8c03a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Fri, 23 Sep 2022 01:11:37 +0200 Subject: [PATCH 828/977] rework PR comments --- backend/src/graphql/resolver/TransactionLinkResolver.ts | 2 +- backend/src/graphql/resolver/UserResolver.test.ts | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.ts b/backend/src/graphql/resolver/TransactionLinkResolver.ts index d8be2d552..c9acbace3 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.ts @@ -285,7 +285,7 @@ export class TransactionLinkResolver { const transactionLink = await dbTransactionLink.findOneOrFail({ code }) const linkedUser = await dbUser.findOneOrFail( { id: transactionLink.userId }, - { relations: ['user'] }, + { relations: ['emailContact'] }, ) if (user.id === linkedUser.id) { diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index 5fef81ef1..d62762288 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -701,12 +701,10 @@ bei Gradidio sei dabei!`, }) describe('queryOptIn', () => { - // let loginEmailOptIn: LoginEmailOptIn[] let emailContact: UserContact beforeAll(async () => { await userFactory(testEnv, bibiBloxberg) - // loginEmailOptIn = await LoginEmailOptIn.find() emailContact = await UserContact.findOneOrFail({ email: bibiBloxberg.email }) }) From 9f23ac9734e450dc186a965f69da445a3d1b11ac Mon Sep 17 00:00:00 2001 From: mahula Date: Fri, 23 Sep 2022 10:23:30 +0200 Subject: [PATCH 829/977] shorten script name for cypress execution in e2e-tests/cypress/tests/package.json Co-authored-by: Moriz Wahl --- e2e-tests/cypress/tests/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-tests/cypress/tests/package.json b/e2e-tests/cypress/tests/package.json index 2614cdae4..c2f1d3199 100644 --- a/e2e-tests/cypress/tests/package.json +++ b/e2e-tests/cypress/tests/package.json @@ -14,7 +14,7 @@ } }, "scripts": { - "cypress-e2e-tests": "yarn run cypress run", + "cypress": "yarn run cypress run", "lint": "eslint --max-warnings=0 --ext .js,.ts ." }, "dependencies": { From a12bb9e09b8611b9e3211bf3c55c10670ab2a920 Mon Sep 17 00:00:00 2001 From: mahula Date: Fri, 23 Sep 2022 12:15:31 +0200 Subject: [PATCH 830/977] bundle cypress step definitions - bundle step definitions in feature-related multiple-step files - avoid the long ugly file names --- .../the_user_fills_the_password_form_with.ts | 11 ---- ...he_user_is_presented_a_{string}_message.ts | 11 ---- ...the_user_opens_the_change_password_menu.ts | 9 ---- .../the_user_submits_the_password_form.ts | 7 --- .../support/step_definitions/common_steps.ts | 52 +++++++++++++++++++ .../the_browser_navigates_to_page_{string}.ts | 5 -- .../step_definitions/the_user_cannot_login.ts | 11 ---- ..._user_is_logged_in_as_{string}_{string}.ts | 8 --- ...ser_is_logged_in_with_username_{string}.ts | 8 --- .../step_definitions/the_user_logs_out.ts | 7 --- ...bmits_the_credentials_{string}_{string}.ts | 12 ----- .../user_authentication_steps.ts | 7 +++ .../user_profile_change_password_steps.ts | 32 ++++++++++++ .../user_registration_steps.ts | 24 +++++++++ 14 files changed, 115 insertions(+), 89 deletions(-) delete mode 100644 e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword/the_user_fills_the_password_form_with.ts delete mode 100644 e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword/the_user_is_presented_a_{string}_message.ts delete mode 100644 e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword/the_user_opens_the_change_password_menu.ts delete mode 100644 e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword/the_user_submits_the_password_form.ts create mode 100644 e2e-tests/cypress/tests/cypress/support/step_definitions/common_steps.ts delete mode 100644 e2e-tests/cypress/tests/cypress/support/step_definitions/the_browser_navigates_to_page_{string}.ts delete mode 100644 e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_cannot_login.ts delete mode 100644 e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_is_logged_in_as_{string}_{string}.ts delete mode 100644 e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_is_logged_in_with_username_{string}.ts delete mode 100644 e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_logs_out.ts delete mode 100644 e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_submits_the_credentials_{string}_{string}.ts create mode 100644 e2e-tests/cypress/tests/cypress/support/step_definitions/user_authentication_steps.ts create mode 100644 e2e-tests/cypress/tests/cypress/support/step_definitions/user_profile_change_password_steps.ts create mode 100644 e2e-tests/cypress/tests/cypress/support/step_definitions/user_registration_steps.ts diff --git a/e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword/the_user_fills_the_password_form_with.ts b/e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword/the_user_fills_the_password_form_with.ts deleted file mode 100644 index 21fda4b19..000000000 --- a/e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword/the_user_fills_the_password_form_with.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { When } from "@badeball/cypress-cucumber-preprocessor"; -import { ProfilePage } from "../models/ProfilePage"; - -When("the user fills the password form with:", (table) => { - table = table.rowsHash(); - const profilePage = new ProfilePage(); - profilePage.enterOldPassword(table["Old password"]); - profilePage.enterNewPassword(table["New password"]); - profilePage.enterRepeatPassword(table["Repeat new password"]); - cy.get(profilePage.submitNewPasswordBtn).should("be.enabled"); -}); diff --git a/e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword/the_user_is_presented_a_{string}_message.ts b/e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword/the_user_is_presented_a_{string}_message.ts deleted file mode 100644 index 9fa90bd02..000000000 --- a/e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword/the_user_is_presented_a_{string}_message.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { When } from "@badeball/cypress-cucumber-preprocessor"; -import { Toasts } from "../models/Toasts"; - -When("the user is presented a {string} message", (type: string) => { - const toast = new Toasts(); - cy.get(toast.toastTitle).should("contain.text", "Success"); - cy.get(toast.toastMessage).should( - "contain.text", - "Your password has been changed." - ); -}); diff --git a/e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword/the_user_opens_the_change_password_menu.ts b/e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword/the_user_opens_the_change_password_menu.ts deleted file mode 100644 index dcfed3c71..000000000 --- a/e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword/the_user_opens_the_change_password_menu.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { And } from "@badeball/cypress-cucumber-preprocessor"; -import { ProfilePage } from "../models/ProfilePage"; - -And("the user opens the change password menu", () => { - const profilePage = new ProfilePage(); - cy.get(profilePage.openChangePassword).click(); - cy.get(profilePage.newPasswordRepeatInput).should("be.visible"); - cy.get(profilePage.submitNewPasswordBtn).should("be.disabled"); -}); diff --git a/e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword/the_user_submits_the_password_form.ts b/e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword/the_user_submits_the_password_form.ts deleted file mode 100644 index 5752c94fa..000000000 --- a/e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword/the_user_submits_the_password_form.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { And } from "@badeball/cypress-cucumber-preprocessor"; -import { ProfilePage } from "../models/ProfilePage"; - -And("the user submits the password form", () => { - const profilePage = new ProfilePage(); - profilePage.submitPasswordForm(); -}); diff --git a/e2e-tests/cypress/tests/cypress/support/step_definitions/common_steps.ts b/e2e-tests/cypress/tests/cypress/support/step_definitions/common_steps.ts new file mode 100644 index 000000000..439974cda --- /dev/null +++ b/e2e-tests/cypress/tests/cypress/support/step_definitions/common_steps.ts @@ -0,0 +1,52 @@ +import { Given, Then, When } from "@badeball/cypress-cucumber-preprocessor"; +import { LoginPage } from "../../e2e/models/LoginPage"; +import { OverviewPage } from "../../e2e/models/OverviewPage"; +import { SideNavMenu } from "../../e2e/models/SideNavMenu"; +import { Toasts } from "../../e2e/models/Toasts"; + +Given("the browser navigates to page {string}", (page: string) => { + cy.visit(page); +}); + +// login-related + +Given( + "the user is logged in as {string} {string}", + (email: string, password: string) => { + cy.login(email, password); + } +); + +Then("the user is logged in with username {string}", (username: string) => { + const overviewPage = new OverviewPage(); + cy.url().should("include", "/overview"); + cy.get(overviewPage.navbarName).should("contain", username); +}); + +Then("the user cannot login", () => { + const toast = new Toasts(); + cy.get(toast.toastTitle).should("contain.text", "Error!"); + cy.get(toast.toastMessage).should( + "contain.text", + "No user with this credentials." + ); +}); + +// + +When( + "the user submits the credentials {string} {string}", + (email: string, password: string) => { + const loginPage = new LoginPage(); + loginPage.enterEmail(email); + loginPage.enterPassword(password); + loginPage.submitLogin(); + } +); + +// logout + +Then("the user logs out", () => { + const sideNavMenu = new SideNavMenu(); + sideNavMenu.logout(); +}); diff --git a/e2e-tests/cypress/tests/cypress/support/step_definitions/the_browser_navigates_to_page_{string}.ts b/e2e-tests/cypress/tests/cypress/support/step_definitions/the_browser_navigates_to_page_{string}.ts deleted file mode 100644 index cd397080d..000000000 --- a/e2e-tests/cypress/tests/cypress/support/step_definitions/the_browser_navigates_to_page_{string}.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { Given } from "@badeball/cypress-cucumber-preprocessor"; - -Given("the browser navigates to page {string}", (page: string) => { - cy.visit(page); -}); diff --git a/e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_cannot_login.ts b/e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_cannot_login.ts deleted file mode 100644 index 1f38747fe..000000000 --- a/e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_cannot_login.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { Then } from "@badeball/cypress-cucumber-preprocessor"; -import { Toasts } from "../../e2e/models/Toasts"; - -Then("the user cannot login", () => { - const toast = new Toasts(); - cy.get(toast.toastTitle).should("contain.text", "Error!"); - cy.get(toast.toastMessage).should( - "contain.text", - "No user with this credentials." - ); -}); diff --git a/e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_is_logged_in_as_{string}_{string}.ts b/e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_is_logged_in_as_{string}_{string}.ts deleted file mode 100644 index 145ece1b1..000000000 --- a/e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_is_logged_in_as_{string}_{string}.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Given } from "@badeball/cypress-cucumber-preprocessor"; - -Given( - "the user is logged in as {string} {string}", - (email: string, password: string) => { - cy.login(email, password); - } -); diff --git a/e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_is_logged_in_with_username_{string}.ts b/e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_is_logged_in_with_username_{string}.ts deleted file mode 100644 index 64741d122..000000000 --- a/e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_is_logged_in_with_username_{string}.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Then } from "@badeball/cypress-cucumber-preprocessor"; -import { OverviewPage } from "../../e2e/models/OverviewPage"; - -Then("the user is logged in with username {string}", (username: string) => { - const overviewPage = new OverviewPage(); - cy.url().should("include", "/overview"); - cy.get(overviewPage.navbarName).should("contain", username); -}); diff --git a/e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_logs_out.ts b/e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_logs_out.ts deleted file mode 100644 index 62766f7bd..000000000 --- a/e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_logs_out.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Then } from "@badeball/cypress-cucumber-preprocessor"; -import { SideNavMenu } from "../../e2e/models/SideNavMenu"; - -Then("the user logs out", () => { - const sideNavMenu = new SideNavMenu(); - sideNavMenu.logout(); -}); diff --git a/e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_submits_the_credentials_{string}_{string}.ts b/e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_submits_the_credentials_{string}_{string}.ts deleted file mode 100644 index 6aef84797..000000000 --- a/e2e-tests/cypress/tests/cypress/support/step_definitions/the_user_submits_the_credentials_{string}_{string}.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { When } from "@badeball/cypress-cucumber-preprocessor"; -import { LoginPage } from "../../e2e/models/LoginPage"; - -When( - "the user submits the credentials {string} {string}", - (email: string, password: string) => { - const loginPage = new LoginPage(); - loginPage.enterEmail(email); - loginPage.enterPassword(password); - loginPage.submitLogin(); - } -); diff --git a/e2e-tests/cypress/tests/cypress/support/step_definitions/user_authentication_steps.ts b/e2e-tests/cypress/tests/cypress/support/step_definitions/user_authentication_steps.ts new file mode 100644 index 000000000..1e5cfe88c --- /dev/null +++ b/e2e-tests/cypress/tests/cypress/support/step_definitions/user_authentication_steps.ts @@ -0,0 +1,7 @@ +import { When } from "@badeball/cypress-cucumber-preprocessor"; +import { LoginPage } from "../../e2e/models/LoginPage"; + +When("the user submits no credentials", () => { + const loginPage = new LoginPage(); + loginPage.submitLogin(); +}); diff --git a/e2e-tests/cypress/tests/cypress/support/step_definitions/user_profile_change_password_steps.ts b/e2e-tests/cypress/tests/cypress/support/step_definitions/user_profile_change_password_steps.ts new file mode 100644 index 000000000..cbe851f02 --- /dev/null +++ b/e2e-tests/cypress/tests/cypress/support/step_definitions/user_profile_change_password_steps.ts @@ -0,0 +1,32 @@ +import { And, When } from "@badeball/cypress-cucumber-preprocessor"; +import { ProfilePage } from "../../e2e/models/ProfilePage"; +import { Toasts } from "../../e2e/models/Toasts"; + +const profilePage = new ProfilePage(); + +And("the user opens the change password menu", () => { + cy.get(profilePage.openChangePassword).click(); + cy.get(profilePage.newPasswordRepeatInput).should("be.visible"); + cy.get(profilePage.submitNewPasswordBtn).should("be.disabled"); +}); + +When("the user fills the password form with:", (table) => { + table = table.rowsHash(); + profilePage.enterOldPassword(table["Old password"]); + profilePage.enterNewPassword(table["New password"]); + profilePage.enterRepeatPassword(table["Repeat new password"]); + cy.get(profilePage.submitNewPasswordBtn).should("be.enabled"); +}); + +And("the user submits the password form", () => { + profilePage.submitPasswordForm(); +}); + +When("the user is presented a {string} message", (type: string) => { + const toast = new Toasts(); + cy.get(toast.toastTitle).should("contain.text", "Success"); + cy.get(toast.toastMessage).should( + "contain.text", + "Your password has been changed." + ); +}); diff --git a/e2e-tests/cypress/tests/cypress/support/step_definitions/user_registration_steps.ts b/e2e-tests/cypress/tests/cypress/support/step_definitions/user_registration_steps.ts new file mode 100644 index 000000000..49e121fc2 --- /dev/null +++ b/e2e-tests/cypress/tests/cypress/support/step_definitions/user_registration_steps.ts @@ -0,0 +1,24 @@ +import { And, When } from "@badeball/cypress-cucumber-preprocessor"; +import { RegistrationPage } from "../../e2e/models/RegistrationPage"; + +const registrationPage = new RegistrationPage(); + +When( + "the user fills name and email {string} {string} {string}", + (firstname: string, lastname: string, email: string) => { + const registrationPage = new RegistrationPage(); + registrationPage.enterFirstname(firstname); + registrationPage.enterLastname(lastname); + registrationPage.enterEmail(email); + } +); + +And("the user agrees to the privacy policy", () => { + registrationPage.checkPrivacyCheckbox(); +}); + +And("the user submits the registration form", () => { + registrationPage.submitRegistrationPage(); + cy.get(registrationPage.RegistrationThanxHeadline).should("be.visible"); + cy.get(registrationPage.RegistrationThanxText).should("be.visible"); +}); From 454c8e2fda36dfe8d560f0831fbc1021184fc575 Mon Sep 17 00:00:00 2001 From: mahula Date: Fri, 23 Sep 2022 14:20:30 +0200 Subject: [PATCH 831/977] correct cypress execution command in package.json --- e2e-tests/cypress/tests/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-tests/cypress/tests/package.json b/e2e-tests/cypress/tests/package.json index c2f1d3199..a9979725e 100644 --- a/e2e-tests/cypress/tests/package.json +++ b/e2e-tests/cypress/tests/package.json @@ -14,7 +14,7 @@ } }, "scripts": { - "cypress": "yarn run cypress run", + "cypress": "cypress run", "lint": "eslint --max-warnings=0 --ext .js,.ts ." }, "dependencies": { From 60e4cbfd603a0acb89018ed3ce5c85c5c11cd208 Mon Sep 17 00:00:00 2001 From: mahula Date: Fri, 23 Sep 2022 14:23:07 +0200 Subject: [PATCH 832/977] make login query string more human readable in cypress.config.ts --- e2e-tests/cypress/tests/cypress.config.ts | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/e2e-tests/cypress/tests/cypress.config.ts b/e2e-tests/cypress/tests/cypress.config.ts index e82ee586f..815394c5e 100644 --- a/e2e-tests/cypress/tests/cypress.config.ts +++ b/e2e-tests/cypress/tests/cypress.config.ts @@ -41,8 +41,23 @@ export default defineConfig({ }, env: { backendURL: "http://localhost:4000", - loginQuery: - "query ($email: String!, $password: String!, $publisherId: Int) {\n login(email: $email, password: $password, publisherId: $publisherId) {\n email\n firstName\n lastName\n language\n klickTipp {\n newsletterState\n __typename\n }\n hasElopage\n publisherId\n isAdmin\n creation\n __typename\n }\n}\n", + loginQuery: `query ($email: String!, $password: String!, $publisherId: Int) { + login(email: $email, password: $password, publisherId: $publisherId) { + email + firstName + lastName + language + klickTipp { + newsletterState + __typename + } + hasElopage + publisherId + isAdmin + creation + __typename + } +}`, }, setupNodeEvents, }, From 8c6a2348611a16bfc9b65cca6a8a67b81c84ace3 Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 23 Sep 2022 16:20:41 +0200 Subject: [PATCH 833/977] Change contributions table to have deleted_by in the object. --- .../Contribution.ts | 92 +++++++++++++++++++ database/entity/Contribution.ts | 2 +- .../0049-add_delete_by_to_contributions.ts | 12 +++ 3 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 database/entity/0049-add_delete_by_to_contributions/Contribution.ts create mode 100644 database/migrations/0049-add_delete_by_to_contributions.ts diff --git a/database/entity/0049-add_delete_by_to_contributions/Contribution.ts b/database/entity/0049-add_delete_by_to_contributions/Contribution.ts new file mode 100644 index 000000000..32c6f32a3 --- /dev/null +++ b/database/entity/0049-add_delete_by_to_contributions/Contribution.ts @@ -0,0 +1,92 @@ +import Decimal from 'decimal.js-light' +import { + BaseEntity, + Column, + Entity, + PrimaryGeneratedColumn, + DeleteDateColumn, + JoinColumn, + ManyToOne, + OneToMany, +} from 'typeorm' +import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer' +import { User } from '../User' +import { ContributionMessage } from '../ContributionMessage' + +@Entity('contributions') +export class Contribution extends BaseEntity { + @PrimaryGeneratedColumn('increment', { unsigned: true }) + id: number + + @Column({ unsigned: true, nullable: false, name: 'user_id' }) + userId: number + + @ManyToOne(() => User, (user) => user.contributions) + @JoinColumn({ name: 'user_id' }) + user: User + + @Column({ type: 'datetime', default: () => 'CURRENT_TIMESTAMP', name: 'created_at' }) + createdAt: Date + + @Column({ type: 'datetime', nullable: false, name: 'contribution_date' }) + contributionDate: Date + + @Column({ length: 255, nullable: false, collation: 'utf8mb4_unicode_ci' }) + memo: string + + @Column({ + type: 'decimal', + precision: 40, + scale: 20, + nullable: false, + transformer: DecimalTransformer, + }) + amount: Decimal + + @Column({ unsigned: true, nullable: true, name: 'moderator_id' }) + moderatorId: number + + @Column({ unsigned: true, nullable: true, name: 'contribution_link_id' }) + contributionLinkId: number + + @Column({ unsigned: true, nullable: true, name: 'confirmed_by' }) + confirmedBy: number + + @Column({ nullable: true, name: 'confirmed_at' }) + confirmedAt: Date + + @Column({ unsigned: true, nullable: true, name: 'denied_by' }) + deniedBy: number + + @Column({ nullable: true, name: 'denied_at' }) + deniedAt: Date + + @Column({ + name: 'contribution_type', + length: 12, + nullable: false, + collation: 'utf8mb4_unicode_ci', + }) + contributionType: string + + @Column({ + name: 'contribution_status', + length: 12, + nullable: false, + collation: 'utf8mb4_unicode_ci', + }) + contributionStatus: string + + @Column({ unsigned: true, nullable: true, name: 'transaction_id' }) + transactionId: number + + @DeleteDateColumn({ name: 'deleted_at' }) + deletedAt: Date | null + + @DeleteDateColumn({ unsigned: true, nullable: true, name: 'deleted_by' }) + deletedBy: number + + @OneToMany(() => ContributionMessage, (message) => message.contribution) + @JoinColumn({ name: 'contribution_id' }) + messages?: ContributionMessage[] +} diff --git a/database/entity/Contribution.ts b/database/entity/Contribution.ts index f6530f00b..b6d2c36c9 100644 --- a/database/entity/Contribution.ts +++ b/database/entity/Contribution.ts @@ -1 +1 @@ -export { Contribution } from './0047-messages_tables/Contribution' +export { Contribution } from './0049-add_delete_by_to_contributions/Contribution' diff --git a/database/migrations/0049-add_delete_by_to_contributions.ts b/database/migrations/0049-add_delete_by_to_contributions.ts new file mode 100644 index 000000000..21d0eda97 --- /dev/null +++ b/database/migrations/0049-add_delete_by_to_contributions.ts @@ -0,0 +1,12 @@ +/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ +/* eslint-disable @typescript-eslint/no-explicit-any */ + +export async function upgrade(queryFn: (query: string, values?: any[]) => Promise>) { + await queryFn( + `ALTER TABLE \`contributions\` ADD COLUMN \`deleted_by\` int(10) unsigned DEFAULT NULL;`, + ) +} + +export async function downgrade(queryFn: (query: string, values?: any[]) => Promise>) { + await queryFn(`ALTER TABLE \`contributions\` DROP COLUMN \`deleted_by\`;`) +} From 8c69b94e8ed374007645076de23a6a998692403b Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 23 Sep 2022 16:25:22 +0200 Subject: [PATCH 834/977] Throw error if moderator tries to deleted own contribution created as user. Add deletedby value. --- backend/src/graphql/resolver/AdminResolver.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index d71ffc72c..ba7baa703 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -393,12 +393,23 @@ export class AdminResolver { @Authorized([RIGHTS.ADMIN_DELETE_CONTRIBUTION]) @Mutation(() => Boolean) - async adminDeleteContribution(@Arg('id', () => Int) id: number): Promise { + async adminDeleteContribution( + @Arg('id', () => Int) id: number, + @Ctx() context: Context, + ): Promise { const contribution = await Contribution.findOne(id) if (!contribution) { throw new Error('Contribution not found for given id.') } + const moderator = getUser(context) + if ( + contribution.contributionType === ContributionType.USER && + contribution.userId === moderator.id + ) { + throw new Error('Own contribution can not be deleted as admin') + } contribution.contributionStatus = ContributionStatus.DELETED + contribution.deletedBy = moderator.id await contribution.save() const res = await contribution.softRemove() return !!res From e7b5400db2a2ad1d1c216401267f34464b4e5381 Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 23 Sep 2022 16:49:12 +0200 Subject: [PATCH 835/977] Change the database version needed for the backend. --- backend/src/config/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index 6a2ebba87..cd5183693 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -10,7 +10,7 @@ Decimal.set({ }) const constants = { - DB_VERSION: '0048-add_is_moderator_to_contribution_messages', + DB_VERSION: '0049-add_delete_by_to_contributions', // '0048-add_is_moderator_to_contribution_messages', DECAY_START_TIME: new Date('2021-05-13 17:46:31-0000'), // GMT+0 LOG4JS_CONFIG: 'log4js-config.json', // default log level on production should be info From ab1a4ac8d14a89a48e54bd6e403160a217998bdf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Fri, 23 Sep 2022 18:24:13 +0200 Subject: [PATCH 836/977] solve tests --- .../src/graphql/resolver/UserResolver.test.ts | 23 ++++++++++++------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index 722571baf..53dc392ba 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -233,12 +233,12 @@ describe('UserResolver', () => { mutation: createUser, variables: { ...variables, email: 'bibi@bloxberg.de', language: 'it' }, }) - await expect(User.find({ relations: ['emailContact'] })).resolves.toContain( + await expect( + UserContact.findOne({ email: 'bibi@bloxberg.de' }, { relations: ['user'] }), + ).resolves.toEqual( expect.objectContaining({ - emailContact: expect.objectContaining({ - email: 'bibi@bloxberg.de', - }), - language: 'de', + email: 'bibi@bloxberg.de', + user: expect.objectContaining({ language: 'de' }), }), ) }) @@ -401,8 +401,12 @@ describe('UserResolver', () => { }) it('sets the referrer id to bob baumeister id', async () => { - await expect(User.findOne({ email: 'which@ever.de' })).resolves.toEqual( - expect.objectContaining({ referrerId: bob.data.login.id }), + await expect( + UserContact.findOne({ email: 'which@ever.de' }, { relations: ['user'] }), + ).resolves.toEqual( + expect.objectContaining({ + user: expect.objectContaining({ referrerId: bob.data.login.id }), + }), ) }) @@ -577,6 +581,7 @@ describe('UserResolver', () => { describe('no users in database', () => { beforeAll(async () => { + jest.clearAllMocks() result = await query({ query: login, variables }) }) @@ -589,7 +594,9 @@ describe('UserResolver', () => { }) it('logs the error found', () => { - expect(logger.error).toBeCalledWith('User with email=bibi@bloxberg.de does not exist') + expect(logger.error).toBeCalledWith( + 'UserContact with email=bibi@bloxberg.de does not exists', + ) }) }) From 60d2e2ff7bd0c093bb7b4acbea0b81ca34044e42 Mon Sep 17 00:00:00 2001 From: joseji Date: Fri, 23 Sep 2022 18:46:40 +0200 Subject: [PATCH 837/977] fixed contribution delete event saving and testing --- .../resolver/ContributionResolver.test.ts | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index 683946633..ee261c545 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -19,7 +19,6 @@ import { peterLustig } from '@/seeds/users/peter-lustig' import { EventProtocol } from '@entity/EventProtocol' import { EventProtocolType } from '@/event/EventProtocolType' import { logger } from '@test/testSetup' -import { Contribution } from '@entity/Contribution' let mutate: any, query: any, con: any let testEnv: any @@ -773,7 +772,6 @@ describe('ContributionResolver', () => { describe('User deletes own contribution', () => { it('deletes successfully', async () => { - console.log(await Contribution.find({ id: result.data.createContribution.id })) await expect( mutate({ mutation: deleteContribution, @@ -785,11 +783,26 @@ describe('ContributionResolver', () => { }) it('stores the delete contribution event in the database', async () => { - console.log(await Contribution.find({ id: result.data.createContribution.id })) + const contribution = await mutate({ + mutation: createContribution, + variables: { + amount: 166.0, + memo: 'Whatever contribution', + creationDate: new Date().toString(), + }, + }) + + await mutate({ + mutation: deleteContribution, + variables: { + id: contribution.data.createContribution.id, + }, + }) + await expect(EventProtocol.find()).resolves.toContainEqual( expect.objectContaining({ type: EventProtocolType.CONTRIBUTION_DELETE, - // id: result.data.createContribution.id, + contributionId: contribution.data.createContribution.id, }), ) }) From 792d8a8d53ccb1836104985af413f5ce58470995 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Claus-Peter=20H=C3=BCbner?= Date: Fri, 23 Sep 2022 18:47:07 +0200 Subject: [PATCH 838/977] eol convert --- docker-compose.test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/docker-compose.test.yml b/docker-compose.test.yml index 036149b7b..79ee46906 100644 --- a/docker-compose.test.yml +++ b/docker-compose.test.yml @@ -59,3 +59,4 @@ networks: volumes: db_test_vol: + From 744c961c0bcda7595eb6ed1f8269aef5c993d700 Mon Sep 17 00:00:00 2001 From: joseji Date: Fri, 23 Sep 2022 19:33:54 +0200 Subject: [PATCH 839/977] fixed tests with new log message --- backend/src/event/EventProtocolType.ts | 12 ++++++++++++ .../graphql/resolver/ContributionResolver.test.ts | 11 ++++++++--- backend/src/graphql/resolver/util/creations.ts | 5 ++++- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/backend/src/event/EventProtocolType.ts b/backend/src/event/EventProtocolType.ts index c0fc1bb8e..4265fb924 100644 --- a/backend/src/event/EventProtocolType.ts +++ b/backend/src/event/EventProtocolType.ts @@ -3,24 +3,36 @@ export enum EventProtocolType { VISIT_GRADIDO = 'VISIT_GRADIDO', REGISTER = 'REGISTER', REDEEM_REGISTER = 'REDEEM_REGISTER', + VERIFY_REDEEM = 'VERIFY_REDEEM', // TODO INACTIVE_ACCOUNT = 'INACTIVE_ACCOUNT', SEND_CONFIRMATION_EMAIL = 'SEND_CONFIRMATION_EMAIL', + SEND_ACCOUNT_MULTIREGISTRATION_EMAIL = 'SEND_ACCOUNT_MULTIREGISTRATION_EMAIL', // TODO CONFIRM_EMAIL = 'CONFIRM_EMAIL', REGISTER_EMAIL_KLICKTIPP = 'REGISTER_EMAIL_KLICKTIPP', LOGIN = 'LOGIN', + LOGOUT = 'LOGOUT', // TODO REDEEM_LOGIN = 'REDEEM_LOGIN', ACTIVATE_ACCOUNT = 'ACTIVATE_ACCOUNT', + SEND_FORGOT_PASSWORD_EMAIL = 'SEND_FORGOT_PASSWORD_EMAIL', // TODO PASSWORD_CHANGE = 'PASSWORD_CHANGE', + SEND_TRANSACTION_SEND_EMAIL = 'SEND_TRANSACTION_SEND_EMAIL', // TODO + SEND_TRANSACTION_RECEIVE_EMAIL = 'SEND_TRANSACTION_RECEIVE_EMAIL', // TODO TRANSACTION_SEND = 'TRANSACTION_SEND', TRANSACTION_SEND_REDEEM = 'TRANSACTION_SEND_REDEEM', TRANSACTION_REPEATE_REDEEM = 'TRANSACTION_REPEATE_REDEEM', TRANSACTION_CREATION = 'TRANSACTION_CREATION', TRANSACTION_RECEIVE = 'TRANSACTION_RECEIVE', TRANSACTION_RECEIVE_REDEEM = 'TRANSACTION_RECEIVE_REDEEM', + SEND_TRANSACTION_LINK_REDEEM_EMAIL = 'SEND_TRANSACTION_LINK_REDEEM_EMAIL', // TODO + SEND_ADDED_CONTRIBUTION_EMAIL = 'SEND_ADDED_CONTRIBUTION_EMAIL', // TODO + SEND_CONTRIBUTION_CONFIRM_EMAIL = 'SEND_CONTRIBUTION_CONFIRM_EMAIL', // TODO CONTRIBUTION_CREATE = 'CONTRIBUTION_CREATE', CONTRIBUTION_CONFIRM = 'CONTRIBUTION_CONFIRM', + CONTRIBUTION_DENY = 'CONTRIBUTION_DENY', // TODO CONTRIBUTION_LINK_DEFINE = 'CONTRIBUTION_LINK_DEFINE', CONTRIBUTION_LINK_ACTIVATE_REDEEM = 'CONTRIBUTION_LINK_ACTIVATE_REDEEM', CONTRIBUTION_DELETE = 'CONTRIBUTION_DELETE', CONTRIBUTION_UPDATE = 'CONTRIBUTION_UPDATE', + USER_CREATE_CONTRIBUTION_MESSAGE = 'USER_CREATE_CONTRIBUTION_MESSAGE', // TODO + ADMIN_CREATE_CONTRIBUTION_MESSAGE = 'ADMIN_CREATE_CONTRIBUTION_MESSAGE', // TODO } diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index ee261c545..b8bbebbd9 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -136,7 +136,8 @@ describe('ContributionResolver', () => { it('logs the error found', () => { expect(logger.error).toBeCalledWith( - 'No information for available creations for the given date', + 'No information for available creations with the given creationDate=', + new Date('non-valid').toDateString, ) }) @@ -161,8 +162,10 @@ describe('ContributionResolver', () => { }) it('logs the error found', () => { + const date = new Date() expect(logger.error).toBeCalledWith( - 'No information for available creations for the given date', + 'No information for available creations with the given creationDate=', + new Date(date.setMonth(date.getMonth() - 3).toString()).toDateString, ) }) }) @@ -557,8 +560,10 @@ describe('ContributionResolver', () => { }) it('logs the error found', () => { + const date = new Date() expect(logger.error).toBeCalledWith( - 'No information for available creations for the given date', + 'No information for available creations with the given creationDate=', + new Date(date.setMonth(date.getMonth() - 3).toString()).toDateString, ) }) }) diff --git a/backend/src/graphql/resolver/util/creations.ts b/backend/src/graphql/resolver/util/creations.ts index afbadead1..0b055e1d0 100644 --- a/backend/src/graphql/resolver/util/creations.ts +++ b/backend/src/graphql/resolver/util/creations.ts @@ -19,7 +19,10 @@ export const validateContribution = ( const index = getCreationIndex(creationDate.getMonth()) if (index < 0) { - logger.error('No information for available creations for the given date') + logger.error( + 'No information for available creations with the given creationDate=', + creationDate.toDateString, + ) throw new Error('No information for available creations for the given date') } From 6df8b9a83f7229eacf41afc05456dd1b64d05941 Mon Sep 17 00:00:00 2001 From: elweyn Date: Sat, 24 Sep 2022 11:32:07 +0200 Subject: [PATCH 840/977] Test that when an admin user create a contribution in FE he can not delete it in admin interface. --- .../graphql/resolver/AdminResolver.test.ts | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/backend/src/graphql/resolver/AdminResolver.test.ts b/backend/src/graphql/resolver/AdminResolver.test.ts index 75c672bd5..57ccd788f 100644 --- a/backend/src/graphql/resolver/AdminResolver.test.ts +++ b/backend/src/graphql/resolver/AdminResolver.test.ts @@ -16,6 +16,7 @@ import { setUserRole, deleteUser, unDeleteUser, + createContribution, adminCreateContribution, adminCreateContributions, adminUpdateContribution, @@ -77,6 +78,7 @@ afterAll(async () => { let admin: User let user: User let creation: Contribution | void +let result: any describe('AdminResolver', () => { describe('set user role', () => { @@ -1360,6 +1362,38 @@ describe('AdminResolver', () => { }) }) + describe('admin deletes own user contribution', () => { + beforeAll(async () => { + await query({ + query: login, + variables: { email: 'peter@lustig.de', password: 'Aa12345_' }, + }) + result = await mutate({ + mutation: createContribution, + variables: { + amount: 100.0, + memo: 'Test env contribution', + creationDate: new Date().toString(), + }, + }) + }) + + it('throws an error', async () => { + await expect( + mutate({ + mutation: adminDeleteContribution, + variables: { + id: result.data.createContribution.id, + }, + }), + ).resolves.toEqual( + expect.objectContaining({ + errors: [new GraphQLError('Own contribution can not be deleted as admin')], + }), + ) + }) + }) + describe('creation id does exist', () => { it('returns true', async () => { await expect( From 209c61e5d84c848705561fb141203f73af6ab72c Mon Sep 17 00:00:00 2001 From: elweyn Date: Mon, 26 Sep 2022 08:48:04 +0200 Subject: [PATCH 841/977] Change call from Contribution to DbContribution and use Contribution as model. --- backend/src/graphql/resolver/AdminResolver.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index ddd3a7f76..16ab3671c 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -248,7 +248,7 @@ export class AdminResolver { const creationDateObj = new Date(creationDate) logger.trace('creationDateObj:', creationDateObj) validateContribution(creations, amount, creationDateObj) - const contribution = Contribution.create() + const contribution = DbContribution.create() contribution.userId = emailContact.userId contribution.amount = amount contribution.createdAt = new Date() @@ -259,7 +259,7 @@ export class AdminResolver { contribution.contributionStatus = ContributionStatus.PENDING logger.trace('contribution to save', contribution) - await Contribution.save(contribution) + await DbContribution.save(contribution) return getUserCreation(emailContact.userId) } From f136f3c4adde15e09dea37bbb7a8a1c1b24727da Mon Sep 17 00:00:00 2001 From: elweyn Date: Mon, 26 Sep 2022 08:59:46 +0200 Subject: [PATCH 842/977] Remove unused migration. --- .../0049-add_delete_by_to_contributions.ts | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 database/migrations/0049-add_delete_by_to_contributions.ts diff --git a/database/migrations/0049-add_delete_by_to_contributions.ts b/database/migrations/0049-add_delete_by_to_contributions.ts deleted file mode 100644 index 21d0eda97..000000000 --- a/database/migrations/0049-add_delete_by_to_contributions.ts +++ /dev/null @@ -1,12 +0,0 @@ -/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -/* eslint-disable @typescript-eslint/no-explicit-any */ - -export async function upgrade(queryFn: (query: string, values?: any[]) => Promise>) { - await queryFn( - `ALTER TABLE \`contributions\` ADD COLUMN \`deleted_by\` int(10) unsigned DEFAULT NULL;`, - ) -} - -export async function downgrade(queryFn: (query: string, values?: any[]) => Promise>) { - await queryFn(`ALTER TABLE \`contributions\` DROP COLUMN \`deleted_by\`;`) -} From 186e6711f55714302b9865145932e50a635cc360 Mon Sep 17 00:00:00 2001 From: elweyn Date: Mon, 26 Sep 2022 09:10:58 +0200 Subject: [PATCH 843/977] Remove unused import. --- backend/src/graphql/resolver/AdminResolver.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index 16ab3671c..3435edb94 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -39,7 +39,6 @@ import { Decay } from '@model/Decay' import Paginated from '@arg/Paginated' import TransactionLinkFilters from '@arg/TransactionLinkFilters' import { Order } from '@enum/Order' -import { communityUser } from '@/util/communityUser' import { findUserByEmail, activationLink, printTimeDuration } from './UserResolver' import { sendAccountActivationEmail } from '@/mailer/sendAccountActivationEmail' import { transactionLinkCode as contributionLinkCode } from './TransactionLinkResolver' From 49378c64e250beccdf72045eaea6598257d39bd0 Mon Sep 17 00:00:00 2001 From: joseji Date: Mon, 26 Sep 2022 22:17:07 +0200 Subject: [PATCH 844/977] new events fully implemented --- backend/src/event/Event.ts | 115 +++++++++++++++++++++++++ backend/src/event/EventProtocolType.ts | 24 +++--- 2 files changed, 127 insertions(+), 12 deletions(-) diff --git a/backend/src/event/Event.ts b/backend/src/event/Event.ts index 40eb333fd..f6e6a554c 100644 --- a/backend/src/event/Event.ts +++ b/backend/src/event/Event.ts @@ -30,11 +30,20 @@ export class EventBasicRedeem extends EventBasicUserId { export class EventVisitGradido extends EventBasic {} export class EventRegister extends EventBasicUserId {} export class EventRedeemRegister extends EventBasicRedeem {} +export class EventVerifyRedeem extends EventBasicRedeem {} export class EventInactiveAccount extends EventBasicUserId {} export class EventSendConfirmationEmail extends EventBasicUserId {} +export class EventSendAccountMultiregistrationEmail extends EventBasicUserId {} +export class EventSendForgotPasswordEmail extends EventBasicUserId {} +export class EventSendTransactionSendEmail extends EventBasicRedeem {} +export class EventSendTransactionReceiveEmail extends EventBasicRedeem {} +export class EventSendTransactionLinkRedeemEmail extends EventBasicRedeem {} +export class EventSendAddedContributionEmail extends EventBasicCt {} +export class EventSendContributionConfirmEmail extends EventBasicCt {} export class EventConfirmationEmail extends EventBasicUserId {} export class EventRegisterEmailKlicktipp extends EventBasicUserId {} export class EventLogin extends EventBasicUserId {} +export class EventLogout extends EventBasicUserId {} export class EventRedeemLogin extends EventBasicRedeem {} export class EventActivateAccount extends EventBasicUserId {} export class EventPasswordChange extends EventBasicUserId {} @@ -48,12 +57,22 @@ export class EventTransactionCreation extends EventBasicUserId { export class EventTransactionReceive extends EventBasicTx {} export class EventTransactionReceiveRedeem extends EventBasicTx {} export class EventContributionCreate extends EventBasicCt {} +export class EventUserCreateContributionMessage extends EventBasicCt { + message: string +} +export class EventAdminCreateContributionMessage extends EventBasicCt { + message: string +} export class EventContributionDelete extends EventBasicCt {} export class EventContributionUpdate extends EventBasicCt {} export class EventContributionConfirm extends EventBasicCt { xUserId: number xCommunityId: number } +export class EventContributionDeny extends EventBasicCt { + xUserId: number + xCommunityId: number +} export class EventContributionLinkDefine extends EventBasicCt {} export class EventContributionLinkActivateRedeem extends EventBasicCt {} @@ -101,6 +120,13 @@ export class Event { return this } + public setEventVerifyRedeem(ev: EventVerifyRedeem): Event { + this.setByBasicRedeem(ev.userId, ev.transactionId, ev.contributionId) + this.type = EventProtocolType.VERIFY_REDEEM + + return this + } + public setEventInactiveAccount(ev: EventInactiveAccount): Event { this.setByBasicUser(ev.userId) this.type = EventProtocolType.INACTIVE_ACCOUNT @@ -115,6 +141,62 @@ export class Event { return this } + public setEventSendAccountMultiregistrationEmail( + ev: EventSendAccountMultiregistrationEmail, + ): Event { + this.setByBasicUser(ev.userId) + this.type = EventProtocolType.SEND_ACCOUNT_MULTIREGISTRATION_EMAIL + + return this + } + + public setEventSendForgotPasswordEmail(ev: EventSendForgotPasswordEmail): Event { + this.setByBasicUser(ev.userId) + this.type = EventProtocolType.SEND_FORGOT_PASSWORD_EMAIL + + return this + } + + public setEventSendTransactionSendEmail(ev: EventSendTransactionSendEmail): Event { + this.setByBasicUser(ev.userId) + this.transactionId = ev.transactionId + this.type = EventProtocolType.SEND_TRANSACTION_SEND_EMAIL + + return this + } + + public setEventSendTransactionReceiveEmail(ev: EventSendTransactionReceiveEmail): Event { + this.setByBasicUser(ev.userId) + this.transactionId = ev.transactionId + this.type = EventProtocolType.SEND_TRANSACTION_RECEIVE_EMAIL + + return this + } + + public setEventSendTransactionLinkRedeemEmail(ev: EventSendTransactionLinkRedeemEmail): Event { + this.setByBasicUser(ev.userId) + this.transactionId = ev.transactionId + this.type = EventProtocolType.SEND_TRANSACTION_LINK_REDEEM_EMAIL + + return this + } + + public setEventSendAddedContributionEmail(ev: EventSendAddedContributionEmail): Event { + this.setByBasicUser(ev.userId) + this.contributionId = ev.contributionId + this.type = EventProtocolType.SEND_ADDED_CONTRIBUTION_EMAIL + + return this + } + + public setEventSendContributionConfirmEmail(ev: EventSendContributionConfirmEmail): Event { + this.setByBasicUser(ev.userId) + this.contributionId = ev.contributionId + this.type = EventProtocolType.SEND_CONTRIBUTION_CONFIRM_EMAIL + + return this + } + public setEventConfirmationEmail(ev: EventConfirmationEmail): Event { this.setByBasicUser(ev.userId) this.type = EventProtocolType.CONFIRM_EMAIL @@ -136,6 +218,13 @@ export class Event { return this } + public setEventLogout(ev: EventLogout): Event { + this.setByBasicUser(ev.userId) + this.type = EventProtocolType.LOGOUT + + return this + } + public setEventRedeemLogin(ev: EventRedeemLogin): Event { this.setByBasicRedeem(ev.userId, ev.transactionId, ev.contributionId) this.type = EventProtocolType.REDEEM_LOGIN @@ -208,6 +297,22 @@ export class Event { return this } + public setEventUserCreateContributionMessage(ev: EventUserCreateContributionMessage): Event { + this.setByBasicCt(ev.userId, ev.contributionId, ev.amount) + if (ev.message) this.message = ev.message + this.type = EventProtocolType.USER_CREATE_CONTRIBUTION_MESSAGE + + return this + } + + public setEventAdminCreateContributionMessage(ev: EventAdminCreateContributionMessage): Event { + this.setByBasicCt(ev.userId, ev.contributionId, ev.amount) + if (ev.message) this.message = ev.message + this.type = EventProtocolType.ADMIN_CREATE_CONTRIBUTION_MESSAGE + + return this + } + public setEventContributionDelete(ev: EventContributionDelete): Event { this.setByBasicCt(ev.userId, ev.contributionId, ev.amount) this.type = EventProtocolType.CONTRIBUTION_DELETE @@ -231,6 +336,15 @@ export class Event { return this } + public setEventContributionDeny(ev: EventContributionDeny): Event { + this.setByBasicCt(ev.userId, ev.contributionId, ev.amount) + if (ev.xUserId) this.xUserId = ev.xUserId + if (ev.xCommunityId) this.xCommunityId = ev.xCommunityId + this.type = EventProtocolType.CONTRIBUTION_DENY + + return this + } + public setEventContributionLinkDefine(ev: EventContributionLinkDefine): Event { this.setByBasicCt(ev.userId, ev.contributionId, ev.amount) this.type = EventProtocolType.CONTRIBUTION_LINK_DEFINE @@ -314,4 +428,5 @@ export class Event { transactionId?: number contributionId?: number amount?: decimal + message?: string } diff --git a/backend/src/event/EventProtocolType.ts b/backend/src/event/EventProtocolType.ts index 4265fb924..d53eb6961 100644 --- a/backend/src/event/EventProtocolType.ts +++ b/backend/src/event/EventProtocolType.ts @@ -3,36 +3,36 @@ export enum EventProtocolType { VISIT_GRADIDO = 'VISIT_GRADIDO', REGISTER = 'REGISTER', REDEEM_REGISTER = 'REDEEM_REGISTER', - VERIFY_REDEEM = 'VERIFY_REDEEM', // TODO + VERIFY_REDEEM = 'VERIFY_REDEEM', INACTIVE_ACCOUNT = 'INACTIVE_ACCOUNT', SEND_CONFIRMATION_EMAIL = 'SEND_CONFIRMATION_EMAIL', - SEND_ACCOUNT_MULTIREGISTRATION_EMAIL = 'SEND_ACCOUNT_MULTIREGISTRATION_EMAIL', // TODO + SEND_ACCOUNT_MULTIREGISTRATION_EMAIL = 'SEND_ACCOUNT_MULTIREGISTRATION_EMAIL', CONFIRM_EMAIL = 'CONFIRM_EMAIL', REGISTER_EMAIL_KLICKTIPP = 'REGISTER_EMAIL_KLICKTIPP', LOGIN = 'LOGIN', - LOGOUT = 'LOGOUT', // TODO + LOGOUT = 'LOGOUT', REDEEM_LOGIN = 'REDEEM_LOGIN', ACTIVATE_ACCOUNT = 'ACTIVATE_ACCOUNT', - SEND_FORGOT_PASSWORD_EMAIL = 'SEND_FORGOT_PASSWORD_EMAIL', // TODO + SEND_FORGOT_PASSWORD_EMAIL = 'SEND_FORGOT_PASSWORD_EMAIL', PASSWORD_CHANGE = 'PASSWORD_CHANGE', - SEND_TRANSACTION_SEND_EMAIL = 'SEND_TRANSACTION_SEND_EMAIL', // TODO - SEND_TRANSACTION_RECEIVE_EMAIL = 'SEND_TRANSACTION_RECEIVE_EMAIL', // TODO + SEND_TRANSACTION_SEND_EMAIL = 'SEND_TRANSACTION_SEND_EMAIL', + SEND_TRANSACTION_RECEIVE_EMAIL = 'SEND_TRANSACTION_RECEIVE_EMAIL', TRANSACTION_SEND = 'TRANSACTION_SEND', TRANSACTION_SEND_REDEEM = 'TRANSACTION_SEND_REDEEM', TRANSACTION_REPEATE_REDEEM = 'TRANSACTION_REPEATE_REDEEM', TRANSACTION_CREATION = 'TRANSACTION_CREATION', TRANSACTION_RECEIVE = 'TRANSACTION_RECEIVE', TRANSACTION_RECEIVE_REDEEM = 'TRANSACTION_RECEIVE_REDEEM', - SEND_TRANSACTION_LINK_REDEEM_EMAIL = 'SEND_TRANSACTION_LINK_REDEEM_EMAIL', // TODO - SEND_ADDED_CONTRIBUTION_EMAIL = 'SEND_ADDED_CONTRIBUTION_EMAIL', // TODO - SEND_CONTRIBUTION_CONFIRM_EMAIL = 'SEND_CONTRIBUTION_CONFIRM_EMAIL', // TODO + SEND_TRANSACTION_LINK_REDEEM_EMAIL = 'SEND_TRANSACTION_LINK_REDEEM_EMAIL', + SEND_ADDED_CONTRIBUTION_EMAIL = 'SEND_ADDED_CONTRIBUTION_EMAIL', + SEND_CONTRIBUTION_CONFIRM_EMAIL = 'SEND_CONTRIBUTION_CONFIRM_EMAIL', CONTRIBUTION_CREATE = 'CONTRIBUTION_CREATE', CONTRIBUTION_CONFIRM = 'CONTRIBUTION_CONFIRM', - CONTRIBUTION_DENY = 'CONTRIBUTION_DENY', // TODO + CONTRIBUTION_DENY = 'CONTRIBUTION_DENY', CONTRIBUTION_LINK_DEFINE = 'CONTRIBUTION_LINK_DEFINE', CONTRIBUTION_LINK_ACTIVATE_REDEEM = 'CONTRIBUTION_LINK_ACTIVATE_REDEEM', CONTRIBUTION_DELETE = 'CONTRIBUTION_DELETE', CONTRIBUTION_UPDATE = 'CONTRIBUTION_UPDATE', - USER_CREATE_CONTRIBUTION_MESSAGE = 'USER_CREATE_CONTRIBUTION_MESSAGE', // TODO - ADMIN_CREATE_CONTRIBUTION_MESSAGE = 'ADMIN_CREATE_CONTRIBUTION_MESSAGE', // TODO + USER_CREATE_CONTRIBUTION_MESSAGE = 'USER_CREATE_CONTRIBUTION_MESSAGE', + ADMIN_CREATE_CONTRIBUTION_MESSAGE = 'ADMIN_CREATE_CONTRIBUTION_MESSAGE', } From 329e6f0893e8a2786c60a2264717965cb578a791 Mon Sep 17 00:00:00 2001 From: joseji Date: Mon, 26 Sep 2022 22:29:48 +0200 Subject: [PATCH 845/977] removed unnecesary previously included parameter 'message' on events --- backend/src/event/Event.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/backend/src/event/Event.ts b/backend/src/event/Event.ts index f6e6a554c..bebc91915 100644 --- a/backend/src/event/Event.ts +++ b/backend/src/event/Event.ts @@ -299,7 +299,6 @@ export class Event { public setEventUserCreateContributionMessage(ev: EventUserCreateContributionMessage): Event { this.setByBasicCt(ev.userId, ev.contributionId, ev.amount) - if (ev.message) this.message = ev.message this.type = EventProtocolType.USER_CREATE_CONTRIBUTION_MESSAGE return this @@ -307,7 +306,6 @@ export class Event { public setEventAdminCreateContributionMessage(ev: EventAdminCreateContributionMessage): Event { this.setByBasicCt(ev.userId, ev.contributionId, ev.amount) - if (ev.message) this.message = ev.message this.type = EventProtocolType.ADMIN_CREATE_CONTRIBUTION_MESSAGE return this @@ -428,5 +426,4 @@ export class Event { transactionId?: number contributionId?: number amount?: decimal - message?: string } From c8a2d899b88bc563e1363cead9caef1064481605 Mon Sep 17 00:00:00 2001 From: joseji Date: Mon, 26 Sep 2022 22:41:33 +0200 Subject: [PATCH 846/977] all stated according to the events table --- backend/src/event/Event.ts | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/backend/src/event/Event.ts b/backend/src/event/Event.ts index bebc91915..27e188a64 100644 --- a/backend/src/event/Event.ts +++ b/backend/src/event/Event.ts @@ -35,9 +35,9 @@ export class EventInactiveAccount extends EventBasicUserId {} export class EventSendConfirmationEmail extends EventBasicUserId {} export class EventSendAccountMultiregistrationEmail extends EventBasicUserId {} export class EventSendForgotPasswordEmail extends EventBasicUserId {} -export class EventSendTransactionSendEmail extends EventBasicRedeem {} -export class EventSendTransactionReceiveEmail extends EventBasicRedeem {} -export class EventSendTransactionLinkRedeemEmail extends EventBasicRedeem {} +export class EventSendTransactionSendEmail extends EventBasicTx {} +export class EventSendTransactionReceiveEmail extends EventBasicTx {} +export class EventSendTransactionLinkRedeemEmail extends EventBasicTx {} export class EventSendAddedContributionEmail extends EventBasicCt {} export class EventSendContributionConfirmEmail extends EventBasicCt {} export class EventConfirmationEmail extends EventBasicUserId {} @@ -57,9 +57,7 @@ export class EventTransactionCreation extends EventBasicUserId { export class EventTransactionReceive extends EventBasicTx {} export class EventTransactionReceiveRedeem extends EventBasicTx {} export class EventContributionCreate extends EventBasicCt {} -export class EventUserCreateContributionMessage extends EventBasicCt { - message: string -} +export class EventUserCreateContributionMessage extends EventBasicCt {} export class EventAdminCreateContributionMessage extends EventBasicCt { message: string } @@ -159,7 +157,10 @@ export class Event { public setEventSendTransactionSendEmail(ev: EventSendTransactionSendEmail): Event { this.setByBasicUser(ev.userId) - this.transactionId = ev.transactionId + if (ev.transactionId) this.transactionId = ev.transactionId + if (ev.xCommunityId) this.xCommunityId = ev.xCommunityId + if (ev.xUserId) this.xUserId = ev.xUserId + if (ev.amount) this.amount = ev.amount this.type = EventProtocolType.SEND_TRANSACTION_SEND_EMAIL return this @@ -167,7 +168,10 @@ export class Event { public setEventSendTransactionReceiveEmail(ev: EventSendTransactionReceiveEmail): Event { this.setByBasicUser(ev.userId) - this.transactionId = ev.transactionId + if (ev.transactionId) this.transactionId = ev.transactionId + if (ev.xCommunityId) this.xCommunityId = ev.xCommunityId + if (ev.xUserId) this.xUserId = ev.xUserId + if (ev.amount) this.amount = ev.amount this.type = EventProtocolType.SEND_TRANSACTION_RECEIVE_EMAIL return this @@ -175,7 +179,10 @@ export class Event { public setEventSendTransactionLinkRedeemEmail(ev: EventSendTransactionLinkRedeemEmail): Event { this.setByBasicUser(ev.userId) - this.transactionId = ev.transactionId + if (ev.transactionId) this.transactionId = ev.transactionId + if (ev.xCommunityId) this.xCommunityId = ev.xCommunityId + if (ev.xUserId) this.xUserId = ev.xUserId + if (ev.amount) this.amount = ev.amount this.type = EventProtocolType.SEND_TRANSACTION_LINK_REDEEM_EMAIL return this @@ -183,7 +190,7 @@ export class Event { public setEventSendAddedContributionEmail(ev: EventSendAddedContributionEmail): Event { this.setByBasicUser(ev.userId) - this.contributionId = ev.contributionId + if (ev.contributionId) this.contributionId = ev.contributionId this.type = EventProtocolType.SEND_ADDED_CONTRIBUTION_EMAIL return this @@ -191,7 +198,7 @@ export class Event { public setEventSendContributionConfirmEmail(ev: EventSendContributionConfirmEmail): Event { this.setByBasicUser(ev.userId) - this.contributionId = ev.contributionId + if (ev.contributionId) this.contributionId = ev.contributionId this.type = EventProtocolType.SEND_CONTRIBUTION_CONFIRM_EMAIL return this From 54266349bc87253190fb6d59004b2122039a69d8 Mon Sep 17 00:00:00 2001 From: jjimenezgarcia <99907380+jjimenezgarcia@users.noreply.github.com> Date: Mon, 26 Sep 2022 22:44:10 +0200 Subject: [PATCH 847/977] Refactor: Add all events to documentation table Added missing events to the table. Events implemented on #2231 --- .../BusinessEventProtocol.md | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/docu/Concepts/TechnicalRequirements/BusinessEventProtocol.md b/docu/Concepts/TechnicalRequirements/BusinessEventProtocol.md index ecdf8df34..13a32cce3 100644 --- a/docu/Concepts/TechnicalRequirements/BusinessEventProtocol.md +++ b/docu/Concepts/TechnicalRequirements/BusinessEventProtocol.md @@ -68,7 +68,7 @@ The following table lists for each event type the mapping between old and new ke | VISIT_GRADIDO | VisitGradidoEvent | x | x | x | | | | | | | | REGISTER | RegisterEvent | x | x | x | x | | | | | | | LOGIN | LoginEvent | x | x | x | x | | | | | | -| | VerifyRedeemEvent | | | | | | | | | | +| VERIFY_REDEEM | VerifyRedeemEvent | x | x | x | x | | | (x) | (x) | | | REDEEM_REGISTER | RedeemRegisterEvent | x | x | x | x | | | (x) | (x) | | | REDEEM_LOGIN | RedeemLoginEvent | x | x | x | x | | | (x) | (x) | | | ACTIVATE_ACCOUNT | ActivateAccountEvent | x | x | x | x | | | | | | @@ -82,20 +82,20 @@ The following table lists for each event type the mapping between old and new ke | TRANSACTION_SEND_REDEEM | TransactionLinkRedeemEvent | x | x | x | x | x | x | x | | x | | CONTRIBUTION_CREATE | ContributionCreateEvent | x | x | x | x | | | | x | x | | CONTRIBUTION_CONFIRM | ContributionConfirmEvent | x | x | x | x | x | x | | x | x | -| | ContributionDenyEvent | x | x | x | x | x | x | | x | x | +| CONTRIBUTION_DENY | ContributionDenyEvent | x | x | x | x | x | x | | x | x | | CONTRIBUTION_LINK_DEFINE | ContributionLinkDefineEvent | x | x | x | x | | | | | x | | CONTRIBUTION_LINK_ACTIVATE_REDEEM | ContributionLinkRedeemEvent | x | x | x | x | | | | x | x | -| | UserCreateContributionMessageEvent | x | x | x | x | | | | x | x | -| | AdminCreateContributionMessageEvent | x | x | x | x | | | | x | x | -| | LogoutEvent | x | x | x | x | | | | x | x | +| USER_CREATES_CONTRIBUTION_MESSAGE | UserCreateContributionMessageEvent | x | x | x | x | | | | x | x | +| ADMIN_CREATES_CONTRIBUTION_MESSAGE | AdminCreateContributionMessageEvent | x | x | x | x | | | | x | x | +| LOGOUT | LogoutEvent | x | x | x | x | | | | | | | SEND_CONFIRMATION_EMAIL | SendConfirmEmailEvent | x | x | x | x | | | | | | -| | SendAccountMultiRegistrationEmailEvent | x | x | x | x | | | | | | -| | SendForgotPasswordEmailEvent | x | x | x | x | | | | | | -| | SendTransactionSendEmailEvent | x | x | x | x | x | x | x | | x | -| | SendTransactionReceiveEmailEvent | x | x | x | x | x | x | x | | x | -| | SendAddedContributionEmailEvent | x | x | x | x | | | | x | x | -| | SendContributionConfirmEmailEvent | x | x | x | x | | | | x | x | -| | SendTransactionLinkRedeemEmailEvent | x | x | x | x | x | x | x | | x | +| SEND_ACCOUNT_MULTIREGISTRATION_EMAIL | SendAccountMultiRegistrationEmailEvent | x | x | x | x | | | | | | +| SEND_FORGOT_PASSWORD_EMAIL | SendForgotPasswordEmailEvent | x | x | x | x | | | | | | +| SEND_TRANSACTION_SEND_EMAIL | SendTransactionSendEmailEvent | x | x | x | x | x | x | x | | x | +| SEND_TRANSACTION_RECEIVE_EMAIL | SendTransactionReceiveEmailEvent | x | x | x | x | x | x | x | | x | +| SEND_ADDED_CONTRIBUTION_EMAIL | SendAddedContributionEmailEvent | x | x | x | x | | | | x | x | +| SEND_CONTRIBUTION_CONFIRM_EMAIL | SendContributionConfirmEmailEvent | x | x | x | x | | | | x | x | +| SEND_TRANSACTION_LINK_REDEEM_EMAIL | SendTransactionLinkRedeemEmailEvent | x | x | x | x | x | x | x | | x | | TRANSACTION_REPEATE_REDEEM | - | | | | | | | | | | | TRANSACTION_RECEIVE_REDEEM | - | | | | | | | | | | From e97aac759fd33ec0e678789686f78d681d69a5ad Mon Sep 17 00:00:00 2001 From: joseji Date: Mon, 26 Sep 2022 23:00:33 +0200 Subject: [PATCH 848/977] typo camel case in 'send multiregistration email event' --- backend/src/event/Event.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/src/event/Event.ts b/backend/src/event/Event.ts index 7c212978a..a0b5c05ec 100644 --- a/backend/src/event/Event.ts +++ b/backend/src/event/Event.ts @@ -33,7 +33,7 @@ export class EventRedeemRegister extends EventBasicRedeem {} export class EventVerifyRedeem extends EventBasicRedeem {} export class EventInactiveAccount extends EventBasicUserId {} export class EventSendConfirmationEmail extends EventBasicUserId {} -export class EventSendAccountMultiregistrationEmail extends EventBasicUserId {} +export class EventSendAccountMultiRegistrationEmail extends EventBasicUserId {} export class EventSendForgotPasswordEmail extends EventBasicUserId {} export class EventSendTransactionSendEmail extends EventBasicTx {} export class EventSendTransactionReceiveEmail extends EventBasicTx {} @@ -139,8 +139,8 @@ export class Event { return this } - public setEventSendAccountMultiregistrationEmail( - ev: EventSendAccountMultiregistrationEmail, + public setEventSendAccountMultiRegistrationEmail( + ev: EventSendAccountMultiRegistrationEmail, ): Event { this.setByBasicUser(ev.userId) this.type = EventProtocolType.SEND_ACCOUNT_MULTIREGISTRATION_EMAIL From b7c3d2acf19c40752c4352373a13b2e620fbb3b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Tue, 27 Sep 2022 09:58:22 +0200 Subject: [PATCH 849/977] Refactor 'setup.md' to a mark-down file and clearify instructions --- deployment/bare_metal/setup.md | 265 ++++++++++++++++++++++----------- 1 file changed, 174 insertions(+), 91 deletions(-) diff --git a/deployment/bare_metal/setup.md b/deployment/bare_metal/setup.md index 7c1154862..1bce53b26 100644 --- a/deployment/bare_metal/setup.md +++ b/deployment/bare_metal/setup.md @@ -1,111 +1,194 @@ -# Setup script to setup the server be ready to run gradido -# This assums you have root access via ssh to your cleanly setup server -# Furthermore this assumes you have debian (11 64bit) running -# Check your (Sub-)Domain with your Provider. -# In this document gddhost.tld refers to your chosen domain +# Instructions To Run `Gradido` On Your Server -> ssh root@gddhost.tld +We split setting up `Gradido` on your server into two steps: -# change root default shell -> chsh -s /bin/bash -# Create user `gradido` -> useradd -d /home/gradido -m gradido -> passwd gradido ->> enter new password twice +- [Preparing your server](#command-list-to-setup-your-server-be-ready-to-install-gradido) +- [Installing `Gradido`](#use-commands-in-installsh-manually-in-your-shell-for-now) -# Gives the user priviledges - this might be omitted in order to harden security -# Care: This will require another administering user if you don't want root access. -# Since this setup expects the user running the software be the same as the administering user, -# you have to adjust the instructions according to that scenario. -# You might lock yourself out, if done wrong. -> usermod -a -G sudo gradido +## Command List To Setup Your Server Be Ready To Install `Gradido` -# change gradido default shell -> chsh -s /bin/bash gradido -# Install sudo -> apt-get install sudo -# switch to the new user -> su gradido +We assume you have root access via ssh to your cleanly setup server. +Furthermore we assume you have debian (11 64bit) running. -# Register first ssh key for user `gradido` -> mkdir ~/.ssh -> chmod 700 ~/.ssh -> nano ~/.ssh/authorized_keys ->> insert public key ->> ctrl + x ->> save +Check your (Sub-)Domain with your Provider. +In this document `gddhost.tld` refers to your chosen domain. -# Test authentication via SSH -> ssh -i /path/to/privKey gradido@gddhost.tld ->> This should log you in and allow you to use sudo commands, which will require the user's password +### SSH into your server -# Disable password authentication & root login -> cd /etc/ssh -> sudo cp sshd_config sshd_config.org -> sudo nano sshd_config ->> change `PermitRootLogin yes` to `PermitRootLogin no` ->> change `#PasswordAuthentication yes` to `PasswordAuthentication no` ->> change `UsePAM yes` to `UsePAM no` ->> ctrl + x ->> save -> sudo /etc/init.d/ssh restart +```bash +ssh root@gddhost.tld +``` -# Test SSH Access only, no root ssh access -> ssh gradido@gddhost.tld ->> Will result in in either a password request for your key or the message `Permission denied (publickey)` -> ssh -i /path/to/privKey root@gddhost.tld ->> Will result in `Permission denied (publickey)` -> ssh -i /path/to/privKey gradido@gddhost.tld ->> Will succeed after entering the correct keys password (if any) +### Change root default shell -# update system -> sudo apt-get update -> sudo apt-get upgrade +```bash +chsh -s /bin/bash +``` -# Install security tools -## ufw -> sudo apt-get install ufw -> sudo ufw allow http -> sudo ufw allow https -> sudo ufw allow ssh -> sudo ufw enable +### Create user `gradido` -## fail2ban -> sudo apt-get install -y fail2ban -> sudo /etc/init.d/fail2ban restart +```bash +$ useradd -d /home/gradido -m gradido +$ passwd gradido +# enter new password twice +``` -# Install gradido -> sudo apt-get install -y git -> cd ~ -> git clone https://github.com/gradido/gradido.git +### Give the user priviledges -# Timezone -# Note: This is needed - since there is Summer-Time included in the default server Setup - UTC is REQUIRED for production data -> sudo timedatectl set-timezone UTC -# > sudo timedatectl set-ntp on -# > sudo apt purge ntp -# > sudo systemctl start systemd-timesyncd -# >> timedatectl to verify +This might be omitted in order to harden security. -# Adjust .env -# NOTE ';' can not be part of any value -# The Github Secret is Created on Github in Settimgs -> Webhooks -> cd gradido/deployment/bare_metal -> cp .env.dist .env -> nano .env ->> Adjust values accordingly +***!!! Attention !!!*** -# TODO the install.sh is not yet ready to run directly - consider to use it as pattern to do it manually +- Care: This will require another administering user if you don't want root access. +- Since this setup expects the user running the software be the same as the administering user, + - you have to adjust the instructions according to that scenario. + - you might lock yourself out, if done wrong. -!!! ATTENTION: +#### Add the new user `gradido` to `sudo` group -- NGINX: - - Be aware to set the values for NGINX in the following files according to your needs before you install NGINX! - - `./nginx/sites-available/gradido.conf` - - `./nginx/sites-available/update-page.conf` -- Commands in `./install.sh`: - - The commands for setting the paths in the used env variables are not working directly in the terminal, consider the out commented commands for this purpose, see below. +```bash +usermod -a -G sudo gradido +``` -Follow the commands in `./install.sh`. +### Change gradido default shell +```bash +chsh -s /bin/bash gradido +``` + +### Install sudo + +```bash +apt-get install sudo +``` + +### Switch to the new user + +```bash +su gradido +``` + +### Register first ssh key for user `gradido` + +```bash +$ mkdir ~/.ssh +$ chmod 700 ~/.ssh +$ nano ~/.ssh/authorized_keys +# insert public key +# ctrl + x +# save +``` + +### Test authentication via SSH + +```bash +$ ssh -i /path/to/privKey gradido@gddhost.tld +# This should log you in and allow you to use sudo commands, which will require the user's password +``` + +### Disable password authentication and root login + +```bash +$ cd /etc/ssh +$ sudo cp sshd_config sshd_config.org +$ sudo nano sshd_config +# change 'PermitRootLogin yes' to `PermitRootLogin no` +# change 'PasswordAuthentication yes' to 'PasswordAuthentication no' +# change 'UsePAM yes' to 'UsePAM no' +# ctrl + x +# save +$ sudo /etc/init.d/ssh restart +``` + +### Test SSH Access only, no root ssh access + +```bash +$ ssh gradido@gddhost.tld +# Will result in in either a password request for your key or the message 'Permission denied (publickey)' +$ ssh -i /path/to/privKey root@gddhost.tld +# Will result in 'Permission denied (publickey)' +$ ssh -i /path/to/privKey gradido@gddhost.tld +# Will succeed after entering the correct keys password (if any) +``` + +### Update system + +```bash +sudo apt-get update +sudo apt-get upgrade +``` + +### Install security tools + +#### Install: `ufw` + +```bash +sudo apt-get install ufw +sudo ufw allow http +sudo ufw allow https +sudo ufw allow ssh +sudo ufw enable +``` + +#### Install: `fail2ban` + +```bash +sudo apt-get install -y fail2ban +sudo /etc/init.d/fail2ban restart +``` + +### Install `Gradido` code + +```bash +sudo apt-get install -y git +cd ~ +git clone https://github.com/gradido/gradido.git +``` + +### Timezone + +*Note: This is needed - since there is Summer-Time included in the default server Setup - UTC is REQUIRED for production data.* + +```bash +sudo timedatectl set-timezone UTC +sudo timedatectl set-ntp on +sudo apt purge ntp +sudo systemctl start systemd-timesyncd +# timedatectl to verify +``` + +### Adjust the values in `.env` + +***!!! Attention !!!*** + +*Don't forget this step! +All your following installations in `install.sh` will fail!* + +*Notes:* + +- *`;` cannot be part of any value!* +- *The GitHub secret is created on GitHub in Settings -> Webhooks.* + +#### Create `.env` and set values + +```bash +$ cd gradido/deployment/bare_metal +$ cp .env.dist .env +$ nano .env +# adjust values accordingly +``` + +## Use Commands In `install.sh` Manually In Your Shell For Now + +The script `install.sh` is not yet ready to run directly. +Use it as pattern to do all steps manually in your terminal shell. + +*TODO: Bring the `install.sh` script to run in the shell.* + +***!!! Attention !!!*** + +- *Commands in `install.sh`:* + - *The commands for setting the paths in the used env variables are not working directly in the terminal, consider the out commented commands for this purpose.* + +Follow the commands in `./install.sh` as installation pattern. From 3c1b103f931a8dae74325fb66e226da34c72055c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Tue, 27 Sep 2022 10:22:08 +0200 Subject: [PATCH 850/977] Refine the integration of the conflicting docu --- deployment/bare_metal/setup.md | 44 +++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/deployment/bare_metal/setup.md b/deployment/bare_metal/setup.md index 8f09d296b..96ff0f48b 100644 --- a/deployment/bare_metal/setup.md +++ b/deployment/bare_metal/setup.md @@ -1,10 +1,11 @@ # Instructions To Run `Gradido` On Your Server -We split setting up `Gradido` on your server into two steps: +We split setting up `Gradido` on your server into three steps: - [Preparing your server](#command-list-to-setup-your-server-be-ready-to-install-gradido) - [Installing `Gradido`](#use-commands-in-installsh-manually-in-your-shell-for-now) +- [Crone-Job for `Gradido`](#define-cronjob-to-compensate-yarn-output-in-tmp) ## Command List To Setup Your Server Be Ready To Install `Gradido` @@ -193,13 +194,38 @@ Use it as pattern to do all steps manually in your terminal shell. Follow the commands in `./install.sh` as installation pattern. -## Define cronjob to compensate yarn output in /tmp +## Define Cronjob To Compensate Yarn Output In `/tmp` -> yarn creates output in /tmp directory, which must be deleted regularly and will be done per cronjob -> on stage1 a hourly job is necessary by setting the following job in the crontab for the gradido user -> crontab -e opens the crontab in edit-mode and insert the following entry: -> "0 * * * * find /tmp -name "yarn--*" -cmin +60 -exec rm -r {} \; > /dev/null" -> on stage2 a daily job is necessary by setting the following job in the crontab for the gradido user -> crontab -e opens the crontab in edit-mode and insert the following entry: -> "0 4 * * * find /tmp -name "yarn--*" -ctime +1 -exec rm -r {} \; > /dev/null" +`yarn` creates output in `/tmp` directory, which must be deleted regularly and will be done per Cron-Job. +### On `stage1` + +An hourly job is necessary on `stage1` by setting the following job in the `crontab` for the `gradido` user. + +Run: + +```bash +crontab -e +``` + +This opens the crontab in edit-mode and insert the following entry: + +```bash +0 * * * * find /tmp -name "yarn--*" -cmin +60 -exec rm -r {} \; > /dev/null +``` + +### On `stage2` + +A daily job is necessary on `stage2` by setting the following job in the `crontab` for the `gradido` user. + +Run: + +```bash +crontab -e +``` + +This opens the `crontab` in edit-mode and insert the following entry: + +```bash +0 4 * * * find /tmp -name "yarn--*" -ctime +1 -exec rm -r {} \; > /dev/null +``` From cbfeb88a2f80905b4e48d654a5d11f86a5e3b540 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wolfgang=20Hu=C3=9F?= Date: Tue, 27 Sep 2022 14:13:19 +0200 Subject: [PATCH 851/977] Fulfill Moriz suggestions Co-Authored-By: Mogge --- deployment/bare_metal/setup.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/deployment/bare_metal/setup.md b/deployment/bare_metal/setup.md index 96ff0f48b..5892cf4fc 100644 --- a/deployment/bare_metal/setup.md +++ b/deployment/bare_metal/setup.md @@ -83,6 +83,8 @@ $ nano ~/.ssh/authorized_keys ### Test authentication via SSH +If you logout from the server you can test authentication: + ```bash $ ssh -i /path/to/privKey gradido@gddhost.tld # This should log you in and allow you to use sudo commands, which will require the user's password @@ -106,11 +108,11 @@ $ sudo /etc/init.d/ssh restart ```bash $ ssh gradido@gddhost.tld -# Will result in in either a password request for your key or the message 'Permission denied (publickey)' +# Will result in in either a passphrase request for your key or the message 'Permission denied (publickey)' $ ssh -i /path/to/privKey root@gddhost.tld # Will result in 'Permission denied (publickey)' $ ssh -i /path/to/privKey gradido@gddhost.tld -# Will succeed after entering the correct keys password (if any) +# Will succeed after entering the correct keys passphrase (if any) ``` ### Update system From 1a01c7df83f92c826c2378bba9d64023d770db1a Mon Sep 17 00:00:00 2001 From: mahula Date: Tue, 27 Sep 2022 15:22:08 +0200 Subject: [PATCH 852/977] change cypress command in package.json to make "cypress open" available for local testing --- e2e-tests/cypress/tests/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-tests/cypress/tests/package.json b/e2e-tests/cypress/tests/package.json index a9979725e..a6f817503 100644 --- a/e2e-tests/cypress/tests/package.json +++ b/e2e-tests/cypress/tests/package.json @@ -14,7 +14,7 @@ } }, "scripts": { - "cypress": "cypress run", + "cypress-e2e": "cypress run", "lint": "eslint --max-warnings=0 --ext .js,.ts ." }, "dependencies": { From bb7e8d2b3de11c590a16800af83142fc48aaa264 Mon Sep 17 00:00:00 2001 From: mahula Date: Tue, 27 Sep 2022 15:51:05 +0200 Subject: [PATCH 853/977] set default command wait timout higher in cypress configuration --- e2e-tests/cypress/tests/cypress.config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/e2e-tests/cypress/tests/cypress.config.ts b/e2e-tests/cypress/tests/cypress.config.ts index 815394c5e..ad6a8d7de 100644 --- a/e2e-tests/cypress/tests/cypress.config.ts +++ b/e2e-tests/cypress/tests/cypress.config.ts @@ -32,6 +32,7 @@ export default defineConfig({ excludeSpecPattern: "*.js", baseUrl: "http://localhost:3000", chromeWebSecurity: false, + defaultCommandTimeout: 10000, supportFile: "cypress/support/index.ts", viewportHeight: 720, viewportWidth: 1280, From 825b364a3b979ee26374cbe70dc220e4e2a8e6cd Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 27 Sep 2022 19:13:32 +0200 Subject: [PATCH 854/977] fix user contact migration. Each user must have one contact, forget about that email_opt_in trash data --- .../0049-add_user_contacts_table.ts | 55 ++++--------------- 1 file changed, 10 insertions(+), 45 deletions(-) diff --git a/database/migrations/0049-add_user_contacts_table.ts b/database/migrations/0049-add_user_contacts_table.ts index c3b89ed88..0a6d4c89f 100644 --- a/database/migrations/0049-add_user_contacts_table.ts +++ b/database/migrations/0049-add_user_contacts_table.ts @@ -14,8 +14,8 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis \`type\` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL, \`user_id\` int(10) unsigned NOT NULL, \`email\` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL UNIQUE, - \`email_verification_code\` bigint(20) unsigned NOT NULL UNIQUE, - \`email_opt_in_type_id\` int NOT NULL, + \`email_verification_code\` bigint(20) unsigned DEFAULT NULL UNIQUE, + \`email_opt_in_type_id\` int DEFAULT NULL, \`email_resend_count\` int DEFAULT '0', \`email_checked\` tinyint(4) NOT NULL DEFAULT 0, \`phone\` varchar(255) COLLATE utf8mb4_unicode_ci NULL DEFAULT NULL, @@ -41,47 +41,10 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis // merge values from login_email_opt_in table with users.email in new user_contacts table await queryFn(` - INSERT INTO user_contacts - (type, user_id, email, email_verification_code, email_opt_in_type_id, email_resend_count, email_checked, created_at, updated_at, deleted_at) - SELECT - 'EMAIL', - u.id as user_id, - u.email, - e.verification_code as email_verification_code, - e.email_opt_in_type_id, - e.resend_count as email_resend_count, - u.email_checked, - e.created as created_at, - e.updated as updated_at, - u.deletedAt as deleted_at\ - FROM - users as u, - login_email_opt_in as e - WHERE - u.id = e.user_id AND - e.id in ( - WITH opt_in AS ( - SELECT - le.id, le.user_id, le.created, le.updated, ROW_NUMBER() OVER (PARTITION BY le.user_id ORDER BY le.created DESC) AS row_num - FROM - login_email_opt_in as le - ) - SELECT - opt_in.id - FROM - opt_in - WHERE - row_num = 1);`) - /* - // SELECT - // le.id - // FROM - // login_email_opt_in as le - // WHERE - // le.user_id = u.id - // ORDER BY - // le.updated DESC, le.created DESC LIMIT 1);`) - */ + INSERT INTO \`user_contacts\` + (type, user_id, email, email_verification_code, email_opt_in_type_id, email_resend_count, email_checked, created_at, updated_at, deleted_at) + SELECT 'EMAIL', \`users\`.id, \`users\`.email, optin.\`verification_code\`, optin.\`email_opt_in_type_id\`, optin.\`resend_count\`, users.\`email_checked\`, users.created, null, users.deletedAt + FROM users LEFT JOIN (SELECT * FROM \`login_email_opt_in\` ORDER BY created DESC LIMIT 1) AS optin ON users.id = optin.\`user_id\`;`) // insert in users table the email_id of the new created email-contacts const contacts = await queryFn(`SELECT c.id, c.user_id FROM user_contacts as c`) @@ -113,11 +76,13 @@ export async function downgrade(queryFn: (query: string, values?: any[]) => Prom ) // reconstruct the previous email back from contacts to users table - const contacts = await queryFn(`SELECT c.id, c.email, c.user_id FROM user_contacts as c`) + const contacts = await queryFn( + `SELECT c.id, c.email, c.user_id, c.email_checked FROM user_contacts as c`, + ) for (const id in contacts) { const contact = contacts[id] await queryFn( - `UPDATE users SET email = "${contact.email}" WHERE id = "${contact.user_id}" and email_id = "${contact.id}"`, + `UPDATE users SET email = "${contact.email}", email_checked="${contact.email_checked}" WHERE id = "${contact.user_id}" and email_id = "${contact.id}"`, ) } await queryFn('ALTER TABLE users MODIFY COLUMN email varchar(255) NOT NULL UNIQUE;') From 480378a18267b6a026e7cebcb38d11e23417291c Mon Sep 17 00:00:00 2001 From: mahula Date: Wed, 28 Sep 2022 10:38:46 +0200 Subject: [PATCH 855/977] fix language dependency of some selectors in login and user profile tests --- e2e-tests/cypress/tests/cypress/e2e/models/LoginPage.ts | 4 ++-- e2e-tests/cypress/tests/cypress/e2e/models/ProfilePage.ts | 8 ++++---- .../src/components/Inputs/InputPasswordConfirmation.vue | 1 + 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/e2e-tests/cypress/tests/cypress/e2e/models/LoginPage.ts b/e2e-tests/cypress/tests/cypress/e2e/models/LoginPage.ts index a16b93a11..9a0df62ee 100644 --- a/e2e-tests/cypress/tests/cypress/e2e/models/LoginPage.ts +++ b/e2e-tests/cypress/tests/cypress/e2e/models/LoginPage.ts @@ -2,8 +2,8 @@ export class LoginPage { // selectors - emailInput = "#Email-input-field"; - passwordInput = "#Password-input-field"; + emailInput = "input[type=email]"; + passwordInput = "input[type=password]"; submitBtn = "[type=submit]"; emailHint = "#vee_Email"; passwordHint = "#vee_Password"; diff --git a/e2e-tests/cypress/tests/cypress/e2e/models/ProfilePage.ts b/e2e-tests/cypress/tests/cypress/e2e/models/ProfilePage.ts index b280a0b2a..0532a7ff8 100644 --- a/e2e-tests/cypress/tests/cypress/e2e/models/ProfilePage.ts +++ b/e2e-tests/cypress/tests/cypress/e2e/models/ProfilePage.ts @@ -4,8 +4,8 @@ export class ProfilePage { // selectors openChangePassword = "[data-test=open-password-change-form]"; oldPasswordInput = "#password-input-field"; - newPasswordInput = "#New-password-input-field"; - newPasswordRepeatInput = "#Repeat-new-password-input-field"; + newPasswordInput = "#new-password-input-field"; + newPasswordRepeatInput = "#repeat-new-password-input-field"; submitNewPasswordBtn = "[data-test=submit-new-password-btn]"; goto() { @@ -19,12 +19,12 @@ export class ProfilePage { } enterNewPassword(password: string) { - cy.get(this.newPasswordInput).clear().type(password); + cy.get(this.newPasswordInput).find("input").clear().type(password); return this; } enterRepeatPassword(password: string) { - cy.get(this.newPasswordRepeatInput).clear().type(password); + cy.get(this.newPasswordRepeatInput).find("input").clear().type(password); return this; } diff --git a/frontend/src/components/Inputs/InputPasswordConfirmation.vue b/frontend/src/components/Inputs/InputPasswordConfirmation.vue index 3209018c3..56d58d9ad 100644 --- a/frontend/src/components/Inputs/InputPasswordConfirmation.vue +++ b/frontend/src/components/Inputs/InputPasswordConfirmation.vue @@ -29,6 +29,7 @@ required: true, samePassword: value.password, }" + id="repeat-new-password-input-field" :label="register ? $t('form.passwordRepeat') : $t('form.password_new_repeat')" :immediate="true" :name="createId(register ? $t('form.passwordRepeat') : $t('form.password_new_repeat'))" From 2ca9945a1b1675ffe402b9734d225840bdb6ce5e Mon Sep 17 00:00:00 2001 From: joseji Date: Wed, 28 Sep 2022 11:09:14 +0200 Subject: [PATCH 856/977] added missing events --- backend/src/graphql/resolver/AdminResolver.ts | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index e9ee0b55b..4bf2794dc 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -66,6 +66,8 @@ import { ContributionMessageType } from '@enum/MessageType' import { ContributionMessage } from '@model/ContributionMessage' import { sendContributionConfirmedEmail } from '@/mailer/sendContributionConfirmedEmail' import { sendAddedContributionMessageEmail } from '@/mailer/sendAddedContributionMessageEmail' +import { eventProtocol } from '@/event/EventProtocolEmitter' +import { Event, EventContributionConfirm, EventContributionCreate, EventContributionLinkDefine, EventSendConfirmationEmail } from '@/event/Event' // const EMAIL_OPT_IN_REGISTER = 1 // const EMAIL_OPT_UNKNOWN = 3 // elopage? @@ -241,6 +243,8 @@ export class AdminResolver { logger.error('Contribution could not be saved, Email is not activated') throw new Error('Contribution could not be saved, Email is not activated') } + + const event = new Event() const moderator = getUser(context) logger.trace('moderator: ', moderator.id) const creations = await getUserCreation(emailContact.userId) @@ -260,6 +264,13 @@ export class AdminResolver { logger.trace('contribution to save', contribution) await Contribution.save(contribution) + + const eventCreateContribution = new EventContributionCreate() + eventCreateContribution.userId = moderator.id + eventCreateContribution.amount = amount + eventCreateContribution.contributionId = contribution.id + await eventProtocol.writeEvent(event.setEventContributionCreate(eventCreateContribution)) + return getUserCreation(emailContact.userId) } @@ -495,6 +506,13 @@ export class AdminResolver { contributionAmount: contribution.amount, overviewURL: CONFIG.EMAIL_LINK_OVERVIEW, }) + + const event = new Event() + const eventContributionConfirm = new EventContributionConfirm() + eventContributionConfirm.xUserId = user.id + eventContributionConfirm.amount = contribution.amount + eventContributionConfirm.contributionId = contribution.id + await eventProtocol.writeEvent(event.setEventContributionConfirm(eventContributionConfirm)) } catch (e) { await queryRunner.rollbackTransaction() logger.error(`Creation was not successful: ${e}`) @@ -558,6 +576,13 @@ export class AdminResolver { // In case EMails are disabled log the activation link for the user if (!emailSent) { logger.info(`Account confirmation link: ${activationLink}`) + } else { + const event = new Event() + const eventSendConfirmationEmail = new EventSendConfirmationEmail() + eventSendConfirmationEmail.userId = user.id + await eventProtocol.writeEvent( + event.setEventSendConfirmationEmail(eventSendConfirmationEmail), + ) } return true @@ -660,6 +685,13 @@ export class AdminResolver { dbContributionLink.maxAmountPerMonth = maxAmountPerMonth dbContributionLink.maxPerCycle = maxPerCycle await dbContributionLink.save() + + const event = new Event() + const eventContributionLinkDefine = new EventContributionLinkDefine() + await eventProtocol.writeEvent( + event.setEventContributionLinkDefine(eventContributionLinkDefine), + ) + logger.debug(`createContributionLink successful!`) return new ContributionLink(dbContributionLink) } From 33eeab344f6e2b479452ab51599b17d5eb045026 Mon Sep 17 00:00:00 2001 From: joseji Date: Wed, 28 Sep 2022 11:14:16 +0200 Subject: [PATCH 857/977] added missing error logs --- backend/src/graphql/resolver/AdminResolver.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index 4bf2794dc..660f5ab31 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -148,11 +148,13 @@ export class AdminResolver { const user = await dbUser.findOne({ id: userId }) // user exists ? if (!user) { + logger.error(`Could not find user with userId: ${userId}`) throw new Error(`Could not find user with userId: ${userId}`) } // administrator user changes own role? const moderatorUser = getUser(context) if (moderatorUser.id === userId) { + logger.error('Administrator can not change his own role!') throw new Error('Administrator can not change his own role!') } // change isAdmin @@ -161,6 +163,7 @@ export class AdminResolver { if (isAdmin === true) { user.isAdmin = new Date() } else { + logger.error('User is already a usual user!') throw new Error('User is already a usual user!') } break @@ -168,6 +171,7 @@ export class AdminResolver { if (isAdmin === false) { user.isAdmin = null } else { + logger.error('User is already admin!') throw new Error('User is already admin!') } break @@ -186,11 +190,13 @@ export class AdminResolver { const user = await dbUser.findOne({ id: userId }) // user exists ? if (!user) { + logger.error(`Could not find user with userId: ${userId}`) throw new Error(`Could not find user with userId: ${userId}`) } // moderator user disabled own account? const moderatorUser = getUser(context) if (moderatorUser.id === userId) { + logger.error('Moderator can not delete his own account!') throw new Error('Moderator can not delete his own account!') } // soft-delete user @@ -204,9 +210,11 @@ export class AdminResolver { async unDeleteUser(@Arg('userId', () => Int) userId: number): Promise { const user = await dbUser.findOne({ id: userId }, { withDeleted: true }) if (!user) { + logger.error(`Could not find user with userId: ${userId}`) throw new Error(`Could not find user with userId: ${userId}`) } if (!user.deletedAt) { + logger.error('User is not deleted') throw new Error('User is not deleted') } await user.recover() @@ -781,9 +789,11 @@ export class AdminResolver { relations: ['user'], }) if (!contribution) { + logger.error('Contribution not found') throw new Error('Contribution not found') } if (contribution.userId === user.id) { + logger.error('Admin can not answer on own contribution') throw new Error('Admin can not answer on own contribution') } if (!contribution.user.emailContact) { From 0f1f9baa8dd0f836a0f1112a98865118968f5647 Mon Sep 17 00:00:00 2001 From: joseji Date: Wed, 28 Sep 2022 11:57:49 +0200 Subject: [PATCH 858/977] added tests for events --- .../graphql/resolver/AdminResolver.test.ts | 27 ++++++++++++++++++ backend/src/graphql/resolver/AdminResolver.ts | 28 +++++++++---------- 2 files changed, 40 insertions(+), 15 deletions(-) diff --git a/backend/src/graphql/resolver/AdminResolver.test.ts b/backend/src/graphql/resolver/AdminResolver.test.ts index b1b4e469e..c132cb10f 100644 --- a/backend/src/graphql/resolver/AdminResolver.test.ts +++ b/backend/src/graphql/resolver/AdminResolver.test.ts @@ -41,6 +41,8 @@ import { Contribution } from '@entity/Contribution' import { Transaction as DbTransaction } from '@entity/Transaction' import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' import { sendContributionConfirmedEmail } from '@/mailer/sendContributionConfirmedEmail' +import { EventProtocol } from '@entity/EventProtocol' +import { EventProtocolType } from '@/event/EventProtocolType' // mock account activation email to avoid console spam jest.mock('@/mailer/sendAccountActivationEmail', () => { @@ -1037,6 +1039,15 @@ describe('AdminResolver', () => { }), ) }) + + it('stores the create contribution event in the database', async () => { + await expect(EventProtocol.find()).resolves.toContainEqual( + expect.objectContaining({ + type: EventProtocolType.CONTRIBUTION_CREATE, + userId: admin.id, + }), + ) + }) }) describe('second creation surpasses the available amount ', () => { @@ -1451,6 +1462,14 @@ describe('AdminResolver', () => { ) }) + it('stores the contribution confirm event in the database', async () => { + await expect(EventProtocol.find()).resolves.toContainEqual( + expect.objectContaining({ + type: EventProtocolType.CONTRIBUTION_CONFIRM, + }), + ) + }) + it('creates a transaction', async () => { const transaction = await DbTransaction.find() expect(transaction[0].amount.toString()).toBe('450') @@ -1475,6 +1494,14 @@ describe('AdminResolver', () => { }), ) }) + + it('stores the send confirmation email event in the database', async () => { + await expect(EventProtocol.find()).resolves.toContainEqual( + expect.objectContaining({ + type: EventProtocolType.SEND_CONFIRMATION_EMAIL, + }), + ) + }) }) describe('confirm two creations one after the other quickly', () => { diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index 660f5ab31..b03da9dc4 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -67,7 +67,12 @@ import { ContributionMessage } from '@model/ContributionMessage' import { sendContributionConfirmedEmail } from '@/mailer/sendContributionConfirmedEmail' import { sendAddedContributionMessageEmail } from '@/mailer/sendAddedContributionMessageEmail' import { eventProtocol } from '@/event/EventProtocolEmitter' -import { Event, EventContributionConfirm, EventContributionCreate, EventContributionLinkDefine, EventSendConfirmationEmail } from '@/event/Event' +import { + Event, + EventContributionConfirm, + EventContributionCreate, + EventSendConfirmationEmail, +} from '@/event/Event' // const EMAIL_OPT_IN_REGISTER = 1 // const EMAIL_OPT_UNKNOWN = 3 // elopage? @@ -514,13 +519,6 @@ export class AdminResolver { contributionAmount: contribution.amount, overviewURL: CONFIG.EMAIL_LINK_OVERVIEW, }) - - const event = new Event() - const eventContributionConfirm = new EventContributionConfirm() - eventContributionConfirm.xUserId = user.id - eventContributionConfirm.amount = contribution.amount - eventContributionConfirm.contributionId = contribution.id - await eventProtocol.writeEvent(event.setEventContributionConfirm(eventContributionConfirm)) } catch (e) { await queryRunner.rollbackTransaction() logger.error(`Creation was not successful: ${e}`) @@ -528,6 +526,13 @@ export class AdminResolver { } finally { await queryRunner.release() } + + const event = new Event() + const eventContributionConfirm = new EventContributionConfirm() + eventContributionConfirm.userId = user.id + eventContributionConfirm.amount = contribution.amount + eventContributionConfirm.contributionId = contribution.id + await eventProtocol.writeEvent(event.setEventContributionConfirm(eventContributionConfirm)) return true } @@ -693,13 +698,6 @@ export class AdminResolver { dbContributionLink.maxAmountPerMonth = maxAmountPerMonth dbContributionLink.maxPerCycle = maxPerCycle await dbContributionLink.save() - - const event = new Event() - const eventContributionLinkDefine = new EventContributionLinkDefine() - await eventProtocol.writeEvent( - event.setEventContributionLinkDefine(eventContributionLinkDefine), - ) - logger.debug(`createContributionLink successful!`) return new ContributionLink(dbContributionLink) } From e7207da9ac56442068f8d3189f6ffaf79df5e7e4 Mon Sep 17 00:00:00 2001 From: mahula Date: Wed, 28 Sep 2022 10:38:46 +0200 Subject: [PATCH 859/977] fix language dependency of some selectors in login and user profile tests --- e2e-tests/cypress/tests/cypress/e2e/models/Toasts.ts | 3 +++ .../cypress/support/step_definitions/common_steps.ts | 10 +++++----- .../user_profile_change_password_steps.ts | 10 +++++----- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/e2e-tests/cypress/tests/cypress/e2e/models/Toasts.ts b/e2e-tests/cypress/tests/cypress/e2e/models/Toasts.ts index b2198bc8d..aabd0a45e 100644 --- a/e2e-tests/cypress/tests/cypress/e2e/models/Toasts.ts +++ b/e2e-tests/cypress/tests/cypress/e2e/models/Toasts.ts @@ -2,6 +2,9 @@ export class Toasts { // selectors + toastSlot = ".b-toaster-slot"; + toastTypeSuccess = ".b-toast-success"; + toastTypeError = ".b-toast-danger"; toastTitle = ".gdd-toaster-title"; toastMessage = ".gdd-toaster-body"; } diff --git a/e2e-tests/cypress/tests/cypress/support/step_definitions/common_steps.ts b/e2e-tests/cypress/tests/cypress/support/step_definitions/common_steps.ts index 439974cda..f45358f3c 100644 --- a/e2e-tests/cypress/tests/cypress/support/step_definitions/common_steps.ts +++ b/e2e-tests/cypress/tests/cypress/support/step_definitions/common_steps.ts @@ -25,11 +25,11 @@ Then("the user is logged in with username {string}", (username: string) => { Then("the user cannot login", () => { const toast = new Toasts(); - cy.get(toast.toastTitle).should("contain.text", "Error!"); - cy.get(toast.toastMessage).should( - "contain.text", - "No user with this credentials." - ); + cy.get(toast.toastSlot).within(() => { + cy.get(toast.toastTypeError); + cy.get(toast.toastTitle).should("be.visible"); + cy.get(toast.toastMessage).should("be.visible"); + }); }); // diff --git a/e2e-tests/cypress/tests/cypress/support/step_definitions/user_profile_change_password_steps.ts b/e2e-tests/cypress/tests/cypress/support/step_definitions/user_profile_change_password_steps.ts index cbe851f02..5396b66bb 100644 --- a/e2e-tests/cypress/tests/cypress/support/step_definitions/user_profile_change_password_steps.ts +++ b/e2e-tests/cypress/tests/cypress/support/step_definitions/user_profile_change_password_steps.ts @@ -24,9 +24,9 @@ And("the user submits the password form", () => { When("the user is presented a {string} message", (type: string) => { const toast = new Toasts(); - cy.get(toast.toastTitle).should("contain.text", "Success"); - cy.get(toast.toastMessage).should( - "contain.text", - "Your password has been changed." - ); + cy.get(toast.toastSlot).within(() => { + cy.get(toast.toastTypeSuccess); + cy.get(toast.toastTitle).should("be.visible"); + cy.get(toast.toastMessage).should("be.visible"); + }); }); From a756f0a4cc7c078e106f5c2515864d4196703cdf Mon Sep 17 00:00:00 2001 From: joseji Date: Wed, 28 Sep 2022 12:47:00 +0200 Subject: [PATCH 860/977] all tests completed --- .../graphql/resolver/AdminResolver.test.ts | 189 ++++++++++++++++++ .../src/graphql/resolver/util/creations.ts | 2 +- 2 files changed, 190 insertions(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/AdminResolver.test.ts b/backend/src/graphql/resolver/AdminResolver.test.ts index c132cb10f..6576a7d04 100644 --- a/backend/src/graphql/resolver/AdminResolver.test.ts +++ b/backend/src/graphql/resolver/AdminResolver.test.ts @@ -43,6 +43,7 @@ import { ContributionLink as DbContributionLink } from '@entity/ContributionLink import { sendContributionConfirmedEmail } from '@/mailer/sendContributionConfirmedEmail' import { EventProtocol } from '@entity/EventProtocol' import { EventProtocolType } from '@/event/EventProtocolType' +import { logger } from '@test/testSetup' // mock account activation email to avoid console spam jest.mock('@/mailer/sendAccountActivationEmail', () => { @@ -144,6 +145,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith(`Could not find user with userId: ${admin.id + 1}`) + }) }) describe('change role with success', () => { @@ -196,6 +201,9 @@ describe('AdminResolver', () => { }), ) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('Administrator can not change his own role!') + }) }) describe('user has already role to be set', () => { @@ -213,6 +221,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('User is already admin!') + }) }) describe('to usual user', () => { @@ -229,6 +241,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('User is already a usual user!') + }) }) }) }) @@ -297,6 +313,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith(`Could not find user with userId: ${admin.id + 1}`) + }) }) describe('delete self', () => { @@ -309,6 +329,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('Moderator can not delete his own account!') + }) }) describe('delete with success', () => { @@ -338,6 +362,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith(`Could not find user with userId: ${user.id}`) + }) }) }) }) @@ -405,6 +433,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith(`Could not find user with userId: ${admin.id + 1}`) + }) }) describe('user to undelete is not deleted', () => { @@ -422,6 +454,10 @@ describe('AdminResolver', () => { ) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('User is not deleted') + }) + describe('undelete deleted user', () => { beforeAll(async () => { await mutate({ mutation: deleteUser, variables: { userId: user.id } }) @@ -909,6 +945,12 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'Could not find user with email: bibi@bloxberg.de', + ) + }) }) describe('user to create for is deleted', () => { @@ -928,6 +970,12 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'This user was deleted. Cannot create a contribution.', + ) + }) }) describe('user to create for has email not confirmed', () => { @@ -947,6 +995,12 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'Contribution could not be saved, Email is not activated', + ) + }) }) describe('valid user to create for', () => { @@ -967,6 +1021,13 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'No information for available creations with the given creationDate=', + new Date('not-valid').toString(), + ) + }) }) describe('date of creation is four months ago', () => { @@ -987,6 +1048,13 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'No information for available creations with the given creationDate=', + variables.creationDate, + ) + }) }) describe('date of creation is in the future', () => { @@ -1007,6 +1075,13 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'No information for available creations with the given creationDate=', + variables.creationDate, + ) + }) }) describe('amount of creation is too high', () => { @@ -1024,6 +1099,12 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'The amount (2000 GDD) to be created exceeds the amount (1000 GDD) still available for this month.', + ) + }) }) describe('creation is valid', () => { @@ -1065,6 +1146,12 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'The amount (1000 GDD) to be created exceeds the amount (800 GDD) still available for this month.', + ) + }) }) }) }) @@ -1143,6 +1230,12 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'Could not find UserContact with email: bob@baumeister.de', + ) + }) }) describe('user for creation to update is deleted', () => { @@ -1164,6 +1257,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('User was deleted (stephen@hawking.uk)') + }) }) describe('creation does not exist', () => { @@ -1185,6 +1282,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('No contribution found to given id.') + }) }) describe('user email does not match creation user', () => { @@ -1210,6 +1311,12 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'user of the pending contribution and send user does not correspond', + ) + }) }) describe('creation update is not valid', () => { @@ -1235,6 +1342,12 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'The amount (1900 GDD) to be created exceeds the amount (500 GDD) still available for this month.', + ) + }) }) describe('creation update is successful changing month', () => { @@ -1371,6 +1484,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('Contribution not found for given id: -1') + }) }) describe('creation id does exist', () => { @@ -1407,6 +1524,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('Contribution not found for given id: -1') + }) }) describe('confirm own creation', () => { @@ -1434,6 +1555,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('Moderator can not confirm own contribution') + }) }) describe('confirm creation for other user', () => { @@ -2041,6 +2166,12 @@ describe('AdminResolver', () => { ) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'Start-Date is not initialized. A Start-Date must be set!', + ) + }) + it('returns an error if missing endDate', async () => { await expect( mutate({ @@ -2057,6 +2188,12 @@ describe('AdminResolver', () => { ) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'End-Date is not initialized. An End-Date must be set!', + ) + }) + it('returns an error if endDate is before startDate', async () => { await expect( mutate({ @@ -2076,6 +2213,12 @@ describe('AdminResolver', () => { ) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + `The value of validFrom must before or equals the validTo!`, + ) + }) + it('returns an error if name is an empty string', async () => { await expect( mutate({ @@ -2092,6 +2235,10 @@ describe('AdminResolver', () => { ) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('The name must be initialized!') + }) + it('returns an error if name is shorter than 5 characters', async () => { await expect( mutate({ @@ -2112,6 +2259,12 @@ describe('AdminResolver', () => { ) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + `The value of 'name' with a length of 3 did not fulfill the requested bounderies min=5 and max=100`, + ) + }) + it('returns an error if name is longer than 100 characters', async () => { await expect( mutate({ @@ -2132,6 +2285,12 @@ describe('AdminResolver', () => { ) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + `The value of 'name' with a length of 101 did not fulfill the requested bounderies min=5 and max=100`, + ) + }) + it('returns an error if memo is an empty string', async () => { await expect( mutate({ @@ -2148,6 +2307,10 @@ describe('AdminResolver', () => { ) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('The memo must be initialized!') + }) + it('returns an error if memo is shorter than 5 characters', async () => { await expect( mutate({ @@ -2168,6 +2331,12 @@ describe('AdminResolver', () => { ) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + `The value of 'memo' with a length of 3 did not fulfill the requested bounderies min=5 and max=255`, + ) + }) + it('returns an error if memo is longer than 255 characters', async () => { await expect( mutate({ @@ -2188,6 +2357,12 @@ describe('AdminResolver', () => { ) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + `The value of 'memo' with a length of 256 did not fulfill the requested bounderies min=5 and max=255`, + ) + }) + it('returns an error if amount is not positive', async () => { await expect( mutate({ @@ -2205,6 +2380,12 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'The amount=0 must be initialized with a positiv value!', + ) + }) }) describe('listContributionLinks', () => { @@ -2260,6 +2441,10 @@ describe('AdminResolver', () => { }) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('Contribution Link not found to given id: -1') + }) + describe('valid id', () => { let linkId: number beforeAll(async () => { @@ -2325,6 +2510,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('Contribution Link not found to given id: -1') + }) }) describe('valid id', () => { diff --git a/backend/src/graphql/resolver/util/creations.ts b/backend/src/graphql/resolver/util/creations.ts index 4f1cec0e0..9987dfae6 100644 --- a/backend/src/graphql/resolver/util/creations.ts +++ b/backend/src/graphql/resolver/util/creations.ts @@ -21,7 +21,7 @@ export const validateContribution = ( if (index < 0) { logger.error( 'No information for available creations with the given creationDate=', - creationDate, + creationDate.toString(), ) throw new Error('No information for available creations for the given date') } From 2a82faff47fbbb83886524d48b65cf74d31f5ccf Mon Sep 17 00:00:00 2001 From: mahula Date: Wed, 28 Sep 2022 13:01:27 +0200 Subject: [PATCH 861/977] fix error caused by missing files regarding rgistration tests --- .../cypress/e2e/User.Registration.feature | 13 ++++++ .../cypress/e2e/models/RegistrationPage.ts | 42 +++++++++++++++++++ 2 files changed, 55 insertions(+) create mode 100644 e2e-tests/cypress/tests/cypress/e2e/User.Registration.feature create mode 100644 e2e-tests/cypress/tests/cypress/e2e/models/RegistrationPage.ts diff --git a/e2e-tests/cypress/tests/cypress/e2e/User.Registration.feature b/e2e-tests/cypress/tests/cypress/e2e/User.Registration.feature new file mode 100644 index 000000000..9361d2b84 --- /dev/null +++ b/e2e-tests/cypress/tests/cypress/e2e/User.Registration.feature @@ -0,0 +1,13 @@ +Feature: User registration + As a user + I want to register to create an account + + @skip + Scenario: Register successfully + Given the browser navigates to page "/register" + When the user fills name and email "Regina" "Register" "regina@register.com" + And the user agrees to the privacy policy + And the user submits the registration form + Then the user can use a provided activation link + And the user can set a password "Aa12345_" + And the user can login with the credentials "regina@register.com" "Aa12345_" diff --git a/e2e-tests/cypress/tests/cypress/e2e/models/RegistrationPage.ts b/e2e-tests/cypress/tests/cypress/e2e/models/RegistrationPage.ts new file mode 100644 index 000000000..27a9cb8cc --- /dev/null +++ b/e2e-tests/cypress/tests/cypress/e2e/models/RegistrationPage.ts @@ -0,0 +1,42 @@ +/// + +export class RegistrationPage { + // selectors + firstnameInput = "#registerFirstname"; + lastnameInput = "#registerLastname"; + emailInput = "#Email-input-field"; + checkbox = "#registerCheckbox"; + submitBtn = "[type=submit]"; + + RegistrationThanxHeadline = ".test-message-headline"; + RegistrationThanxText = ".test-message-subtitle"; + + goto() { + cy.visit("/register"); + return this; + } + + enterFirstname(firstname: string) { + cy.get(this.firstnameInput).clear().type(firstname); + return this; + } + + enterLastname(lastname: string) { + cy.get(this.lastnameInput).clear().type(lastname); + return this; + } + + enterEmail(email: string) { + cy.get(this.emailInput).clear().type(email); + return this; + } + + checkPrivacyCheckbox() { + cy.get(this.checkbox).click({ force: true }); + } + + submitRegistrationPage() { + cy.get(this.submitBtn).should("be.enabled"); + cy.get(this.submitBtn).click(); + } +} From 5d24d1d51002359263796bd45a2c407b723ae0cf Mon Sep 17 00:00:00 2001 From: mahula Date: Wed, 28 Sep 2022 13:59:29 +0200 Subject: [PATCH 862/977] update cypress test readme --- e2e-tests/cypress/README.md | 45 ++++++++++++++++++++++++++++++++----- 1 file changed, 39 insertions(+), 6 deletions(-) diff --git a/e2e-tests/cypress/README.md b/e2e-tests/cypress/README.md index b1ddae514..e653413d6 100644 --- a/e2e-tests/cypress/README.md +++ b/e2e-tests/cypress/README.md @@ -1,24 +1,57 @@ # Gradido End-to-End Testing with [Cypress](https://www.cypress.io/) (CI-ready via Docker) +A setup to show-case Cypress as an end-to-end testing tool for Gradido running in a Docker container. +The tests are organized in feature files written in Gherkin syntax. + + +## Features under test + +So far these features are initially tested +- [User authentication](https://github.com/gradido/gradido/blob/master/e2e-tests/cypress/tests/cypress/e2e/User.Authentication.feature) +- [User profile - change password](https://github.com/gradido/gradido/blob/master/e2e-tests/cypress/tests/cypress/e2e/UserProfile.ChangePassword.feature) +- [User registration]((https://github.com/gradido/gradido/blob/master/e2e-tests/cypress/tests/cypress/e2e/User.Registration.feature)) (WIP) -A sample setup to show-case Cypress as an end-to-end testing tool for Gradido running in a Docker container. -Here we have a simple UI-based happy path login test running against the DEV system. ## Precondition -Since dependencies and configurations for Github Actions integration is not set up yet, please run in root directory + +Before running the test, change to the the repo's root directory (gradido) and boot up the system under test ```bash docker-compose up ``` -to boot up the DEV system, before running the test. ## Execute the test +This setup will be integrated in the Gradido Github Actions to automatically support the CI/CD process. +For now the test setup can only be use locally in two modes + +### Run Cypress directly from the code + ```bash +# change to the tests directory +cd /path/to/gradido/e2e-tests/cypress/tests + +# install all dependencies +yarn install + +# a) run the tests on command line +yarn cypress run + +# b) open the Cypress GUI to run the tests in interactive mode +yarn cypress open +``` + + +### Run Cyprss from a separate Docker container + +```bash +# change to the cypress directory +cd /path/to/gradido/e2e-tests/cypress/ + # build a Docker image from the Dockerfile docker build -t gradido_e2e-tests-cypress . -# run the Docker container and execute the given tests -docker run -it --network=host gradido_e2e-tests-cypress yarn run cypress-e2e-tests +# run the Docker image and execute the given tests +docker run -it --network=host gradido_e2e-tests-cypress yarn cypress-e2e ``` From 5bb6fd048de04dd740d94a5fc65d115685e617f1 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Wed, 28 Sep 2022 22:15:21 +0200 Subject: [PATCH 863/977] get email optin in a better way --- database/migrations/0049-add_user_contacts_table.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/database/migrations/0049-add_user_contacts_table.ts b/database/migrations/0049-add_user_contacts_table.ts index 0a6d4c89f..964285420 100644 --- a/database/migrations/0049-add_user_contacts_table.ts +++ b/database/migrations/0049-add_user_contacts_table.ts @@ -44,7 +44,10 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis INSERT INTO \`user_contacts\` (type, user_id, email, email_verification_code, email_opt_in_type_id, email_resend_count, email_checked, created_at, updated_at, deleted_at) SELECT 'EMAIL', \`users\`.id, \`users\`.email, optin.\`verification_code\`, optin.\`email_opt_in_type_id\`, optin.\`resend_count\`, users.\`email_checked\`, users.created, null, users.deletedAt - FROM users LEFT JOIN (SELECT * FROM \`login_email_opt_in\` ORDER BY created DESC LIMIT 1) AS optin ON users.id = optin.\`user_id\`;`) + FROM users LEFT JOIN + (SELECT le.id, le.user_id, le.verification_code, le.email_opt_in_type_id, le.resend_count, le.created, le.updated, + ROW_NUMBER() OVER (PARTITION BY le.user_id ORDER BY le.created DESC) AS row_num + FROM login_email_opt_in as le) AS optin ON users.id = optin.\`user_id\` AND row_num = 1;`) // insert in users table the email_id of the new created email-contacts const contacts = await queryFn(`SELECT c.id, c.user_id FROM user_contacts as c`) From 0ed12f878f70018069b6d2c4542ca9f3dfdf55c2 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 29 Sep 2022 04:38:33 +0200 Subject: [PATCH 864/977] remove back ticks in sql statement --- database/migrations/0049-add_user_contacts_table.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/database/migrations/0049-add_user_contacts_table.ts b/database/migrations/0049-add_user_contacts_table.ts index 964285420..acdd1af61 100644 --- a/database/migrations/0049-add_user_contacts_table.ts +++ b/database/migrations/0049-add_user_contacts_table.ts @@ -41,13 +41,13 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis // merge values from login_email_opt_in table with users.email in new user_contacts table await queryFn(` - INSERT INTO \`user_contacts\` + INSERT INTO user_contacts (type, user_id, email, email_verification_code, email_opt_in_type_id, email_resend_count, email_checked, created_at, updated_at, deleted_at) - SELECT 'EMAIL', \`users\`.id, \`users\`.email, optin.\`verification_code\`, optin.\`email_opt_in_type_id\`, optin.\`resend_count\`, users.\`email_checked\`, users.created, null, users.deletedAt + SELECT 'EMAIL', users.id, users.email, optin.verification_code, optin.email_opt_in_type_id, optin.resend_count, users.email_checked, users.created, null, users.deletedAt FROM users LEFT JOIN (SELECT le.id, le.user_id, le.verification_code, le.email_opt_in_type_id, le.resend_count, le.created, le.updated, ROW_NUMBER() OVER (PARTITION BY le.user_id ORDER BY le.created DESC) AS row_num - FROM login_email_opt_in as le) AS optin ON users.id = optin.\`user_id\` AND row_num = 1;`) + FROM login_email_opt_in as le) AS optin ON users.id = optin.user_id AND row_num = 1;`) // insert in users table the email_id of the new created email-contacts const contacts = await queryFn(`SELECT c.id, c.user_id FROM user_contacts as c`) From 07815e887f2625107c3cc39c86c2bdcfc24db127 Mon Sep 17 00:00:00 2001 From: mahula Date: Thu, 29 Sep 2022 11:12:06 +0200 Subject: [PATCH 865/977] update e2e-tests/cypress/README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Wolfgang Huß --- e2e-tests/cypress/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-tests/cypress/README.md b/e2e-tests/cypress/README.md index e653413d6..72c3745ec 100644 --- a/e2e-tests/cypress/README.md +++ b/e2e-tests/cypress/README.md @@ -14,7 +14,7 @@ So far these features are initially tested ## Precondition -Before running the test, change to the the repo's root directory (gradido) and boot up the system under test +Before running the test, change to the repo's root directory (gradido) and boot up the system under test: ```bash docker-compose up From 6796190f09ef0f5b817bab97c14bfadadcf3637b Mon Sep 17 00:00:00 2001 From: mahula Date: Thu, 29 Sep 2022 11:12:29 +0200 Subject: [PATCH 866/977] update e2e-tests/cypress/README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Wolfgang Huß --- e2e-tests/cypress/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-tests/cypress/README.md b/e2e-tests/cypress/README.md index 72c3745ec..08ca5ee0c 100644 --- a/e2e-tests/cypress/README.md +++ b/e2e-tests/cypress/README.md @@ -24,7 +24,7 @@ docker-compose up ## Execute the test This setup will be integrated in the Gradido Github Actions to automatically support the CI/CD process. -For now the test setup can only be use locally in two modes +For now the test setup can only be used locally in two modes. ### Run Cypress directly from the code From f780b1c431341cae1e075f8a97f88485cd407de9 Mon Sep 17 00:00:00 2001 From: mahula Date: Thu, 29 Sep 2022 11:32:57 +0200 Subject: [PATCH 867/977] update e2e-tests/cypress/README.md - hint about seeding the database before each test run --- e2e-tests/cypress/README.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/e2e-tests/cypress/README.md b/e2e-tests/cypress/README.md index 08ca5ee0c..6e4af822f 100644 --- a/e2e-tests/cypress/README.md +++ b/e2e-tests/cypress/README.md @@ -14,12 +14,28 @@ So far these features are initially tested ## Precondition -Before running the test, change to the repo's root directory (gradido) and boot up the system under test: +Before running the test, change to the repo's root directory (gradido) + +### Boot up the system under test ```bash docker-compose up ``` +### Seed the database + +The database has to be seeded upfront to every test run. + +```bash +# change to the backend directory +cd /path/to/gradido/gradido/backend + +# install all dependencies +yarn + +# seed the database (everytime before running the tests) +yarn seed +``` ## Execute the test From df2519784211723a52c9415770a0c6c66cc3a4d2 Mon Sep 17 00:00:00 2001 From: joseji Date: Thu, 29 Sep 2022 11:39:01 +0200 Subject: [PATCH 868/977] solved unnecessary date creation regarding one invalid date testing --- backend/src/graphql/resolver/AdminResolver.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/AdminResolver.test.ts b/backend/src/graphql/resolver/AdminResolver.test.ts index 6576a7d04..53097abbe 100644 --- a/backend/src/graphql/resolver/AdminResolver.test.ts +++ b/backend/src/graphql/resolver/AdminResolver.test.ts @@ -1025,7 +1025,7 @@ describe('AdminResolver', () => { it('logs the error thrown', () => { expect(logger.error).toBeCalledWith( 'No information for available creations with the given creationDate=', - new Date('not-valid').toString(), + 'Invalid Date', ) }) }) From ce280f6320c802ded0d9a422aabdb8a51d26a531 Mon Sep 17 00:00:00 2001 From: joseji Date: Thu, 29 Sep 2022 11:53:32 +0200 Subject: [PATCH 869/977] some conversations solved --- backend/src/event/Event.ts | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/backend/src/event/Event.ts b/backend/src/event/Event.ts index a0b5c05ec..8b8834b59 100644 --- a/backend/src/event/Event.ts +++ b/backend/src/event/Event.ts @@ -22,11 +22,22 @@ export class EventBasicCt extends EventBasicUserId { amount: decimal } +export class EventBasicCtX extends EventBasicUserId { + xUserId: number + xCommunityId: number + contributionId: number + amount: decimal +} + export class EventBasicRedeem extends EventBasicUserId { transactionId?: number contributionId?: number } +export class EventBasicCtMsg extends EventBasicCt { + message: string +} + export class EventVisitGradido extends EventBasic {} export class EventRegister extends EventBasicUserId {} export class EventRedeemRegister extends EventBasicRedeem {} @@ -57,8 +68,8 @@ export class EventTransactionCreation extends EventBasicUserId { export class EventTransactionReceive extends EventBasicTx {} export class EventTransactionReceiveRedeem extends EventBasicTx {} export class EventContributionCreate extends EventBasicCt {} -export class EventUserCreateContributionMessage extends EventBasicCt {} -export class EventAdminCreateContributionMessage extends EventBasicCt { +export class EventUserCreateContributionMessage extends EventBasicCtMsg {} +export class EventAdminCreateContributionMessage extends EventBasicCtMsg { message: string } export class EventContributionDelete extends EventBasicCt {} @@ -67,10 +78,7 @@ export class EventContributionConfirm extends EventBasicCt { xUserId: number xCommunityId: number } -export class EventContributionDeny extends EventBasicCt { - xUserId: number - xCommunityId: number -} +export class EventContributionDeny extends EventBasicCtX {} export class EventContributionLinkDefine extends EventBasicCt {} export class EventContributionLinkActivateRedeem extends EventBasicCt {} @@ -306,14 +314,14 @@ export class Event { public setEventUserCreateContributionMessage(ev: EventUserCreateContributionMessage): Event { this.setByBasicCt(ev.userId, ev.contributionId, ev.amount) this.type = EventProtocolType.USER_CREATE_CONTRIBUTION_MESSAGE - + this.message = ev.message return this } public setEventAdminCreateContributionMessage(ev: EventAdminCreateContributionMessage): Event { this.setByBasicCt(ev.userId, ev.contributionId, ev.amount) this.type = EventProtocolType.ADMIN_CREATE_CONTRIBUTION_MESSAGE - + this.message = ev.message return this } @@ -341,9 +349,11 @@ export class Event { } public setEventContributionDeny(ev: EventContributionDeny): Event { - this.setByBasicCt(ev.userId, ev.contributionId, ev.amount) - if (ev.xUserId) this.xUserId = ev.xUserId + this.setByBasicTx(ev.userId) + if (ev.contributionId) this.contributionId = ev.contributionId if (ev.xCommunityId) this.xCommunityId = ev.xCommunityId + if (ev.xUserId) this.xUserId = ev.xUserId + if (ev.amount) this.amount = ev.amount this.type = EventProtocolType.CONTRIBUTION_DENY return this @@ -432,4 +442,5 @@ export class Event { transactionId?: number contributionId?: number amount?: decimal + message?: string } From 7061718c1f92aee84ef2c14aeb21055ad59162f9 Mon Sep 17 00:00:00 2001 From: joseji Date: Thu, 29 Sep 2022 12:20:08 +0200 Subject: [PATCH 870/977] all conversations solved --- backend/src/event/Event.ts | 78 ++++++++++--------- .../resolver/ContributionResolver.test.ts | 8 +- .../src/graphql/resolver/util/creations.ts | 2 +- 3 files changed, 46 insertions(+), 42 deletions(-) diff --git a/backend/src/event/Event.ts b/backend/src/event/Event.ts index 8b8834b59..ee24c768b 100644 --- a/backend/src/event/Event.ts +++ b/backend/src/event/Event.ts @@ -22,7 +22,7 @@ export class EventBasicCt extends EventBasicUserId { amount: decimal } -export class EventBasicCtX extends EventBasicUserId { +export class EventBasicCtX extends EventBasicCt { xUserId: number xCommunityId: number contributionId: number @@ -74,10 +74,7 @@ export class EventAdminCreateContributionMessage extends EventBasicCtMsg { } export class EventContributionDelete extends EventBasicCt {} export class EventContributionUpdate extends EventBasicCt {} -export class EventContributionConfirm extends EventBasicCt { - xUserId: number - xCommunityId: number -} +export class EventContributionConfirm extends EventBasicCtX {} export class EventContributionDeny extends EventBasicCtX {} export class EventContributionLinkDefine extends EventBasicCt {} export class EventContributionLinkActivateRedeem extends EventBasicCt {} @@ -164,50 +161,37 @@ export class Event { } public setEventSendTransactionSendEmail(ev: EventSendTransactionSendEmail): Event { - this.setByBasicUser(ev.userId) - if (ev.transactionId) this.transactionId = ev.transactionId - if (ev.xCommunityId) this.xCommunityId = ev.xCommunityId - if (ev.xUserId) this.xUserId = ev.xUserId - if (ev.amount) this.amount = ev.amount + this.setByBasicTx(ev.userId, ev.xUserId, ev.xCommunityId, ev.transactionId, ev.amount) this.type = EventProtocolType.SEND_TRANSACTION_SEND_EMAIL return this } public setEventSendTransactionReceiveEmail(ev: EventSendTransactionReceiveEmail): Event { - this.setByBasicUser(ev.userId) - if (ev.transactionId) this.transactionId = ev.transactionId - if (ev.xCommunityId) this.xCommunityId = ev.xCommunityId - if (ev.xUserId) this.xUserId = ev.xUserId - if (ev.amount) this.amount = ev.amount + this.setByBasicTx(ev.userId, ev.xUserId, ev.xCommunityId, ev.transactionId, ev.amount) this.type = EventProtocolType.SEND_TRANSACTION_RECEIVE_EMAIL return this } public setEventSendTransactionLinkRedeemEmail(ev: EventSendTransactionLinkRedeemEmail): Event { - this.setByBasicUser(ev.userId) - if (ev.transactionId) this.transactionId = ev.transactionId - if (ev.xCommunityId) this.xCommunityId = ev.xCommunityId - if (ev.xUserId) this.xUserId = ev.xUserId - if (ev.amount) this.amount = ev.amount + this.setByBasicTx(ev.userId, ev.xUserId, ev.xCommunityId, ev.transactionId, ev.amount) this.type = EventProtocolType.SEND_TRANSACTION_LINK_REDEEM_EMAIL return this } public setEventSendAddedContributionEmail(ev: EventSendAddedContributionEmail): Event { - this.setByBasicUser(ev.userId) - if (ev.contributionId) this.contributionId = ev.contributionId + this.setByBasicCt(ev.userId, ev.contributionId, ev.amount) this.type = EventProtocolType.SEND_ADDED_CONTRIBUTION_EMAIL return this } public setEventSendContributionConfirmEmail(ev: EventSendContributionConfirmEmail): Event { - this.setByBasicUser(ev.userId) - if (ev.contributionId) this.contributionId = ev.contributionId + this.setByBasicCt(ev.userId, ev.contributionId, ev.amount) this.type = EventProtocolType.SEND_CONTRIBUTION_CONFIRM_EMAIL + return this } @@ -312,16 +296,16 @@ export class Event { } public setEventUserCreateContributionMessage(ev: EventUserCreateContributionMessage): Event { - this.setByBasicCt(ev.userId, ev.contributionId, ev.amount) + this.setByBasicCtMsg(ev.userId, ev.contributionId, ev.amount, ev.message) this.type = EventProtocolType.USER_CREATE_CONTRIBUTION_MESSAGE - this.message = ev.message + return this } public setEventAdminCreateContributionMessage(ev: EventAdminCreateContributionMessage): Event { - this.setByBasicCt(ev.userId, ev.contributionId, ev.amount) + this.setByBasicCtMsg(ev.userId, ev.contributionId, ev.amount, ev.message) this.type = EventProtocolType.ADMIN_CREATE_CONTRIBUTION_MESSAGE - this.message = ev.message + return this } @@ -340,20 +324,14 @@ export class Event { } public setEventContributionConfirm(ev: EventContributionConfirm): Event { - this.setByBasicCt(ev.userId, ev.contributionId, ev.amount) - if (ev.xUserId) this.xUserId = ev.xUserId - if (ev.xCommunityId) this.xCommunityId = ev.xCommunityId + this.setByBasicCtX(ev.userId, ev.xUserId, ev.xCommunityId, ev.contributionId, ev.amount) this.type = EventProtocolType.CONTRIBUTION_CONFIRM return this } public setEventContributionDeny(ev: EventContributionDeny): Event { - this.setByBasicTx(ev.userId) - if (ev.contributionId) this.contributionId = ev.contributionId - if (ev.xCommunityId) this.xCommunityId = ev.xCommunityId - if (ev.xUserId) this.xUserId = ev.xUserId - if (ev.amount) this.amount = ev.amount + this.setByBasicCtX(ev.userId, ev.xUserId, ev.xCommunityId, ev.contributionId, ev.amount) this.type = EventProtocolType.CONTRIBUTION_DENY return this @@ -404,6 +382,34 @@ export class Event { return this } + setByBasicCtMsg( + userId: number, + contributionId: number, + amount?: decimal, + message?: string, + ): Event { + this.setByBasicCt(userId, contributionId, amount) + if (message) this.message = message + + return this + } + + setByBasicCtX( + userId: number, + xUserId?: number, + xCommunityId?: number, + contributionId?: number, + amount?: decimal, + ): Event { + this.setByBasicUser(userId) + if (xUserId) this.xUserId = xUserId + if (xCommunityId) this.xCommunityId = xCommunityId + if (contributionId) this.contributionId = contributionId + if (amount) this.amount = amount + + return this + } + setByBasicRedeem(userId: number, transactionId?: number, contributionId?: number): Event { this.setByBasicUser(userId) if (transactionId) this.transactionId = transactionId diff --git a/backend/src/graphql/resolver/ContributionResolver.test.ts b/backend/src/graphql/resolver/ContributionResolver.test.ts index b8bbebbd9..199fb6c76 100644 --- a/backend/src/graphql/resolver/ContributionResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionResolver.test.ts @@ -137,7 +137,7 @@ describe('ContributionResolver', () => { it('logs the error found', () => { expect(logger.error).toBeCalledWith( 'No information for available creations with the given creationDate=', - new Date('non-valid').toDateString, + 'Invalid Date', ) }) @@ -162,10 +162,9 @@ describe('ContributionResolver', () => { }) it('logs the error found', () => { - const date = new Date() expect(logger.error).toBeCalledWith( 'No information for available creations with the given creationDate=', - new Date(date.setMonth(date.getMonth() - 3).toString()).toDateString, + 'Invalid Date', ) }) }) @@ -560,10 +559,9 @@ describe('ContributionResolver', () => { }) it('logs the error found', () => { - const date = new Date() expect(logger.error).toBeCalledWith( 'No information for available creations with the given creationDate=', - new Date(date.setMonth(date.getMonth() - 3).toString()).toDateString, + 'Invalid Date', ) }) }) diff --git a/backend/src/graphql/resolver/util/creations.ts b/backend/src/graphql/resolver/util/creations.ts index b390e197d..9987dfae6 100644 --- a/backend/src/graphql/resolver/util/creations.ts +++ b/backend/src/graphql/resolver/util/creations.ts @@ -21,7 +21,7 @@ export const validateContribution = ( if (index < 0) { logger.error( 'No information for available creations with the given creationDate=', - creationDate.toDateString, + creationDate.toString(), ) throw new Error('No information for available creations for the given date') } From b0e9550ffc1d7cfa0c13c5fc942a2336025505aa Mon Sep 17 00:00:00 2001 From: mahula Date: Thu, 29 Sep 2022 12:21:49 +0200 Subject: [PATCH 871/977] update e2e-tests/cypress/README.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Wolfgang Huß --- e2e-tests/cypress/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e-tests/cypress/README.md b/e2e-tests/cypress/README.md index 6e4af822f..4ec1ebe51 100644 --- a/e2e-tests/cypress/README.md +++ b/e2e-tests/cypress/README.md @@ -14,7 +14,7 @@ So far these features are initially tested ## Precondition -Before running the test, change to the repo's root directory (gradido) +Before running the tests, change to the repo's root directory (gradido). ### Boot up the system under test From bc11a4a5baec9e80bd2613aec039d841919ab3ac Mon Sep 17 00:00:00 2001 From: joseji Date: Thu, 29 Sep 2022 12:26:28 +0200 Subject: [PATCH 872/977] headers fix --- docu/Concepts/TechnicalRequirements/BusinessEventProtocol.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docu/Concepts/TechnicalRequirements/BusinessEventProtocol.md b/docu/Concepts/TechnicalRequirements/BusinessEventProtocol.md index 13a32cce3..dfafe11dd 100644 --- a/docu/Concepts/TechnicalRequirements/BusinessEventProtocol.md +++ b/docu/Concepts/TechnicalRequirements/BusinessEventProtocol.md @@ -62,7 +62,7 @@ The business events will be stored in database in the new table `EventProtocol`. The following table lists for each event type the mapping between old and new key, the mandatory attributes, which have to be initialized at event occurence and to be written in the database event protocol table: -| EventType - old key | EventType - new key | id | type | createdAt | userID | XuserID | XCommunityID | transactionID | contribID | amount | +| EventKey | EventType | id | type | createdAt | userID | XuserID | XCommunityID | transactionID | contribID | amount | | :-------------------------------- | :------------------------------------- | :-: | :--: | :-------: | :----: | :-----: | :----------: | :-----------: | :-------: | :----: | | BASIC | BasicEvent | x | x | x | | | | | | | | VISIT_GRADIDO | VisitGradidoEvent | x | x | x | | | | | | | From f05c31f69b90df32e71d424c08a166246dbe277e Mon Sep 17 00:00:00 2001 From: joseji Date: Thu, 29 Sep 2022 12:32:43 +0200 Subject: [PATCH 873/977] removed duplicated code --- backend/src/event/Event.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/backend/src/event/Event.ts b/backend/src/event/Event.ts index ee24c768b..a70df23a2 100644 --- a/backend/src/event/Event.ts +++ b/backend/src/event/Event.ts @@ -69,9 +69,7 @@ export class EventTransactionReceive extends EventBasicTx {} export class EventTransactionReceiveRedeem extends EventBasicTx {} export class EventContributionCreate extends EventBasicCt {} export class EventUserCreateContributionMessage extends EventBasicCtMsg {} -export class EventAdminCreateContributionMessage extends EventBasicCtMsg { - message: string -} +export class EventAdminCreateContributionMessage extends EventBasicCtMsg {} export class EventContributionDelete extends EventBasicCt {} export class EventContributionUpdate extends EventBasicCt {} export class EventContributionConfirm extends EventBasicCtX {} From 55453b217b35da34c3966ec9c5e696e1b4d6eda0 Mon Sep 17 00:00:00 2001 From: mahula Date: Thu, 29 Sep 2022 12:37:30 +0200 Subject: [PATCH 874/977] admin frontend: merge components - functionality of slot compoments IsModerator and IsNotModerator is added to component ContributionMessagesListItem - the slot components are removed, since not required anymore --- .../slots/ContributionMessagesListItem.vue | 37 +++++++++++++++---- .../slots/IsModerator.vue | 37 ------------------- .../slots/IsNotModerator.vue | 34 ----------------- 3 files changed, 29 insertions(+), 79 deletions(-) delete mode 100644 admin/src/components/ContributionMessages/slots/IsModerator.vue delete mode 100644 admin/src/components/ContributionMessages/slots/IsNotModerator.vue diff --git a/admin/src/components/ContributionMessages/slots/ContributionMessagesListItem.vue b/admin/src/components/ContributionMessages/slots/ContributionMessagesListItem.vue index fa5bdd940..b0630d0b4 100644 --- a/admin/src/components/ContributionMessages/slots/ContributionMessagesListItem.vue +++ b/admin/src/components/ContributionMessages/slots/ContributionMessagesListItem.vue @@ -1,19 +1,24 @@ + diff --git a/admin/src/components/ContributionMessages/slots/IsModerator.vue b/admin/src/components/ContributionMessages/slots/IsModerator.vue deleted file mode 100644 index 0224e042f..000000000 --- a/admin/src/components/ContributionMessages/slots/IsModerator.vue +++ /dev/null @@ -1,37 +0,0 @@ - - - diff --git a/admin/src/components/ContributionMessages/slots/IsNotModerator.vue b/admin/src/components/ContributionMessages/slots/IsNotModerator.vue deleted file mode 100644 index 64946c557..000000000 --- a/admin/src/components/ContributionMessages/slots/IsNotModerator.vue +++ /dev/null @@ -1,34 +0,0 @@ - - - From 899b74d60a4b83317fc4c1e8fbcef5810e3d1cb8 Mon Sep 17 00:00:00 2001 From: mahula Date: Thu, 29 Sep 2022 12:39:21 +0200 Subject: [PATCH 875/977] wallet frontend: merge components - functionality of slot compoments IsModerator and IsNotModerator is added to component ContributionMessagesListItem - the slot components are removed, since not required anymore --- .../ContributionMessagesListItem.vue | 39 ++++++++++++++----- .../slots/IsModerator.vue | 34 ---------------- .../slots/IsNotModerator.vue | 36 ----------------- 3 files changed, 30 insertions(+), 79 deletions(-) delete mode 100644 frontend/src/components/ContributionMessages/slots/IsModerator.vue delete mode 100644 frontend/src/components/ContributionMessages/slots/IsNotModerator.vue diff --git a/frontend/src/components/ContributionMessages/ContributionMessagesListItem.vue b/frontend/src/components/ContributionMessages/ContributionMessagesListItem.vue index 5fde8f825..85d371250 100644 --- a/frontend/src/components/ContributionMessages/ContributionMessagesListItem.vue +++ b/frontend/src/components/ContributionMessages/ContributionMessagesListItem.vue @@ -1,19 +1,24 @@ - + diff --git a/frontend/src/components/ContributionMessages/slots/IsModerator.vue b/frontend/src/components/ContributionMessages/slots/IsModerator.vue deleted file mode 100644 index 343b92d97..000000000 --- a/frontend/src/components/ContributionMessages/slots/IsModerator.vue +++ /dev/null @@ -1,34 +0,0 @@ - - - diff --git a/frontend/src/components/ContributionMessages/slots/IsNotModerator.vue b/frontend/src/components/ContributionMessages/slots/IsNotModerator.vue deleted file mode 100644 index 8efca7270..000000000 --- a/frontend/src/components/ContributionMessages/slots/IsNotModerator.vue +++ /dev/null @@ -1,36 +0,0 @@ - - - From 14aa976e5a1c1ce19e6807a250f0dba54bfcfa3a Mon Sep 17 00:00:00 2001 From: mahula Date: Tue, 4 Oct 2022 12:11:23 +0200 Subject: [PATCH 876/977] wallet frontend: adapt unit tests for merged components - add tests to ContributionMessagesListItem.spec.js - remove slots tests --- .../ContributionMessagesListItem.spec.js | 127 +++++++++++++++--- .../ContributionMessagesListItem.vue | 4 +- .../slots/IsModerator.spec.js | 49 ------- .../slots/IsNotModerator.spec.js | 49 ------- 4 files changed, 110 insertions(+), 119 deletions(-) delete mode 100644 frontend/src/components/ContributionMessages/slots/IsModerator.spec.js delete mode 100644 frontend/src/components/ContributionMessages/slots/IsNotModerator.spec.js diff --git a/frontend/src/components/ContributionMessages/ContributionMessagesListItem.spec.js b/frontend/src/components/ContributionMessages/ContributionMessagesListItem.spec.js index b9f6f0029..74cab882d 100644 --- a/frontend/src/components/ContributionMessages/ContributionMessagesListItem.spec.js +++ b/frontend/src/components/ContributionMessages/ContributionMessagesListItem.spec.js @@ -1,29 +1,29 @@ import { mount } from '@vue/test-utils' import ContributionMessagesList from './ContributionMessagesList.vue' +import ContributionMessagesListItem from './ContributionMessagesListItem.vue' const localVue = global.localVue +let wrapper + +const mocks = { + $t: jest.fn((t) => t), + $d: jest.fn((d) => d), + $store: { + state: { + firstName: 'Peter', + lastName: 'Lustig', + }, + }, +} describe('ContributionMessagesList', () => { - let wrapper - - const mocks = { - $t: jest.fn((t) => t), - $d: jest.fn((d) => d), - $store: { - state: { - firstName: 'Peter', - lastName: 'Lustig', - }, - }, - } - const propsData = { contributionId: 42, - state: 'PENDING0', + state: 'PENDING', messages: [ { id: 111, - message: 'asd asda sda sda', + message: 'Lorem ipsum?', createdAt: '2022-08-29T12:23:27.000Z', updatedAt: null, type: 'DIALOG', @@ -32,10 +32,21 @@ describe('ContributionMessagesList', () => { userId: 107, __typename: 'ContributionMessage', }, + { + id: 113, + message: 'Asda sdad ad asdasd, das Ass das Das. ', + createdAt: '2022-08-29T12:25:34.000Z', + updatedAt: null, + type: 'DIALOG', + userFirstName: 'Bibi', + userLastName: 'Bloxberg', + userId: 108, + __typename: 'ContributionMessage', + }, ], } - const Wrapper = () => { + const ListWrapper = () => { return mount(ContributionMessagesList, { localVue, mocks, @@ -45,11 +56,89 @@ describe('ContributionMessagesList', () => { describe('mount', () => { beforeEach(() => { - wrapper = Wrapper() + wrapper = ListWrapper() }) - it('has a DIV .contribution-messages-list-item', () => { - expect(wrapper.find('div.contribution-messages-list-item').exists()).toBe(true) + it('has two DIV .contribution-messages-list-item elements', () => { + expect(wrapper.findAll('div.contribution-messages-list-item').length).toBe(2) + }) + }) +}) + +describe('ContributionMessagesListItem', () => { + describe('if message author has moderator role', () => { + const propsData = { + message: { + id: 113, + message: 'Asda sdad ad asdasd, das Ass das Das. ', + createdAt: '2022-08-29T12:25:34.000Z', + updatedAt: null, + type: 'DIALOG', + userFirstName: 'Bibi', + userLastName: 'Bloxberg', + userId: 108, + __typename: 'ContributionMessage', + }, + } + + const ItemWrapper = () => { + return mount(ContributionMessagesListItem, { + localVue, + mocks, + propsData, + }) + } + + describe('mount', () => { + beforeAll(() => { + wrapper = ItemWrapper() + }) + + it('has a DIV .is-moderator.text-left', () => { + expect(wrapper.find('div.is-moderator.text-left').exists()).toBe(true) + }) + + it('props.message.default', () => { + expect(wrapper.vm.$options.props.message.default.call()).toEqual({}) + }) + }) + }) + + describe('if message author does not have moderator role', () => { + const propsData = { + message: { + id: 111, + message: 'Lorem ipsum?', + createdAt: '2022-08-29T12:23:27.000Z', + updatedAt: null, + type: 'DIALOG', + userFirstName: 'Peter', + userLastName: 'Lustig', + userId: 107, + __typename: 'ContributionMessage', + }, + } + + const ModeratorItemWrapper = () => { + return mount(ContributionMessagesListItem, { + localVue, + mocks, + propsData, + }) + } + + describe('mount', () => { + beforeAll(() => { + wrapper = ModeratorItemWrapper() + }) + + it('has a DIV .is-not-moderator.text-right', () => { + expect(wrapper.find('div.is-not-moderator.text-right').exists()).toBe(true) + }) + + it('props.message.default', () => { + expect(wrapper.vm.$options.props.message.default.call()).toEqual({}) + }) }) }) }) diff --git a/frontend/src/components/ContributionMessages/ContributionMessagesListItem.vue b/frontend/src/components/ContributionMessages/ContributionMessagesListItem.vue index 85d371250..e2bc50be6 100644 --- a/frontend/src/components/ContributionMessages/ContributionMessagesListItem.vue +++ b/frontend/src/components/ContributionMessages/ContributionMessagesListItem.vue @@ -44,7 +44,7 @@ export default { diff --git a/admin/src/components/ContributionMessages/slots/IsNotModerator.vue b/admin/src/components/ContributionMessages/slots/IsNotModerator.vue deleted file mode 100644 index f45d4f890..000000000 --- a/admin/src/components/ContributionMessages/slots/IsNotModerator.vue +++ /dev/null @@ -1,34 +0,0 @@ - - - diff --git a/frontend/src/components/ContributionMessages/slots/IsModerator.vue b/frontend/src/components/ContributionMessages/slots/IsModerator.vue deleted file mode 100644 index d0810d9fb..000000000 --- a/frontend/src/components/ContributionMessages/slots/IsModerator.vue +++ /dev/null @@ -1,34 +0,0 @@ - - - diff --git a/frontend/src/components/ContributionMessages/slots/IsNotModerator.vue b/frontend/src/components/ContributionMessages/slots/IsNotModerator.vue deleted file mode 100644 index c726cb8ef..000000000 --- a/frontend/src/components/ContributionMessages/slots/IsNotModerator.vue +++ /dev/null @@ -1,36 +0,0 @@ - - - From cb39745b2324bbf2312435ee5fe207be0f6cec54 Mon Sep 17 00:00:00 2001 From: ogerly Date: Sat, 15 Oct 2022 07:54:58 +0200 Subject: [PATCH 943/977] change linkify to computed --- .../slots/ContributionMessagesListItem.vue | 32 ++++++------------- .../ContributionMessagesListItem.vue | 26 +++++---------- 2 files changed, 18 insertions(+), 40 deletions(-) diff --git a/admin/src/components/ContributionMessages/slots/ContributionMessagesListItem.vue b/admin/src/components/ContributionMessages/slots/ContributionMessagesListItem.vue index 70ca24cc4..5eae5d7cd 100644 --- a/admin/src/components/ContributionMessages/slots/ContributionMessagesListItem.vue +++ b/admin/src/components/ContributionMessages/slots/ContributionMessagesListItem.vue @@ -1,21 +1,24 @@