From 677581b76e8bef2fa8c42450016ce58a32b6fcd1 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Fri, 18 Mar 2022 03:13:00 +0100 Subject: [PATCH 01/39] enforce config on backend --- backend/.env.dist | 2 ++ backend/.env.template | 2 ++ backend/src/config/index.ts | 17 +++++++++++++++++ 3 files changed, 21 insertions(+) diff --git a/backend/.env.dist b/backend/.env.dist index b1b16972f..85ad886f1 100644 --- a/backend/.env.dist +++ b/backend/.env.dist @@ -1,3 +1,5 @@ +CONFIG_VERSION=v1.2022-03-18 + # Server PORT=4000 JWT_SECRET=secret123 diff --git a/backend/.env.template b/backend/.env.template index b3a5eb4c6..454b25d3c 100644 --- a/backend/.env.template +++ b/backend/.env.template @@ -1,3 +1,5 @@ +CONFIG_VERSION=$BACKEND_CONFIG_VERSION + # Server JWT_SECRET=$JWT_SECRET JWT_EXPIRES_IN=10m diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index 79101856c..2a2bd6008 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -12,6 +12,11 @@ Decimal.set({ const constants = { DB_VERSION: '0032-add-transaction-link-to-transaction', DECAY_START_TIME: new Date('2021-05-13 17:46:31'), // GMT+0 + CONFIG_VERSION: { + DEFAULT: 'DEFAULT', + EXPECTED: 'v1.2022-03-18', + CURRENT: '', + }, } const server = { @@ -78,6 +83,18 @@ const webhook = { // This is needed by graphql-directive-auth process.env.APP_SECRET = server.JWT_SECRET +// Check config version +constants.CONFIG_VERSION.CURRENT = process.env.CONFIG_VERSION || constants.CONFIG_VERSION.DEFAULT +if ( + ![constants.CONFIG_VERSION.EXPECTED, constants.CONFIG_VERSION.DEFAULT].includes( + constants.CONFIG_VERSION.CURRENT, + ) +) { + throw new Error( + `Fatal: Config Version incorrect - expected "${constants.CONFIG_VERSION.EXPECTED}" or "${constants.CONFIG_VERSION.DEFAULT}", but found "${constants.CONFIG_VERSION.CURRENT}"`, + ) +} + const CONFIG = { ...constants, ...server, From c9177bbce3fbaf648fd239f4bb3d4aeb1ff06e5f Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Fri, 18 Mar 2022 03:13:11 +0100 Subject: [PATCH 02/39] enforce config database --- database/.env.dist | 2 ++ database/.env.template | 2 ++ database/src/config/index.ts | 22 +++++++++++++++++++++- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/database/.env.dist b/database/.env.dist index 689e4f509..58362a7b9 100644 --- a/database/.env.dist +++ b/database/.env.dist @@ -1,3 +1,5 @@ +CONFIG_VERSION=v1.2022-03-18 + DB_HOST=localhost DB_PORT=3306 DB_USER=root diff --git a/database/.env.template b/database/.env.template index 5b8554bcf..f2517a397 100644 --- a/database/.env.template +++ b/database/.env.template @@ -1,3 +1,5 @@ +CONFIG_VERSION=$DATABASE_CONFIG_VERSION + DB_HOST=localhost DB_PORT=3306 DB_USER=$DB_USER diff --git a/database/src/config/index.ts b/database/src/config/index.ts index 2dde06c96..ba41f11d4 100644 --- a/database/src/config/index.ts +++ b/database/src/config/index.ts @@ -3,6 +3,14 @@ import dotenv from 'dotenv' dotenv.config() +const constants = { + CONFIG_VERSION: { + DEFAULT: 'DEFAULT', + EXPECTED: 'v1.2022-03-18', + CURRENT: '', + }, +} + const database = { DB_HOST: process.env.DB_HOST || 'localhost', DB_PORT: process.env.DB_PORT ? parseInt(process.env.DB_PORT) : 3306, @@ -15,6 +23,18 @@ const migrations = { MIGRATIONS_TABLE: process.env.MIGRATIONS_TABLE || 'migrations', } -const CONFIG = { ...database, ...migrations } +// Check config version +constants.CONFIG_VERSION.CURRENT = process.env.CONFIG_VERSION || constants.CONFIG_VERSION.DEFAULT +if ( + ![constants.CONFIG_VERSION.EXPECTED, constants.CONFIG_VERSION.DEFAULT].includes( + constants.CONFIG_VERSION.CURRENT, + ) +) { + throw new Error( + `Fatal: Config Version incorrect - expected "${constants.CONFIG_VERSION.EXPECTED}" or "${constants.CONFIG_VERSION.DEFAULT}", but found "${constants.CONFIG_VERSION.CURRENT}"`, + ) +} + +const CONFIG = { ...constants, ...database, ...migrations } export default CONFIG From 28588ae25c8ab5b08e2330e554a4c9157aa172c7 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Fri, 18 Mar 2022 03:17:48 +0100 Subject: [PATCH 03/39] deployment .env.dist config versions --- deployment/bare_metal/.env.dist | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/deployment/bare_metal/.env.dist b/deployment/bare_metal/.env.dist index 9a9d57b4c..ee0ac3cc3 100644 --- a/deployment/bare_metal/.env.dist +++ b/deployment/bare_metal/.env.dist @@ -18,6 +18,8 @@ WEBHOOK_GITHUB_SECRET=secret WEBHOOK_GITHUB_BRANCH=master # backend +BACKEND_CONFIG_VERSION=v1.2022-03-18 + EMAIL=true EMAIL_USERNAME=peter@lustig.de EMAIL_SENDER=peter@lustig.de @@ -43,6 +45,9 @@ KLICKTIPP_PASSWORD= KLICKTIPP_APIKEY_DE= KLICKTIPP_APIKEY_EN= +# database +DATABASE_CONFIG_VERSION=v1.2022-03-18 + # frontend GRAPHQL_URI=https://stage1.gradido.net/graphql ADMIN_AUTH_URL=https://stage1.gradido.net/admin/authenticate?token={token} From 2fb5cf2d81b0f3388197128fac46138b4207a790 Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 21 Mar 2022 10:27:14 +0100 Subject: [PATCH 04/39] delete redeemCode from store --- frontend/src/store/store.js | 5 ----- frontend/src/store/store.test.js | 11 +---------- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/frontend/src/store/store.js b/frontend/src/store/store.js index fb74624fb..458c8c8de 100644 --- a/frontend/src/store/store.js +++ b/frontend/src/store/store.js @@ -47,9 +47,6 @@ export const mutations = { hasElopage: (state, hasElopage) => { state.hasElopage = hasElopage }, - redeemCode: (state, redeemCode) => { - state.redeemCode = redeemCode - }, } export const actions = { @@ -76,7 +73,6 @@ export const actions = { commit('hasElopage', false) commit('publisherId', null) commit('isAdmin', false) - commit('redeemCode', null) localStorage.clear() }, } @@ -106,7 +102,6 @@ try { }, hasElopage: false, publisherId: null, - redeemCode: null, }, getters: {}, // Syncronous mutation of the state diff --git a/frontend/src/store/store.test.js b/frontend/src/store/store.test.js index 29a703e8f..ea40d9474 100644 --- a/frontend/src/store/store.test.js +++ b/frontend/src/store/store.test.js @@ -26,7 +26,6 @@ const { isAdmin, community, hasElopage, - redeemCode, } = mutations const { login, logout } = actions @@ -142,14 +141,6 @@ describe('Vuex store', () => { hasElopage(state, true) expect(state.hasElopage).toBeTruthy() }) - - describe('redeemCode', () => { - it('sets the state of token', () => { - const state = { redeemCode: null } - redeemCode(state, 'a0000b0000c0000') - expect(state.redeemCode).toEqual('a0000b0000c0000') - }) - }) }) }) @@ -228,7 +219,7 @@ describe('Vuex store', () => { it('calls nine commits', () => { logout({ commit, state }) - expect(commit).toHaveBeenCalledTimes(10) + expect(commit).toHaveBeenCalledTimes(9) }) it('commits token', () => { From 6c87a6f32a05b98ca081e6d9d00704b766b45413 Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 21 Mar 2022 10:28:12 +0100 Subject: [PATCH 05/39] changed code from store to param --- frontend/src/pages/Register.vue | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/frontend/src/pages/Register.vue b/frontend/src/pages/Register.vue index b2df16e0f..4ffe92512 100755 --- a/frontend/src/pages/Register.vue +++ b/frontend/src/pages/Register.vue @@ -118,7 +118,7 @@ {{ messageError }} - +
@@ -130,7 +130,7 @@ readonly id="redeem-code" type="text" - v-model="$store.state.redeemCode" + v-model="redeemCode" >
@@ -234,7 +234,7 @@ export default { messageError: '', register: true, publisherId: this.$store.state.publisherId, - redeemCode: this.$store.state.redeemCode, + redeemCode: this.$route.params.code, } }, methods: { @@ -248,9 +248,6 @@ export default { commitStorePublisherId(val) { this.$store.commit('publisherId', val) }, - commitStoreRedeemCode(val) { - this.$store.commit('redeemCode', val) - }, async onSubmit() { this.$apollo .mutate({ @@ -261,7 +258,7 @@ export default { lastName: this.form.lastname, language: this.language, publisherId: this.$store.state.publisherId, - redeemCode: this.$store.state.redeemCode, + redeemCode: this.redeemCode, }, }) .then(() => { @@ -296,10 +293,5 @@ export default { return !(this.namesFilled && this.emailFilled && this.form.agree && !!this.language) }, }, - created() { - if (this.$route.params.code) { - this.commitStoreRedeemCode(this.$route.params.code) - } - }, } From 1f1cd67b9e76824613993fa850e9a9076559f60a Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 21 Mar 2022 10:29:13 +0100 Subject: [PATCH 06/39] add redeemCode --- backend/src/graphql/arg/CreateUserArgs.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/src/graphql/arg/CreateUserArgs.ts b/backend/src/graphql/arg/CreateUserArgs.ts index 0d63e76bb..59462aa2a 100644 --- a/backend/src/graphql/arg/CreateUserArgs.ts +++ b/backend/src/graphql/arg/CreateUserArgs.ts @@ -16,4 +16,7 @@ export default class CreateUserArgs { @Field(() => Int, { nullable: true }) publisherId: number + + @Field(() => String, { nullable: true }) + redeemCode: string } From 3992882962fedb69714d651aecffbf1fc0548bd8 Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 21 Mar 2022 10:29:56 +0100 Subject: [PATCH 07/39] add redeemCode on UserResolver.ts --- backend/src/graphql/resolver/UserResolver.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 04c5fdf63..4ee564977 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -313,7 +313,7 @@ export class UserResolver { @Authorized([RIGHTS.CREATE_USER]) @Mutation(() => User) async createUser( - @Args() { email, firstName, lastName, language, publisherId }: CreateUserArgs, + @Args() { email, firstName, lastName, language, publisherId, redeemCode }: CreateUserArgs, ): Promise { // TODO: wrong default value (should be null), how does graphql work here? Is it an required field? // default int publisher_id = 0; From 15e0186381522fb60a8d9efe0852353f46eff643 Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 21 Mar 2022 10:54:56 +0100 Subject: [PATCH 08/39] add redeemCode on register process for createUser --- backend/src/graphql/resolver/UserResolver.ts | 10 +++++++--- backend/src/seeds/graphql/mutations.ts | 2 ++ backend/src/webhook/elopage.ts | 1 + frontend/src/graphql/mutations.js | 2 ++ 4 files changed, 12 insertions(+), 3 deletions(-) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 4ee564977..80e927da7 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -367,11 +367,15 @@ export class UserResolver { // TODO: this has duplicate code with sendResetPasswordEmail const emailOptIn = await createEmailOptIn(dbUser.id, queryRunner) - const activationLink = CONFIG.EMAIL_LINK_VERIFICATION.replace( + let activationLink = CONFIG.EMAIL_LINK_VERIFICATION.replace( /{code}/g, emailOptIn.verificationCode.toString(), ) + if (redeemCode !== '') { + activationLink += '/' + redeemCode + } + // eslint-disable-next-line @typescript-eslint/no-unused-vars const emailSent = await sendAccountActivationEmail({ link: activationLink, @@ -380,13 +384,13 @@ export class UserResolver { email, }) - /* uncomment this, when you need the activation link on the console + // 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}`) } - */ + await queryRunner.commitTransaction() } catch (e) { await queryRunner.rollbackTransaction() diff --git a/backend/src/seeds/graphql/mutations.ts b/backend/src/seeds/graphql/mutations.ts index 19ca2a8d0..cab864c4e 100644 --- a/backend/src/seeds/graphql/mutations.ts +++ b/backend/src/seeds/graphql/mutations.ts @@ -45,6 +45,7 @@ export const createUser = gql` $email: String! $language: String! $publisherId: Int + $redeemCode: String ) { createUser( email: $email @@ -52,6 +53,7 @@ export const createUser = gql` lastName: $lastName language: $language publisherId: $publisherId + redeemCode: $redeemCode ) { id } diff --git a/backend/src/webhook/elopage.ts b/backend/src/webhook/elopage.ts index d5eaef521..ee8c3fc94 100644 --- a/backend/src/webhook/elopage.ts +++ b/backend/src/webhook/elopage.ts @@ -140,6 +140,7 @@ export const elopageWebhook = async (req: any, res: any): Promise => { firstName, lastName, publisherId: loginElopageBuy.publisherId || 0, // This seemed to be the default value if not set + redeemCode: '', }) } catch (error) { // eslint-disable-next-line no-console diff --git a/frontend/src/graphql/mutations.js b/frontend/src/graphql/mutations.js index d3a177866..95c811f8d 100644 --- a/frontend/src/graphql/mutations.js +++ b/frontend/src/graphql/mutations.js @@ -45,6 +45,7 @@ export const createUser = gql` $email: String! $language: String! $publisherId: Int + $redeemCode: String ) { createUser( email: $email @@ -52,6 +53,7 @@ export const createUser = gql` lastName: $lastName language: $language publisherId: $publisherId + redeemCode: $redeemCode ) { id } From a23777b6ec5dccfd5e11b1a8e29b5c329c9747da Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 21 Mar 2022 12:07:59 +0100 Subject: [PATCH 09/39] uncomment code activationLink --- backend/src/graphql/resolver/UserResolver.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 80e927da7..311916aad 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -384,12 +384,13 @@ export class UserResolver { email, }) - // uncomment this, when you need the activation link on the console + /* 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}`) } + */ await queryRunner.commitTransaction() } catch (e) { From cdd13cf24e890760563ff043f483ab13bc61ae8d Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 21 Mar 2022 12:09:07 +0100 Subject: [PATCH 10/39] add params on thx and checkEmail --- frontend/src/routes/routes.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/routes/routes.js b/frontend/src/routes/routes.js index 5e0b09c5e..a6586c201 100755 --- a/frontend/src/routes/routes.js +++ b/frontend/src/routes/routes.js @@ -47,7 +47,7 @@ const routes = [ component: () => import('@/pages/Register.vue'), }, { - path: '/thx/:comingFrom', + path: '/thx/:comingFrom/:code?', component: () => import('@/pages/thx.vue'), beforeEnter: (to, from, next) => { const validFrom = ['forgot-password', 'reset-password', 'register', 'login', 'checkEmail'] @@ -79,7 +79,7 @@ const routes = [ component: () => import('@/pages/ResetPassword.vue'), }, { - path: '/checkEmail/:optin', + path: '/checkEmail/:optin/:code?', component: () => import('@/pages/ResetPassword.vue'), }, { From 6d257825e2aee4e5f9710c9e7c73666d2bdeed67 Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 21 Mar 2022 12:11:19 +0100 Subject: [PATCH 11/39] add redeemCode to login button --- frontend/src/pages/thx.vue | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/frontend/src/pages/thx.vue b/frontend/src/pages/thx.vue index 41c63c7d8..308c354fa 100644 --- a/frontend/src/pages/thx.vue +++ b/frontend/src/pages/thx.vue @@ -9,7 +9,11 @@

{{ $t(displaySetup.subtitle) }}


- + + + {{ $t(displaySetup.button) }} + + {{ $t(displaySetup.button) }} @@ -65,6 +69,11 @@ export default { this.displaySetup = textFields[this.$route.params.comingFrom] }, }, + computed: { + redeemLoginLink() { + return this.$route.params.code ? '/login/' + this.$route.params.code : '/login' + }, + }, created() { this.setDisplaySetup() }, From 042741a9aab75f05b0f74857d53ed9b658ee8d67 Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 21 Mar 2022 12:11:59 +0100 Subject: [PATCH 12/39] add code to push --- frontend/src/pages/ResetPassword.vue | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/src/pages/ResetPassword.vue b/frontend/src/pages/ResetPassword.vue index b0194c0ba..b6de8cb97 100644 --- a/frontend/src/pages/ResetPassword.vue +++ b/frontend/src/pages/ResetPassword.vue @@ -96,7 +96,11 @@ export default { .then(() => { this.form.password = '' if (this.$route.path.includes('checkEmail')) { - this.$router.push('/thx/checkEmail') + if (this.$route.params.code) { + this.$router.push('/thx/checkEmail/' + this.$route.params.code) + } else { + this.$router.push('/thx/checkEmail') + } } else { this.$router.push('/thx/resetPassword') } From f8882fa63a8f052b96188bf36874542cd1d7de76 Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 21 Mar 2022 14:41:50 +0100 Subject: [PATCH 13/39] remove computed --- frontend/src/pages/thx.vue | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/frontend/src/pages/thx.vue b/frontend/src/pages/thx.vue index 308c354fa..ee6338d26 100644 --- a/frontend/src/pages/thx.vue +++ b/frontend/src/pages/thx.vue @@ -9,7 +9,7 @@

{{ $t(displaySetup.subtitle) }}


- + {{ $t(displaySetup.button) }} @@ -69,11 +69,6 @@ export default { this.displaySetup = textFields[this.$route.params.comingFrom] }, }, - computed: { - redeemLoginLink() { - return this.$route.params.code ? '/login/' + this.$route.params.code : '/login' - }, - }, created() { this.setDisplaySetup() }, From 2b7d9d8c1a987eed7164692157fe9fdc94946831 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Mon, 21 Mar 2022 17:23:56 +0100 Subject: [PATCH 14/39] save referrer ID when present on register --- backend/src/graphql/resolver/UserResolver.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 33fba47a2..3b3ef394c 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -7,6 +7,7 @@ import { getConnection, getCustomRepository, QueryRunner } from '@dbTools/typeor import CONFIG from '@/config' import { User } from '@model/User' import { User as DbUser } from '@entity/User' +import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink' import { encode } from '@/auth/JWT' import CreateUserArgs from '@arg/CreateUserArgs' import UnsecureLoginArgs from '@arg/UnsecureLoginArgs' @@ -338,6 +339,12 @@ export class UserResolver { dbUser.language = language dbUser.publisherId = publisherId dbUser.passphrase = passphrase.join(' ') + if (redeemCode) { + const transactionLink = await dbTransactionLink.findOne({ code: redeemCode }) + if (transactionLink) { + dbUser.referrerId = transactionLink.userId + } + } // TODO this field has no null allowed unlike the loginServer table // dbUser.pubKey = Buffer.from(randomBytes(32)) // Buffer.alloc(32, 0) default to 0000... // dbUser.pubkey = keyPair[0] From 4675c5679068abafde0e51bdb2252a57a6cbcc1b Mon Sep 17 00:00:00 2001 From: ogerly Date: Mon, 21 Mar 2022 21:38:28 +0100 Subject: [PATCH 15/39] test router.test.js fixed --- frontend/src/routes/router.test.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/frontend/src/routes/router.test.js b/frontend/src/routes/router.test.js index 85f765c69..925b3ffca 100644 --- a/frontend/src/routes/router.test.js +++ b/frontend/src/routes/router.test.js @@ -112,7 +112,7 @@ describe('router', () => { }) describe('thx', () => { - const thx = routes.find((r) => r.path === '/thx/:comingFrom') + const thx = routes.find((r) => r.path === '/thx/:comingFrom/:code?') it('loads the "Thx" page', async () => { const component = await thx.component() @@ -177,7 +177,9 @@ describe('router', () => { describe('checkEmail', () => { it('loads the "CheckEmail" page', async () => { - const component = await routes.find((r) => r.path === '/checkEmail/:optin').component() + const component = await routes + .find((r) => r.path === '/checkEmail/:optin/:code?') + .component() expect(component.default.name).toBe('ResetPassword') }) }) From 8a2ca07b2edabd8ca7c432dfb8f07f9408b689db Mon Sep 17 00:00:00 2001 From: ogerly Date: Tue, 22 Mar 2022 07:09:58 +0100 Subject: [PATCH 16/39] test UserResolver.test.js ok, with redeemCode --- backend/src/graphql/resolver/UserResolver.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index f873fd694..a982f3768 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -54,6 +54,7 @@ describe('UserResolver', () => { lastName: 'Lustig', language: 'de', publisherId: 1234, + redeemCode: 'a0000b0000c0000', } let result: any @@ -126,7 +127,7 @@ describe('UserResolver', () => { it('sends an account activation email', () => { const activationLink = CONFIG.EMAIL_LINK_VERIFICATION.replace(/{code}/g, emailOptIn) expect(sendAccountActivationEmail).toBeCalledWith({ - link: activationLink, + link: activationLink + '/a0000b0000c0000', firstName: 'Peter', lastName: 'Lustig', email: 'peter@lustig.de', From 36b4c6cce7f599cad8d33e18fb2b1643f9cbf7b3 Mon Sep 17 00:00:00 2001 From: ogerly Date: Tue, 22 Mar 2022 09:01:09 +0100 Subject: [PATCH 17/39] update-balance if link succesfully generated --- frontend/src/pages/Send.vue | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/frontend/src/pages/Send.vue b/frontend/src/pages/Send.vue index 89eb1bbe2..bce9a6069 100644 --- a/frontend/src/pages/Send.vue +++ b/frontend/src/pages/Send.vue @@ -143,6 +143,10 @@ export default { .then((result) => { this.code = result.data.createTransactionLink.code this.currentTransactionStep = TRANSACTION_STEPS.transactionResultLink + this.$emit( + 'update-balance', + this.transactionData.amount + this.transactionData.amount * 0.028, + ) }) .catch((error) => { this.toastError(error) From fe869e12c4ff64755ed318b52b313c4b238a14d6 Mon Sep 17 00:00:00 2001 From: Alexander Friedland Date: Tue, 22 Mar 2022 12:31:44 +0100 Subject: [PATCH 18/39] Update backend/src/graphql/resolver/UserResolver.test.ts Co-authored-by: Moriz Wahl --- backend/src/graphql/resolver/UserResolver.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/src/graphql/resolver/UserResolver.test.ts b/backend/src/graphql/resolver/UserResolver.test.ts index a982f3768..ea78c56bd 100644 --- a/backend/src/graphql/resolver/UserResolver.test.ts +++ b/backend/src/graphql/resolver/UserResolver.test.ts @@ -54,7 +54,6 @@ describe('UserResolver', () => { lastName: 'Lustig', language: 'de', publisherId: 1234, - redeemCode: 'a0000b0000c0000', } let result: any From 7929b93964c254889379f7ded46aa658a172fcf4 Mon Sep 17 00:00:00 2001 From: Alexander Friedland Date: Tue, 22 Mar 2022 12:33:10 +0100 Subject: [PATCH 19/39] Update backend/src/graphql/resolver/UserResolver.ts Co-authored-by: Ulf Gebhardt --- backend/src/graphql/resolver/UserResolver.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 3b3ef394c..6d9e42405 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -306,7 +306,7 @@ export class UserResolver { @Authorized([RIGHTS.CREATE_USER]) @Mutation(() => User) async createUser( - @Args() { email, firstName, lastName, language, publisherId, redeemCode }: CreateUserArgs, + @Args() { email, firstName, lastName, language, publisherId, redeemCode = null}: CreateUserArgs, ): Promise { // TODO: wrong default value (should be null), how does graphql work here? Is it an required field? // default int publisher_id = 0; From eda69bfc47edecf508c7734ba508ec42d41d9e8d Mon Sep 17 00:00:00 2001 From: Alexander Friedland Date: Tue, 22 Mar 2022 12:34:17 +0100 Subject: [PATCH 20/39] Update backend/src/graphql/resolver/UserResolver.ts Co-authored-by: Ulf Gebhardt --- backend/src/graphql/resolver/UserResolver.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 6d9e42405..0e9e7c867 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -371,7 +371,7 @@ export class UserResolver { emailOptIn.verificationCode.toString(), ) - if (redeemCode !== '') { + if (redeemCode) { activationLink += '/' + redeemCode } From 703217e9384afa1783c974584705dbaa0b54385b Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 22 Mar 2022 13:07:01 +0100 Subject: [PATCH 21/39] enforce config in frontend --- frontend/.env.dist | 2 ++ frontend/.env.template | 2 ++ frontend/src/config/index.js | 61 +++++++++++++++++++++++------------- frontend/vue.config.js | 23 +++++++------- 4 files changed, 56 insertions(+), 32 deletions(-) diff --git a/frontend/.env.dist b/frontend/.env.dist index 0de8c6252..df3c7cd7e 100644 --- a/frontend/.env.dist +++ b/frontend/.env.dist @@ -1,3 +1,5 @@ +CONFIG_VERSION=v1.2022-03-18 + META_URL=http://localhost META_TITLE_DE="Gradido – Dein Dankbarkeitskonto" META_TITLE_EN="Gradido - Your gratitude account" diff --git a/frontend/.env.template b/frontend/.env.template index 1eef43cef..4e4a86d08 100644 --- a/frontend/.env.template +++ b/frontend/.env.template @@ -1,3 +1,5 @@ +CONFIG_VERSION=$FRONTEND_CONFIG_VERSION + META_URL=$META_URL META_TITLE_DE=$META_TITLE_DE META_TITLE_EN=$META_TITLE_EN diff --git a/frontend/src/config/index.js b/frontend/src/config/index.js index eaa1e7f3d..8b2b68a8a 100644 --- a/frontend/src/config/index.js +++ b/frontend/src/config/index.js @@ -4,6 +4,14 @@ // Load Package Details for some default values const pkg = require('../../package') +const constants = { + CONFIG_VERSION: { + DEFAULT: 'DEFAULT', + EXPECTED: 'v1.2022-03-18', + CURRENT: '', + }, +} + const version = { APP_VERSION: pkg.version, BUILD_COMMIT: process.env.BUILD_COMMIT || null, @@ -16,39 +24,50 @@ const environment = { DEBUG: process.env.NODE_ENV !== 'production' || false, PRODUCTION: process.env.NODE_ENV === 'production' || false, DEFAULT_PUBLISHER_ID: process.env.DEFAULT_PUBLISHER_ID || 2896, + PORT: process.env.PORT || 3000, } -// const meta = { -// META_URL: process.env.META_URL || 'http://localhost', -// META_TITLE_DE: process.env.META_TITLE_DE || 'Gradido – Dein Dankbarkeitskonto', -// META_TITLE_EN: process.env.META_TITLE_EN || 'Gradido - Your gratitude account', -// META_DESCRIPTION_DE: -// process.env.META_DESCRIPTION_DE || -// 'Dankbarkeit ist die Währung der neuen Zeit. Immer mehr Menschen entfalten ihr Potenzial und gestalten eine gute Zukunft für alle.', -// META_DESCRIPTION_EN: -// process.env.META_DESCRIPTION_EN || -// 'Gratitude is the currency of the new age. More and more people are unleashing their potential and shaping a good future for all.', -// META_KEYWORDS_DE: -// process.env.META_KEYWORDS_DE || -// 'Grundeinkommen, Währung, Dankbarkeit, Schenk-Ökonomie, Natürliche Ökonomie des Lebens, Ökonomie, Ökologie, Potenzialentfaltung, Schenken und Danken, Kreislauf des Lebens, Geldsystem', -// META_KEYWORDS_EN: -// process.env.META_KEYWORDS_EN || -// 'Basic Income, Currency, Gratitude, Gift Economy, Natural Economy of Life, Economy, Ecology, Potential Development, Giving and Thanking, Cycle of Life, Monetary System', -// META_AUTHOR: process.env.META_AUTHOR || 'Bernd Hückstädt - Gradido-Akademie', -// } +const meta = { + META_URL: process.env.META_URL || 'http://localhost', + META_TITLE_DE: process.env.META_TITLE_DE || 'Gradido – Dein Dankbarkeitskonto', + META_TITLE_EN: process.env.META_TITLE_EN || 'Gradido - Your gratitude account', + META_DESCRIPTION_DE: + process.env.META_DESCRIPTION_DE || + 'Dankbarkeit ist die Währung der neuen Zeit. Immer mehr Menschen entfalten ihr Potenzial und gestalten eine gute Zukunft für alle.', + META_DESCRIPTION_EN: + process.env.META_DESCRIPTION_EN || + 'Gratitude is the currency of the new age. More and more people are unleashing their potential and shaping a good future for all.', + META_KEYWORDS_DE: + process.env.META_KEYWORDS_DE || + 'Grundeinkommen, Währung, Dankbarkeit, Schenk-Ökonomie, Natürliche Ökonomie des Lebens, Ökonomie, Ökologie, Potenzialentfaltung, Schenken und Danken, Kreislauf des Lebens, Geldsystem', + META_KEYWORDS_EN: + process.env.META_KEYWORDS_EN || + 'Basic Income, Currency, Gratitude, Gift Economy, Natural Economy of Life, Economy, Ecology, Potential Development, Giving and Thanking, Cycle of Life, Monetary System', + META_AUTHOR: process.env.META_AUTHOR || 'Bernd Hückstädt - Gradido-Akademie', +} const endpoints = { GRAPHQL_URI: process.env.GRAPHQL_URI || 'http://localhost/graphql', ADMIN_AUTH_URL: process.env.ADMIN_AUTH_URL || 'http://localhost/admin/authenticate?token={token}', } -const options = {} +// Check config version +constants.CONFIG_VERSION.CURRENT = process.env.CONFIG_VERSION || constants.CONFIG_VERSION.DEFAULT +if ( + ![constants.CONFIG_VERSION.EXPECTED, constants.CONFIG_VERSION.DEFAULT].includes( + constants.CONFIG_VERSION.CURRENT, + ) +) { + throw new Error( + `Fatal: Config Version incorrect - expected "${constants.CONFIG_VERSION.EXPECTED}" or "${constants.CONFIG_VERSION.DEFAULT}", but found "${constants.CONFIG_VERSION.CURRENT}"`, + ) +} const CONFIG = { ...version, ...environment, ...endpoints, - ...options, + ...meta, } -export default CONFIG +module.exports = CONFIG diff --git a/frontend/vue.config.js b/frontend/vue.config.js index 4c86a7a6d..573f2a70b 100644 --- a/frontend/vue.config.js +++ b/frontend/vue.config.js @@ -3,11 +3,12 @@ const webpack = require('webpack') const Dotenv = require('dotenv-webpack') const StatsPlugin = require('stats-webpack-plugin') const HtmlWebpackPlugin = require('vue-html-webpack-plugin') +const CONFIG = require('./src/config') // vue.config.js module.exports = { devServer: { - port: process.env.PORT || 3000, + port: CONFIG.PORT, }, pluginOptions: { i18n: { @@ -35,7 +36,7 @@ module.exports = { // 'process.env.DOCKER_WORKDIR': JSON.stringify(process.env.DOCKER_WORKDIR), // 'process.env.BUILD_DATE': JSON.stringify(process.env.BUILD_DATE), // 'process.env.BUILD_VERSION': JSON.stringify(process.env.BUILD_VERSION), - 'process.env.BUILD_COMMIT': JSON.stringify(process.env.BUILD_COMMIT), + 'process.env.BUILD_COMMIT': JSON.stringify(CONFIG.BUILD_COMMIT), // 'process.env.PORT': JSON.stringify(process.env.PORT), }), // generate webpack stats to allow analysis of the bundlesize @@ -44,14 +45,14 @@ module.exports = { vue: true, template: 'public/index.html', meta: { - title_de: process.env.META_TITLE_DE, - title_en: process.env.META_TITLE_EN, - description_de: process.env.META_DESCRIPTION_DE, - description_en: process.env.META_DESCRIPTION_EN, - keywords_de: process.env.META_KEYWORDS_DE, - keywords_en: process.env.META_KEYWORDS_EN, - author: process.env.META_AUTHOR, - url: process.env.META_URL, + title_de: CONFIG.META_TITLE_DE, + title_en: CONFIG.META_TITLE_EN, + description_de: CONFIG.META_DESCRIPTION_DE, + description_en: CONFIG.META_DESCRIPTION_EN, + keywords_de: CONFIG.META_KEYWORDS_DE, + keywords_en: CONFIG.META_KEYWORDS_EN, + author: CONFIG.META_AUTHOR, + url: CONFIG.META_URL, }, }), ], @@ -61,7 +62,7 @@ module.exports = { }, css: { // Enable CSS source maps. - sourceMap: process.env.NODE_ENV !== 'production', + sourceMap: CONFIG.NODE_ENV !== 'production', }, outputDir: path.resolve(__dirname, './dist'), } From 1d6dace9f46f7085839fb5bfd658c781a3be23c4 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 22 Mar 2022 13:14:13 +0100 Subject: [PATCH 22/39] implement admin config checking --- admin/.env.dist | 2 ++ admin/.env.template | 2 ++ admin/src/config/index.js | 25 ++++++++++++++++++++++--- admin/vue.config.js | 7 ++++--- 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/admin/.env.dist b/admin/.env.dist index 66c84dda8..d7044669a 100644 --- a/admin/.env.dist +++ b/admin/.env.dist @@ -1,3 +1,5 @@ +CONFIG_VERSION=v1.2022-03-18 + GRAPHQL_URI=http://localhost:4000/graphql WALLET_AUTH_URL=http://localhost/authenticate?token={token} WALLET_URL=http://localhost/login diff --git a/admin/.env.template b/admin/.env.template index a965b1bb1..488c9aba4 100644 --- a/admin/.env.template +++ b/admin/.env.template @@ -1,3 +1,5 @@ +CONFIG_VERSION=$ADMIN_CONFIG_VERSION + GRAPHQL_URI=$GRAPHQL_URI WALLET_AUTH_URL=$WALLET_AUTH_URL WALLET_URL=$WALLET_URL diff --git a/admin/src/config/index.js b/admin/src/config/index.js index f7d361c12..03700b4fa 100644 --- a/admin/src/config/index.js +++ b/admin/src/config/index.js @@ -4,11 +4,20 @@ // Load Package Details for some default values const pkg = require('../../package') +const constants = { + CONFIG_VERSION: { + DEFAULT: 'DEFAULT', + EXPECTED: 'v1.2022-03-18', + CURRENT: '', + }, +} + const version = { APP_VERSION: pkg.version, BUILD_COMMIT: process.env.BUILD_COMMIT || null, // self reference of `version.BUILD_COMMIT` is not possible at this point, hence the duplicate code BUILD_COMMIT_SHORT: (process.env.BUILD_COMMIT || '0000000').substr(0, 7), + PORT: process.env.PORT || 8080, } const environment = { @@ -27,14 +36,24 @@ const debug = { DEBUG_DISABLE_AUTH: process.env.DEBUG_DISABLE_AUTH === 'true' || false, } -const options = {} +// Check config version +constants.CONFIG_VERSION.CURRENT = process.env.CONFIG_VERSION || constants.CONFIG_VERSION.DEFAULT +if ( + ![constants.CONFIG_VERSION.EXPECTED, constants.CONFIG_VERSION.DEFAULT].includes( + constants.CONFIG_VERSION.CURRENT, + ) +) { + throw new Error( + `Fatal: Config Version incorrect - expected "${constants.CONFIG_VERSION.EXPECTED}" or "${constants.CONFIG_VERSION.DEFAULT}", but found "${constants.CONFIG_VERSION.CURRENT}"`, + ) +} const CONFIG = { + ...constants, ...version, ...environment, ...endpoints, - ...options, ...debug, } -export default CONFIG +module.exports = CONFIG diff --git a/admin/vue.config.js b/admin/vue.config.js index 4492312a0..8cc1e4b89 100644 --- a/admin/vue.config.js +++ b/admin/vue.config.js @@ -2,11 +2,12 @@ const path = require('path') const webpack = require('webpack') const Dotenv = require('dotenv-webpack') const StatsPlugin = require('stats-webpack-plugin') +const CONFIG = require('./src/config') // vue.config.js module.exports = { devServer: { - port: process.env.PORT || 8080, + port: CONFIG.PORT, }, pluginOptions: { i18n: { @@ -34,7 +35,7 @@ module.exports = { // 'process.env.DOCKER_WORKDIR': JSON.stringify(process.env.DOCKER_WORKDIR), // 'process.env.BUILD_DATE': JSON.stringify(process.env.BUILD_DATE), // 'process.env.BUILD_VERSION': JSON.stringify(process.env.BUILD_VERSION), - 'process.env.BUILD_COMMIT': JSON.stringify(process.env.BUILD_COMMIT), + 'process.env.BUILD_COMMIT': JSON.stringify(CONFIG.BUILD_COMMIT), // 'process.env.PORT': JSON.stringify(process.env.PORT), }), // generate webpack stats to allow analysis of the bundlesize @@ -46,7 +47,7 @@ module.exports = { }, css: { // Enable CSS source maps. - sourceMap: process.env.NODE_ENV !== 'production', + sourceMap: CONFIG.NODE_ENV !== 'production', }, outputDir: path.resolve(__dirname, './dist'), } From 31c6f77a780216c717d72427457cd3881951a12c Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 22 Mar 2022 13:14:26 +0100 Subject: [PATCH 23/39] include constants in the config values --- frontend/src/config/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/config/index.js b/frontend/src/config/index.js index 8b2b68a8a..a542a11f1 100644 --- a/frontend/src/config/index.js +++ b/frontend/src/config/index.js @@ -64,6 +64,7 @@ if ( } const CONFIG = { + ...constants, ...version, ...environment, ...endpoints, From 5e41b59fe758f0e89f0a983d716ed7d944d2a179 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 22 Mar 2022 13:18:10 +0100 Subject: [PATCH 24/39] fix deprecation warning: use `slice` instead of `substr` --- admin/src/config/index.js | 2 +- frontend/src/config/index.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/admin/src/config/index.js b/admin/src/config/index.js index 03700b4fa..fe373386d 100644 --- a/admin/src/config/index.js +++ b/admin/src/config/index.js @@ -16,7 +16,7 @@ const version = { APP_VERSION: pkg.version, BUILD_COMMIT: process.env.BUILD_COMMIT || null, // self reference of `version.BUILD_COMMIT` is not possible at this point, hence the duplicate code - BUILD_COMMIT_SHORT: (process.env.BUILD_COMMIT || '0000000').substr(0, 7), + BUILD_COMMIT_SHORT: (process.env.BUILD_COMMIT || '0000000').slice(0, 7), PORT: process.env.PORT || 8080, } diff --git a/frontend/src/config/index.js b/frontend/src/config/index.js index a542a11f1..3f62012ad 100644 --- a/frontend/src/config/index.js +++ b/frontend/src/config/index.js @@ -16,7 +16,7 @@ const version = { APP_VERSION: pkg.version, BUILD_COMMIT: process.env.BUILD_COMMIT || null, // self reference of `version.BUILD_COMMIT` is not possible at this point, hence the duplicate code - BUILD_COMMIT_SHORT: (process.env.BUILD_COMMIT || '0000000').substr(0, 7), + BUILD_COMMIT_SHORT: (process.env.BUILD_COMMIT || '0000000').slice(0, 7), } const environment = { From 0a3f80ddc9ee883edf24557030f8cfb2ba1e5b4b Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 22 Mar 2022 17:53:51 +0100 Subject: [PATCH 25/39] add default properties to restore data when transaction is canceled in confirmation step --- frontend/src/components/GddSend/TransactionForm.vue | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/GddSend/TransactionForm.vue b/frontend/src/components/GddSend/TransactionForm.vue index ec4aff4d3..c1acf9925 100644 --- a/frontend/src/components/GddSend/TransactionForm.vue +++ b/frontend/src/components/GddSend/TransactionForm.vue @@ -160,15 +160,18 @@ export default { }, props: { balance: { type: Number, default: 0 }, + email: { type: String, default: '' }, + amount: { type: Number, default: 0 }, + memo: { type: String, default: '' }, }, data() { return { amountFocused: false, emailFocused: false, form: { - email: '', - amount: '', - memo: '', + email: this.email, + amount: this.amount ? String(this.amount) : '', + memo: this.memo, amountValue: 0.0, }, selected: SEND_TYPES.send, From e08e1b7ea8618d675aea2ae23b5ff31616cdecf8 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 22 Mar 2022 17:54:55 +0100 Subject: [PATCH 26/39] remove update balance method and event. We want to have the data always from the backend and do no calculation in the frontend --- frontend/src/layouts/DashboardLayout_gdd.spec.js | 8 -------- frontend/src/layouts/DashboardLayout_gdd.vue | 4 ---- 2 files changed, 12 deletions(-) diff --git a/frontend/src/layouts/DashboardLayout_gdd.spec.js b/frontend/src/layouts/DashboardLayout_gdd.spec.js index 2a8b7bf42..fd45b9f05 100644 --- a/frontend/src/layouts/DashboardLayout_gdd.spec.js +++ b/frontend/src/layouts/DashboardLayout_gdd.spec.js @@ -140,14 +140,6 @@ describe('DashboardLayoutGdd', () => { }) }) - describe('update balance', () => { - it('updates the amount correctelly', async () => { - await wrapper.findComponent({ ref: 'router-view' }).vm.$emit('update-balance', 5) - await flushPromises() - expect(wrapper.vm.balance).toBe(-5) - }) - }) - describe('update transactions', () => { beforeEach(async () => { apolloMock.mockResolvedValue({ diff --git a/frontend/src/layouts/DashboardLayout_gdd.vue b/frontend/src/layouts/DashboardLayout_gdd.vue index 9c7cf9c0c..a2a76d88c 100755 --- a/frontend/src/layouts/DashboardLayout_gdd.vue +++ b/frontend/src/layouts/DashboardLayout_gdd.vue @@ -27,7 +27,6 @@ :transactionLinkCount="transactionLinkCount" :pending="pending" :decayStartBlock="decayStartBlock" - @update-balance="updateBalance" @update-transactions="updateTransactions" > @@ -112,9 +111,6 @@ export default { // what to do when loading balance fails? }) }, - updateBalance(ammount) { - this.balance -= ammount - }, admin() { window.location.assign(CONFIG.ADMIN_AUTH_URL.replace('{token}', this.$store.state.token)) this.$store.dispatch('logout') // logout without redirect From 8c8d06d87c5c89f571ef65450ac54c6545b6fb9a Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 22 Mar 2022 17:56:34 +0100 Subject: [PATCH 27/39] bind the transaction data to the transaction form to allow data restoration after canceling transaction confirmation, use always update transaction to update balance --- frontend/src/pages/Send.vue | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/frontend/src/pages/Send.vue b/frontend/src/pages/Send.vue index bce9a6069..38f232fda 100644 --- a/frontend/src/pages/Send.vue +++ b/frontend/src/pages/Send.vue @@ -3,7 +3,11 @@