From 489743b6d6750b8e23fe063f39a863fcf7a4975b Mon Sep 17 00:00:00 2001 From: ogerly Date: Fri, 5 Nov 2021 13:50:10 +0100 Subject: [PATCH 001/101] add navbar and routes --- admin/src/App.vue | 9 ++++++++- admin/src/components/NavBar.vue | 19 +++++++++++++++++++ admin/src/components/UserTable.vue | 24 ++++++++++++++++++++++++ admin/src/main.js | 2 ++ admin/src/router/routes.js | 29 ++++++++++++++++++++++++++--- admin/src/views/Creation.vue | 9 +++++++++ admin/src/views/Overview.vue | 21 +++++++++++++++++++++ admin/src/views/UserSearch.vue | 9 +++++++++ 8 files changed, 118 insertions(+), 4 deletions(-) create mode 100644 admin/src/components/NavBar.vue create mode 100644 admin/src/components/UserTable.vue create mode 100644 admin/src/views/Creation.vue create mode 100644 admin/src/views/Overview.vue create mode 100644 admin/src/views/UserSearch.vue diff --git a/admin/src/App.vue b/admin/src/App.vue index 9267cc82b..1a15d5d7c 100644 --- a/admin/src/App.vue +++ b/admin/src/App.vue @@ -1,9 +1,16 @@ diff --git a/admin/src/components/NavBar.vue b/admin/src/components/NavBar.vue new file mode 100644 index 000000000..42bc2161c --- /dev/null +++ b/admin/src/components/NavBar.vue @@ -0,0 +1,19 @@ + diff --git a/admin/src/components/UserTable.vue b/admin/src/components/UserTable.vue new file mode 100644 index 000000000..55e9b5b3c --- /dev/null +++ b/admin/src/components/UserTable.vue @@ -0,0 +1,24 @@ + + + diff --git a/admin/src/main.js b/admin/src/main.js index 61f65129e..089e02352 100644 --- a/admin/src/main.js +++ b/admin/src/main.js @@ -14,6 +14,8 @@ import VueApollo from 'vue-apollo' import CONFIG from './config' import { BootstrapVue } from 'bootstrap-vue' +import 'bootstrap-vue/dist/bootstrap-vue.css' +import 'bootstrap/dist/css/bootstrap.css' const httpLink = new HttpLink({ uri: CONFIG.GRAPHQL_URI }) diff --git a/admin/src/router/routes.js b/admin/src/router/routes.js index 40f3ce325..71500eece 100644 --- a/admin/src/router/routes.js +++ b/admin/src/router/routes.js @@ -1,13 +1,36 @@ -import NotFound from '@/components/NotFoundPage.vue' - const routes = [ { path: '/', + component: () => import('@/views/Overview.vue'), meta: { requiresAuth: true, }, }, - { path: '*', component: NotFound }, + { + path: '/overview', + component: () => import('@/views/Overview.vue'), + meta: { + requiresAuth: true, + }, + }, + { + path: '/user', + component: () => import('@/views/UserSearch.vue'), + meta: { + requiresAuth: true, + }, + }, + { + path: '/creation', + component: () => import('@/views/Creation.vue'), + meta: { + requiresAuth: true, + }, + }, + { + path: '*', + component: () => import('@/components/NotFoundPage.vue'), + }, ] export default routes diff --git a/admin/src/views/Creation.vue b/admin/src/views/Creation.vue new file mode 100644 index 000000000..794218163 --- /dev/null +++ b/admin/src/views/Creation.vue @@ -0,0 +1,9 @@ + diff --git a/admin/src/views/Overview.vue b/admin/src/views/Overview.vue new file mode 100644 index 000000000..0cb8a106d --- /dev/null +++ b/admin/src/views/Overview.vue @@ -0,0 +1,21 @@ + + diff --git a/admin/src/views/UserSearch.vue b/admin/src/views/UserSearch.vue new file mode 100644 index 000000000..be6ce38c9 --- /dev/null +++ b/admin/src/views/UserSearch.vue @@ -0,0 +1,9 @@ + From 4cb7abdc9bfca2d601a66b417ef301c531d4cb59 Mon Sep 17 00:00:00 2001 From: ogerly Date: Thu, 11 Nov 2021 06:51:21 +0100 Subject: [PATCH 002/101] add momentjs, add component CreateFormular.vue formular for creating gdd --- admin/package.json | 2 + admin/src/components/CreateFormular.vue | 66 +++++++++++++++++++++ admin/src/components/UserTable.vue | 78 ++++++++++++++++++++++--- admin/src/locales/en.json | 17 +++++- admin/src/main.js | 4 ++ admin/src/views/Overview.vue | 7 ++- admin/yarn.lock | 12 ++++ 7 files changed, 177 insertions(+), 9 deletions(-) create mode 100644 admin/src/components/CreateFormular.vue diff --git a/admin/package.json b/admin/package.json index 2b4e33c91..5dff9145e 100644 --- a/admin/package.json +++ b/admin/package.json @@ -33,11 +33,13 @@ "dotenv-webpack": "^7.0.3", "graphql": "^15.6.1", "jest": "26.6.3", + "moment": "^2.29.1", "stats-webpack-plugin": "^0.7.0", "vue": "^2.6.11", "vue-apollo": "^3.0.8", "vue-i18n": "^8.26.5", "vue-jest": "^3.0.7", + "vue-moment": "^4.1.0", "vue-router": "^3.5.3", "vuex": "^3.6.2" }, diff --git a/admin/src/components/CreateFormular.vue b/admin/src/components/CreateFormular.vue new file mode 100644 index 000000000..5dd07a4c1 --- /dev/null +++ b/admin/src/components/CreateFormular.vue @@ -0,0 +1,66 @@ + + diff --git a/admin/src/components/UserTable.vue b/admin/src/components/UserTable.vue index 55e9b5b3c..2e92c9a7f 100644 --- a/admin/src/components/UserTable.vue +++ b/admin/src/components/UserTable.vue @@ -1,22 +1,86 @@ diff --git a/admin/src/components/CreationFormular.spec.js b/admin/src/components/CreationFormular.spec.js new file mode 100644 index 000000000..c2098768c --- /dev/null +++ b/admin/src/components/CreationFormular.spec.js @@ -0,0 +1,22 @@ +import { mount } from '@vue/test-utils' +import CreationFormular from './CreationFormular.vue' + +const localVue = global.localVue + +describe('CreationFormular', () => { + let wrapper + + const Wrapper = () => { + return mount(CreationFormular, { localVue }) + } + + describe('mount', () => { + beforeEach(() => { + wrapper = Wrapper() + }) + + it('have a DIV element with the class.componente-creation-formular', () => { + expect(wrapper.find('.componente-creation-formular').exists()).toBeTruthy() + }) + }) +}) diff --git a/admin/src/components/CreationFormular.vue b/admin/src/components/CreationFormular.vue new file mode 100644 index 000000000..dbc40c13c --- /dev/null +++ b/admin/src/components/CreationFormular.vue @@ -0,0 +1,114 @@ + + diff --git a/admin/src/components/NavBar.spec.js b/admin/src/components/NavBar.spec.js new file mode 100644 index 000000000..ab9be26e5 --- /dev/null +++ b/admin/src/components/NavBar.spec.js @@ -0,0 +1,22 @@ +import { mount } from '@vue/test-utils' +import NavBar from './NavBar.vue' + +const localVue = global.localVue + +describe('NavBar', () => { + let wrapper + + const Wrapper = () => { + return mount(NavBar, { localVue }) + } + + describe('mount', () => { + beforeEach(() => { + wrapper = Wrapper() + }) + + it('have a DIV element with the class.componente-nabvar', () => { + expect(wrapper.find('.componente-nabvar').exists()).toBeTruthy() + }) + }) +}) diff --git a/admin/src/components/NavBar.vue b/admin/src/components/NavBar.vue index 42bc2161c..1efdffc04 100644 --- a/admin/src/components/NavBar.vue +++ b/admin/src/components/NavBar.vue @@ -1,19 +1,18 @@ diff --git a/admin/src/components/UserTable.spec.js b/admin/src/components/UserTable.spec.js new file mode 100644 index 000000000..935bd177c --- /dev/null +++ b/admin/src/components/UserTable.spec.js @@ -0,0 +1,22 @@ +import { mount } from '@vue/test-utils' +import UserTable from './UserTable.vue' + +const localVue = global.localVue + +describe('UserTable', () => { + let wrapper + + const Wrapper = () => { + return mount(UserTable, { localVue }) + } + + describe('mount', () => { + beforeEach(() => { + wrapper = Wrapper() + }) + + it('have a DIV element with the class.componente-user-table', () => { + expect(wrapper.find('.componente-user-table').exists()).toBeTruthy() + }) + }) +}) diff --git a/admin/src/components/UserTable.vue b/admin/src/components/UserTable.vue index 2e92c9a7f..a376e0f67 100644 --- a/admin/src/components/UserTable.vue +++ b/admin/src/components/UserTable.vue @@ -1,24 +1,8 @@ diff --git a/admin/src/locales/en.json b/admin/src/locales/en.json index ac7159ece..0967ef424 100644 --- a/admin/src/locales/en.json +++ b/admin/src/locales/en.json @@ -1,16 +1 @@ -{ - "monthNames": { - "January": "", - "February": "", - "March": "", - "April": "", - "May": "", - "June": "", - "July": "", - "August": "", - "September": "", - "October": "", - "November": "", - "December": "" - } -} +{} diff --git a/admin/src/main.js b/admin/src/main.js index 197b82888..b3925c9fe 100644 --- a/admin/src/main.js +++ b/admin/src/main.js @@ -13,9 +13,9 @@ import VueApollo from 'vue-apollo' import CONFIG from './config' -import { BootstrapVue } from 'bootstrap-vue' -import 'bootstrap-vue/dist/bootstrap-vue.css' +import { BootstrapVue, IconsPlugin } from 'bootstrap-vue' import 'bootstrap/dist/css/bootstrap.css' +import 'bootstrap-vue/dist/bootstrap-vue.css' import moment from 'vue-moment' @@ -52,6 +52,8 @@ const apolloProvider = new VueApollo({ }) Vue.use(BootstrapVue) +Vue.use(IconsPlugin) + Vue.use(moment) addNavigationGuards(router, store) diff --git a/admin/src/main.test.js b/admin/src/main.test.js index 27c8898ab..b2d7fadc8 100644 --- a/admin/src/main.test.js +++ b/admin/src/main.test.js @@ -5,10 +5,13 @@ import CONFIG from './config' import Vue from 'vue' import Vuex from 'vuex' import VueI18n from 'vue-i18n' +import { BootstrapVue, IconsPlugin } from 'bootstrap-vue' +import moment from 'vue-moment' jest.mock('vue') jest.mock('vuex') jest.mock('vue-i18n') +jest.mock('moment') const storeMock = jest.fn() Vuex.Store = storeMock @@ -25,6 +28,16 @@ jest.mock('apollo-boost', () => { } }) +jest.mock('bootstrap-vue', () => { + return { + __esModule: true, + BootstrapVue: jest.fn(), + IconsPlugin: jest.fn(() => { + return { concat: jest.fn() } + }), + } +}) + describe('main', () => { it('calls the HttpLink', () => { expect(HttpLink).toBeCalledWith({ uri: CONFIG.GRAPHQL_URI }) @@ -50,6 +63,18 @@ describe('main', () => { expect(VueI18n).toBeCalled() }) + it('calls BootstrapVue', () => { + expect(BootstrapVue).toBeCalled() + }) + + it('calls IconsPlugin', () => { + expect(IconsPlugin).toBeCalled() + }) + + it('calls Moment', () => { + expect(moment).toBeCalled() + }) + it.skip('creates a store', () => { expect(storeMock).toBeCalled() }) diff --git a/admin/src/router/routes.js b/admin/src/router/routes.js index 71500eece..a13463e08 100644 --- a/admin/src/router/routes.js +++ b/admin/src/router/routes.js @@ -27,6 +27,13 @@ const routes = [ requiresAuth: true, }, }, + { + path: '/creation-confirm', + component: () => import('@/views/CreationConfirm.vue'), + meta: { + requiresAuth: true, + }, + }, { path: '*', component: () => import('@/components/NotFoundPage.vue'), diff --git a/admin/src/views/Creation.vue b/admin/src/views/Creation.vue index 794218163..02a060f74 100644 --- a/admin/src/views/Creation.vue +++ b/admin/src/views/Creation.vue @@ -1,9 +1,178 @@ + diff --git a/admin/src/views/CreationConfirm.vue b/admin/src/views/CreationConfirm.vue new file mode 100644 index 000000000..2d416e08f --- /dev/null +++ b/admin/src/views/CreationConfirm.vue @@ -0,0 +1,108 @@ + + diff --git a/admin/src/views/Overview.vue b/admin/src/views/Overview.vue index 55eca4aea..d529701e2 100644 --- a/admin/src/views/Overview.vue +++ b/admin/src/views/Overview.vue @@ -1,26 +1,71 @@ diff --git a/admin/src/views/UserSearch.vue b/admin/src/views/UserSearch.vue index be6ce38c9..c7ed5ffef 100644 --- a/admin/src/views/UserSearch.vue +++ b/admin/src/views/UserSearch.vue @@ -1,9 +1,73 @@ + From f362032b388373d372bf71102632fc66e5c1d0b3 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Wed, 17 Nov 2021 16:56:13 +0100 Subject: [PATCH 004/101] add body parser --- backend/package.json | 1 + backend/yarn.lock | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/package.json b/backend/package.json index bc098958f..375046363 100644 --- a/backend/package.json +++ b/backend/package.json @@ -20,6 +20,7 @@ "apollo-server-express": "^2.25.2", "apollo-server-testing": "^2.25.2", "axios": "^0.21.1", + "body-parser": "^1.19.0", "class-validator": "^0.13.1", "cors": "^2.8.5", "dotenv": "^10.0.0", diff --git a/backend/yarn.lock b/backend/yarn.lock index b411bcf60..5b74ba7c3 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -1552,7 +1552,7 @@ binary-extensions@^2.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== -body-parser@1.19.0, body-parser@^1.18.3: +body-parser@1.19.0, body-parser@^1.18.3, body-parser@^1.19.0: version "1.19.0" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== From 33670f1575565f37dcf2f980257dfd1a900ee670 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Wed, 17 Nov 2021 16:56:32 +0100 Subject: [PATCH 005/101] WEBHOOK_ELOPAGE_SECRET --- backend/src/config/index.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index f21082d1d..22e37eeb9 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -56,9 +56,21 @@ const email = { process.env.EMAIL_LINK_VERIFICATION || 'http://localhost/vue/checkEmail/$1', } +const webhook = { + WEBHOOK_ELOPAGE_SECRET: process.env.WEBHOOK_ELOPAGE_SECRET || 'secret', +} + // This is needed by graphql-directive-auth process.env.APP_SECRET = server.JWT_SECRET -const CONFIG = { ...server, ...database, ...klicktipp, ...community, ...email, ...loginServer } +const CONFIG = { + ...server, + ...database, + ...klicktipp, + ...community, + ...email, + ...loginServer, + ...webhook, +} export default CONFIG From e68f22ade02861cb5fdb83921de910374e6cec8a Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Wed, 17 Nov 2021 16:57:04 +0100 Subject: [PATCH 006/101] implement the webhook --- backend/src/server/createServer.ts | 10 + backend/src/webhook/elopage.ts | 365 +++++++++++++++++++++++++++++ 2 files changed, 375 insertions(+) create mode 100644 backend/src/webhook/elopage.ts diff --git a/backend/src/server/createServer.ts b/backend/src/server/createServer.ts index 4350483ff..28e0e1ce4 100644 --- a/backend/src/server/createServer.ts +++ b/backend/src/server/createServer.ts @@ -6,6 +6,7 @@ import 'module-alias/register' import { ApolloServer } from 'apollo-server-express' import express from 'express' +import bodyParser from 'body-parser' // database import connection from '../typeorm/connection' @@ -22,6 +23,9 @@ import CONFIG from '../config' // graphql import schema from '../graphql/schema' +// webhooks +import { elopageWebhook } from '../webhook/elopage' + // TODO implement // import queryComplexity, { simpleEstimator, fieldConfigEstimator } from "graphql-query-complexity"; @@ -50,6 +54,12 @@ const createServer = async (context: any = serverContext): Promise => { // cors app.use(cors) + // bodyparser + app.use(bodyParser.json()) + + // Elopage Webhook + app.post('/hook/elopage/' + CONFIG.WEBHOOK_ELOPAGE_SECRET, elopageWebhook) + // Apollo Server const apollo = new ApolloServer({ schema: await schema(), diff --git a/backend/src/webhook/elopage.ts b/backend/src/webhook/elopage.ts new file mode 100644 index 000000000..0db26bf9c --- /dev/null +++ b/backend/src/webhook/elopage.ts @@ -0,0 +1,365 @@ +/* + Elopage Webhook + + Those are all available infos: + HandleElopageRequestTask: order_id 849951 + + Es gibt 5 elopage request mit dieser order_id + Alle von der gleichen Person, aber unterschiedliche Events: + 2019-12-03: chargeback.successful + 29.10.2019: order.subscription.paused + 2019-12-06: payment.successful + 29.10.2019: order.subscription.paying + 2091-12-07: payment.pending + + + order_id=849951&order_token=y22MJxHr9XzzPiaaH9GU&payment_session_id=849951&payment_session_token=y22MJxHr9XzzPiaaH9GU&action=payment_processed&initiator&payer[email]=theodora.mis%40gmx.ch&payer[first_name]=Theodora&payer[last_name]=Mis&payer[country]=Schweiz&payer[country_code]=CH&payer[city]=St.+Gallen&payer[street]=Vonwilstrasse+23&payer[street_number]&payer[zip]=9000&payer[company]&payer[vat_no]&payer[phone]&gift_receiver&publisher[id]=691&publisher[email]=joytopia%40gmail.com&publisher[first_name]=Bernd&publisher[last_name]=H%C3%BCckst%C3%A4dt&publisher[street]=Pfarrweg+2&publisher[zip]=74653&publisher[city]=K%C3%BCnzelsau&publisher[country]=Deutschland&publisher[phone]=%2B4979405460810&team_members&product_id=43944&product[id]=43944&product[slug]=gold-de&product[name]=Gold-Mitgliedschaft&product[type]=membership&product[price]=40.0&product[affiliate_program_id]=111&upsell&membership[id]=43944&membership[name]=Gold-Mitgliedschaft&membership[membership_product_1]=Werkzeuge+%26+Ressourcen+%28Gold%29&membership[membership_product_1_id]=44982&membership[membership_product_2]=Zertifizierung+zum%2Fr+Gradido-Botschafter%2Fin&membership[membership_product_2_id]=43970&membership[membership_product_3]=Seminar+3+Nat%C3%BCrliche+%C3%96konomie+des+Lebens&membership[membership_product_3_id]=43969&membership[membership_product_4]=Potential-Entfaltungs-Techniken&membership[membership_product_4_id]=43954&membership[membership_product_5]=Seminar+2+Nat%C3%BCrliche+%C3%96konomie+des+Lebens&membership[membership_product_5_id]=43896&membership[membership_product_6]=Kongresspaket%3A+Gesundes+Geld+f%C3%BCr+eine+gesunde+Welt&membership[membership_product_6_id]=14590&membership[membership_product_7]=Deine+Gold-Mitgliedschaft+bei+Gradido&membership[membership_product_7_id]=43951&membership[membership_product_8]=Gradido+E-Book%2C+H%C3%B6rspiel+%22Joytopia%22++%E2%80%93+und+100+Vorteile&membership[membership_product_8_id]=7312&membership[membership_product_9]=Danke%2C+dass+Du+hilfst+Gradido+in+die+Welt+zu+bringen%21&membership[membership_product_9_id]=43744&membership[membership_product_10]=Basis-Informationen+zu+Gradido&membership[membership_product_10_id]=42600&membership[membership_product_11]=Seminar+1+Nat%C3%BCrliche+%C3%96konomie+des+Lebens&membership[membership_product_11_id]=43882&membership[membership_product_12]=Musical+%22Gradido+%E2%80%93+gemeinsam+retten+wir+die+Welt%22&membership[membership_product_12_id]=43886&membership[membership_product_13]=Premium+Community+%26+Markt&membership[membership_product_13_id]=43885&membership[membership_product_14]=Gradido+Buch+ungek%C3%BCrzte+Version+%26+%C3%9Cbersetzungen&membership[membership_product_14_id]=43887&membership[membership_product_15]=Online-Konferenzen&membership[membership_product_15_id]=43919&membership[membership_product_16]=Gradido+H%C3%B6rbuch&membership[membership_product_16_id]=43920&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&pricing_plan[name]=Monatlich&add_id_1&add_id_2&campaign_id¤cy=EUR&coupon_code&recurring=yes&recurring_form=subscription&payment_state=payment_paused&payment_method=sepa&opt_ins&payments_schedule[][rate]=1&payments_schedule[][state]=debt&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.10.2019&payments_schedule[][rate]=2&payments_schedule[][state]=pending&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.11.2019&payments_schedule[][rate]=3&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.12.2019&payments_schedule[][rate]=4&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.01.2020&payments_schedule[][rate]=5&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.02.2020&payments_schedule[][rate]=6&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.03.2020&payments_schedule[][rate]=7&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.04.2020&payments_schedule[][rate]=8&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.05.2020&payments_schedule[][rate]=9&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.06.2020&payments_schedule[][rate]=10&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.07.2020&payments_schedule[][rate]=11&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.08.2020&payments_schedule[][rate]=12&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.09.2020&payments_schedule[][rate]=13&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.10.2020&payments_schedule[][rate]=14&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=0.0&payments_schedule[][date]=29.11.2020&payments_count=0&payments_count_expected&with_test_period=false&with_custom_start=false&created=29.10.2019+13%3A17&id=58268076&invoice_number&revenue=-40.0&amount=-23.72&fee=-16.28&vat_rate=0.0&vat_amount=0.0&state=successful&refunded_transfer_id=52876337&invoice_link&credit_memo_link=http%3A%2F%2Felopage.com%2Fcommon%2Fcredit_memos%2F12410%3Ftoken%3D6dyBsddt6gsJpX8Fq-M2&success_link=http%3A%2F%2Felopage.com%2Fs%2Fgradido%2Fpayment%2Fy22MJxHr9XzzPiaaH9GU&error_msg&created_date=2019-12-03T22%3A15Z&success_date=2019-12-03T22%3A15Z&success_date_short=2019-12-03&created_date_utc=03.12.2019+22%3A15&success_date_utc=03.12.2019+22%3A15&team_member_commissions&event=chargeback.successful + order_id=849951&order_token=y22MJxHr9XzzPiaaH9GU&payment_session_id=849951&payment_session_token=y22MJxHr9XzzPiaaH9GU&action=subscription_state_changed&initiator&payer[email]=theodora.mis%40gmx.ch&payer[first_name]=Theodora&payer[last_name]=Mis&payer[country]=Schweiz&payer[country_code]=CH&payer[city]=St.+Gallen&payer[street]=Vonwilstrasse+23&payer[street_number]&payer[zip]=9000&payer[company]&payer[vat_no]&payer[phone]&gift_receiver&publisher[id]=691&publisher[email]=joytopia%40gmail.com&publisher[first_name]=Bernd&publisher[last_name]=H%C3%BCckst%C3%A4dt&publisher[street]=Pfarrweg+2&publisher[zip]=74653&publisher[city]=K%C3%BCnzelsau&publisher[country]=Deutschland&publisher[phone]=%2B4979405460810&team_members&product_id=43944&product[id]=43944&product[slug]=gold-de&product[name]=Gold-Mitgliedschaft&product[type]=membership&product[price]=40.0&product[affiliate_program_id]=111&upsell&membership[id]=43944&membership[name]=Gold-Mitgliedschaft&membership[membership_product_1]=Werkzeuge+%26+Ressourcen+%28Gold%29&membership[membership_product_1_id]=44982&membership[membership_product_2]=Zertifizierung+zum%2Fr+Gradido-Botschafter%2Fin&membership[membership_product_2_id]=43970&membership[membership_product_3]=Seminar+3+Nat%C3%BCrliche+%C3%96konomie+des+Lebens&membership[membership_product_3_id]=43969&membership[membership_product_4]=Potential-Entfaltungs-Techniken&membership[membership_product_4_id]=43954&membership[membership_product_5]=Seminar+2+Nat%C3%BCrliche+%C3%96konomie+des+Lebens&membership[membership_product_5_id]=43896&membership[membership_product_6]=Kongresspaket%3A+Gesundes+Geld+f%C3%BCr+eine+gesunde+Welt&membership[membership_product_6_id]=14590&membership[membership_product_7]=Deine+Gold-Mitgliedschaft+bei+Gradido&membership[membership_product_7_id]=43951&membership[membership_product_8]=Gradido+E-Book%2C+H%C3%B6rspiel+%22Joytopia%22++%E2%80%93+und+100+Vorteile&membership[membership_product_8_id]=7312&membership[membership_product_9]=Danke%2C+dass+Du+hilfst+Gradido+in+die+Welt+zu+bringen%21&membership[membership_product_9_id]=43744&membership[membership_product_10]=Basis-Informationen+zu+Gradido&membership[membership_product_10_id]=42600&membership[membership_product_11]=Seminar+1+Nat%C3%BCrliche+%C3%96konomie+des+Lebens&membership[membership_product_11_id]=43882&membership[membership_product_12]=Musical+%22Gradido+%E2%80%93+gemeinsam+retten+wir+die+Welt%22&membership[membership_product_12_id]=43886&membership[membership_product_13]=Premium+Community+%26+Markt&membership[membership_product_13_id]=43885&membership[membership_product_14]=Gradido+Buch+ungek%C3%BCrzte+Version+%26+%C3%9Cbersetzungen&membership[membership_product_14_id]=43887&membership[membership_product_15]=Online-Konferenzen&membership[membership_product_15_id]=43919&membership[membership_product_16]=Gradido+H%C3%B6rbuch&membership[membership_product_16_id]=43920&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&pricing_plan[name]=Monatlich&add_id_1&add_id_2&campaign_id¤cy=EUR&coupon_code&recurring=yes&recurring_form=subscription&payment_state=payment_paused&payment_method=sepa&opt_ins&payments_schedule[][rate]=1&payments_schedule[][state]=debt&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.10.2019&payments_schedule[][rate]=2&payments_schedule[][state]=pending&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.11.2019&payments_schedule[][rate]=3&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.12.2019&payments_schedule[][rate]=4&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.01.2020&payments_schedule[][rate]=5&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.02.2020&payments_schedule[][rate]=6&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.03.2020&payments_schedule[][rate]=7&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.04.2020&payments_schedule[][rate]=8&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.05.2020&payments_schedule[][rate]=9&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.06.2020&payments_schedule[][rate]=10&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.07.2020&payments_schedule[][rate]=11&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.08.2020&payments_schedule[][rate]=12&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.09.2020&payments_schedule[][rate]=13&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.10.2020&payments_schedule[][rate]=14&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=0.0&payments_schedule[][date]=29.11.2020&payments_count=0&payments_count_expected&with_test_period=false&with_custom_start=false&created=29.10.2019+13%3A17&event=order.subscription.paused + order_id=849951&order_token=y22MJxHr9XzzPiaaH9GU&payment_session_id=849951&payment_session_token=y22MJxHr9XzzPiaaH9GU&action=payment_processed&initiator&payer[email]=theodora.mis%40gmx.ch&payer[first_name]=Theodora&payer[last_name]=Mis&payer[country]=Schweiz&payer[country_code]=CH&payer[city]=St.+Gallen&payer[street]=Vonwilstrasse+23&payer[street_number]&payer[zip]=9000&payer[company]&payer[vat_no]&payer[phone]&gift_receiver&publisher[id]=691&publisher[email]=joytopia%40gmail.com&publisher[first_name]=Bernd&publisher[last_name]=H%C3%BCckst%C3%A4dt&publisher[street]=Pfarrweg+2&publisher[zip]=74653&publisher[city]=K%C3%BCnzelsau&publisher[country]=Deutschland&publisher[phone]=%2B4979405460810&team_members&product_id=43944&product[id]=43944&product[slug]=gold-de&product[name]=Gold-Mitgliedschaft&product[type]=membership&product[price]=40.0&product[affiliate_program_id]=111&upsell&membership[id]=43944&membership[name]=Gold-Mitgliedschaft&membership[membership_product_1]=Werkzeuge+%26+Ressourcen+%28Gold%29&membership[membership_product_1_id]=44982&membership[membership_product_2]=Zertifizierung+zum%2Fr+Gradido-Botschafter%2Fin&membership[membership_product_2_id]=43970&membership[membership_product_3]=Seminar+3+Nat%C3%BCrliche+%C3%96konomie+des+Lebens&membership[membership_product_3_id]=43969&membership[membership_product_4]=Potential-Entfaltungs-Techniken&membership[membership_product_4_id]=43954&membership[membership_product_5]=Seminar+2+Nat%C3%BCrliche+%C3%96konomie+des+Lebens&membership[membership_product_5_id]=43896&membership[membership_product_6]=Kongresspaket%3A+Gesundes+Geld+f%C3%BCr+eine+gesunde+Welt&membership[membership_product_6_id]=14590&membership[membership_product_7]=Deine+Gold-Mitgliedschaft+bei+Gradido&membership[membership_product_7_id]=43951&membership[membership_product_8]=Gradido+E-Book%2C+H%C3%B6rspiel+%22Joytopia%22++%E2%80%93+und+100+Vorteile&membership[membership_product_8_id]=7312&membership[membership_product_9]=Danke%2C+dass+Du+hilfst+Gradido+in+die+Welt+zu+bringen%21&membership[membership_product_9_id]=43744&membership[membership_product_10]=Basis-Informationen+zu+Gradido&membership[membership_product_10_id]=42600&membership[membership_product_11]=Seminar+1+Nat%C3%BCrliche+%C3%96konomie+des+Lebens&membership[membership_product_11_id]=43882&membership[membership_product_12]=Musical+%22Gradido+%E2%80%93+gemeinsam+retten+wir+die+Welt%22&membership[membership_product_12_id]=43886&membership[membership_product_13]=Premium+Community+%26+Markt&membership[membership_product_13_id]=43885&membership[membership_product_14]=Gradido+Buch+ungek%C3%BCrzte+Version+%26+%C3%9Cbersetzungen&membership[membership_product_14_id]=43887&membership[membership_product_15]=Online-Konferenzen&membership[membership_product_15_id]=43919&membership[membership_product_16]=Gradido+H%C3%B6rbuch&membership[membership_product_16_id]=43920&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&pricing_plan[name]=Monatlich&add_id_1&add_id_2&campaign_id¤cy=EUR&coupon_code&recurring=yes&recurring_form=subscription&payment_state=active_subscription&payment_method=sepa&opt_ins&payments_schedule[][rate]=1&payments_schedule[][state]=debt&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.10.2019&payments_schedule[][rate]=2&payments_schedule[][state]=paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.11.2019&payments_schedule[][rate]=3&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.12.2019&payments_schedule[][rate]=4&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.01.2020&payments_schedule[][rate]=5&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.02.2020&payments_schedule[][rate]=6&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.03.2020&payments_schedule[][rate]=7&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.04.2020&payments_schedule[][rate]=8&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.05.2020&payments_schedule[][rate]=9&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.06.2020&payments_schedule[][rate]=10&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.07.2020&payments_schedule[][rate]=11&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.08.2020&payments_schedule[][rate]=12&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.09.2020&payments_schedule[][rate]=13&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.10.2020&payments_schedule[][rate]=14&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=0.0&payments_schedule[][date]=29.11.2020&payments_schedule[][rate]=15&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=0.0&payments_schedule[][date]=29.12.2020&payments_count=1&payments_count_expected&with_test_period=false&with_custom_start=false&created=29.10.2019+13%3A17&id=57354055&invoice_number=111-1839-000000677&revenue=40.0&amount=23.72&fee=16.28&vat_rate=0.0&vat_amount=0.0&state=successful&refunded_transfer_id&invoice_link=http%3A%2F%2Felopage.com%2Fcommon%2Finvoices%2F450856%2Fdownload.pdf%3Ftoken%3DGR7bG7zcbgCzNJEPLDss&credit_memo_link&success_link=http%3A%2F%2Felopage.com%2Fs%2Fgradido%2Fpayment%2Fy22MJxHr9XzzPiaaH9GU&error_msg&created_date=2019-11-29T07%3A19Z&success_date=2019-12-06T13%3A12Z&success_date_short=2019-12-06&created_date_utc=29.11.2019+07%3A19&success_date_utc=06.12.2019+13%3A12&team_member_commissions&event=payment.successful + order_id=849951&order_token=y22MJxHr9XzzPiaaH9GU&payment_session_id=849951&payment_session_token=y22MJxHr9XzzPiaaH9GU&action=subscription_state_changed&initiator&payer[email]=theodora.mis%40gmx.ch&payer[first_name]=Theodora&payer[last_name]=Mis&payer[country]=Schweiz&payer[country_code]=CH&payer[city]=St.+Gallen&payer[street]=Vonwilstrasse+23&payer[street_number]&payer[zip]=9000&payer[company]&payer[vat_no]&payer[phone]&gift_receiver&publisher[id]=691&publisher[email]=joytopia%40gmail.com&publisher[first_name]=Bernd&publisher[last_name]=H%C3%BCckst%C3%A4dt&publisher[street]=Pfarrweg+2&publisher[zip]=74653&publisher[city]=K%C3%BCnzelsau&publisher[country]=Deutschland&publisher[phone]=%2B4979405460810&team_members&product_id=43944&product[id]=43944&product[slug]=gold-de&product[name]=Gold-Mitgliedschaft&product[type]=membership&product[price]=40.0&product[affiliate_program_id]=111&upsell&membership[id]=43944&membership[name]=Gold-Mitgliedschaft&membership[membership_product_1]=Werkzeuge+%26+Ressourcen+%28Gold%29&membership[membership_product_1_id]=44982&membership[membership_product_2]=Zertifizierung+zum%2Fr+Gradido-Botschafter%2Fin&membership[membership_product_2_id]=43970&membership[membership_product_3]=Seminar+3+Nat%C3%BCrliche+%C3%96konomie+des+Lebens&membership[membership_product_3_id]=43969&membership[membership_product_4]=Potential-Entfaltungs-Techniken&membership[membership_product_4_id]=43954&membership[membership_product_5]=Seminar+2+Nat%C3%BCrliche+%C3%96konomie+des+Lebens&membership[membership_product_5_id]=43896&membership[membership_product_6]=Kongresspaket%3A+Gesundes+Geld+f%C3%BCr+eine+gesunde+Welt&membership[membership_product_6_id]=14590&membership[membership_product_7]=Deine+Gold-Mitgliedschaft+bei+Gradido&membership[membership_product_7_id]=43951&membership[membership_product_8]=Gradido+E-Book%2C+H%C3%B6rspiel+%22Joytopia%22++%E2%80%93+und+100+Vorteile&membership[membership_product_8_id]=7312&membership[membership_product_9]=Danke%2C+dass+Du+hilfst+Gradido+in+die+Welt+zu+bringen%21&membership[membership_product_9_id]=43744&membership[membership_product_10]=Basis-Informationen+zu+Gradido&membership[membership_product_10_id]=42600&membership[membership_product_11]=Seminar+1+Nat%C3%BCrliche+%C3%96konomie+des+Lebens&membership[membership_product_11_id]=43882&membership[membership_product_12]=Musical+%22Gradido+%E2%80%93+gemeinsam+retten+wir+die+Welt%22&membership[membership_product_12_id]=43886&membership[membership_product_13]=Premium+Community+%26+Markt&membership[membership_product_13_id]=43885&membership[membership_product_14]=Gradido+Buch+ungek%C3%BCrzte+Version+%26+%C3%9Cbersetzungen&membership[membership_product_14_id]=43887&membership[membership_product_15]=Online-Konferenzen&membership[membership_product_15_id]=43919&membership[membership_product_16]=Gradido+H%C3%B6rbuch&membership[membership_product_16_id]=43920&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&pricing_plan[name]=Monatlich&add_id_1&add_id_2&campaign_id¤cy=EUR&coupon_code&recurring=yes&recurring_form=subscription&payment_state=active_subscription&payment_method=sepa&opt_ins&payments_schedule[][rate]=1&payments_schedule[][state]=debt&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.10.2019&payments_schedule[][rate]=2&payments_schedule[][state]=paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.11.2019&payments_schedule[][rate]=3&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.12.2019&payments_schedule[][rate]=4&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.01.2020&payments_schedule[][rate]=5&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.02.2020&payments_schedule[][rate]=6&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.03.2020&payments_schedule[][rate]=7&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.04.2020&payments_schedule[][rate]=8&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.05.2020&payments_schedule[][rate]=9&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.06.2020&payments_schedule[][rate]=10&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.07.2020&payments_schedule[][rate]=11&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.08.2020&payments_schedule[][rate]=12&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.09.2020&payments_schedule[][rate]=13&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.10.2020&payments_schedule[][rate]=14&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=0.0&payments_schedule[][date]=29.11.2020&payments_schedule[][rate]=15&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=0.0&payments_schedule[][date]=29.12.2020&payments_count=1&payments_count_expected&with_test_period=false&with_custom_start=false&created=29.10.2019+13%3A17&event=order.subscription.paying + order_id=849951&order_token=y22MJxHr9XzzPiaaH9GU&payment_session_id=849951&payment_session_token=y22MJxHr9XzzPiaaH9GU&action=payment_processed&initiator&payer[email]=theodora.mis%40gmx.ch&payer[first_name]=Theodora&payer[last_name]=Mis&payer[country]=Schweiz&payer[country_code]=CH&payer[city]=St.+Gallen&payer[street]=Vonwilstrasse+23&payer[street_number]&payer[zip]=9000&payer[company]&payer[vat_no]&payer[phone]&gift_receiver&publisher[id]=691&publisher[email]=joytopia%40gmail.com&publisher[first_name]=Bernd&publisher[last_name]=H%C3%BCckst%C3%A4dt&publisher[street]=Pfarrweg+2&publisher[zip]=74653&publisher[city]=K%C3%BCnzelsau&publisher[country]=Deutschland&publisher[phone]=%2B4979405460810&team_members&product_id=43944&product[id]=43944&product[slug]=gold-de&product[name]=Gold-Mitgliedschaft&product[type]=membership&product[price]=40.0&product[affiliate_program_id]=111&upsell&membership[id]=43944&membership[name]=Gold-Mitgliedschaft&membership[membership_product_1]=Werkzeuge+%26+Ressourcen+%28Gold%29&membership[membership_product_1_id]=44982&membership[membership_product_2]=Zertifizierung+zum%2Fr+Gradido-Botschafter%2Fin&membership[membership_product_2_id]=43970&membership[membership_product_3]=Seminar+3+Nat%C3%BCrliche+%C3%96konomie+des+Lebens&membership[membership_product_3_id]=43969&membership[membership_product_4]=Potential-Entfaltungs-Techniken&membership[membership_product_4_id]=43954&membership[membership_product_5]=Seminar+2+Nat%C3%BCrliche+%C3%96konomie+des+Lebens&membership[membership_product_5_id]=43896&membership[membership_product_6]=Kongresspaket%3A+Gesundes+Geld+f%C3%BCr+eine+gesunde+Welt&membership[membership_product_6_id]=14590&membership[membership_product_7]=Deine+Gold-Mitgliedschaft+bei+Gradido&membership[membership_product_7_id]=43951&membership[membership_product_8]=Gradido+E-Book%2C+H%C3%B6rspiel+%22Joytopia%22++%E2%80%93+und+100+Vorteile&membership[membership_product_8_id]=7312&membership[membership_product_9]=Danke%2C+dass+Du+hilfst+Gradido+in+die+Welt+zu+bringen%21&membership[membership_product_9_id]=43744&membership[membership_product_10]=Basis-Informationen+zu+Gradido&membership[membership_product_10_id]=42600&membership[membership_product_11]=Seminar+1+Nat%C3%BCrliche+%C3%96konomie+des+Lebens&membership[membership_product_11_id]=43882&membership[membership_product_12]=Musical+%22Gradido+%E2%80%93+gemeinsam+retten+wir+die+Welt%22&membership[membership_product_12_id]=43886&membership[membership_product_13]=Premium+Community+%26+Markt&membership[membership_product_13_id]=43885&membership[membership_product_14]=Gradido+Buch+ungek%C3%BCrzte+Version+%26+%C3%9Cbersetzungen&membership[membership_product_14_id]=43887&membership[membership_product_15]=Online-Konferenzen&membership[membership_product_15_id]=43919&membership[membership_product_16]=Gradido+H%C3%B6rbuch&membership[membership_product_16_id]=43920&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&events[]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&tickets[][codes]&tickets[][ticket_attendees]&pricing_plan[name]=Monatlich&add_id_1&add_id_2&campaign_id¤cy=EUR&coupon_code&recurring=yes&recurring_form=subscription&payment_state=active_subscription&payment_method=sepa&opt_ins&payments_schedule[][rate]=1&payments_schedule[][state]=pending&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.10.2019&payments_schedule[][rate]=2&payments_schedule[][state]=paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.11.2019&payments_schedule[][rate]=3&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.12.2019&payments_schedule[][rate]=4&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.01.2020&payments_schedule[][rate]=5&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.02.2020&payments_schedule[][rate]=6&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.03.2020&payments_schedule[][rate]=7&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.04.2020&payments_schedule[][rate]=8&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.05.2020&payments_schedule[][rate]=9&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.06.2020&payments_schedule[][rate]=10&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.07.2020&payments_schedule[][rate]=11&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.08.2020&payments_schedule[][rate]=12&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.09.2020&payments_schedule[][rate]=13&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=40.0&payments_schedule[][date]=29.10.2020&payments_schedule[][rate]=14&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=0.0&payments_schedule[][date]=29.11.2020&payments_schedule[][rate]=15&payments_schedule[][state]=to_be_paid&payments_schedule[][amount]=0.0&payments_schedule[][date]=29.12.2020&payments_count=1&payments_count_expected&with_test_period=false&with_custom_start=false&created=29.10.2019+13%3A17&id=58838098&invoice_number=111-1839-000000689&revenue=40.0&amount=23.72&fee=16.28&vat_rate=0.0&vat_amount=0.0&state=pending&refunded_transfer_id&invoice_link=http%3A%2F%2Felopage.com%2Fcommon%2Finvoices%2F470009%2Fdownload.pdf%3Ftoken%3DZ_gogUf8tpKxcHhB-7Cz&credit_memo_link&success_link=http%3A%2F%2Felopage.com%2Fs%2Fgradido%2Fpayment%2Fy22MJxHr9XzzPiaaH9GU&error_msg&created_date=2019-12-07T07%3A19Z&success_date&success_date_short&created_date_utc=07.12.2019+07%3A19&success_date_utc&team_member_commissions&event=payment.pending + + Additional we have the Elopage API docu: + https://apidoc.elopage.com/#webhooks + + I assume that the webhook arrives via POST and transmits a string as shown above +*/ + +import { LoginElopageBuys } from '@entity/LoginElopageBuys' +import { LoginUser } from '@entity/LoginUser' +import { randomBytes } from 'crypto' +import { UserResolver } from '../graphql/resolver/UserResolver' + +export const elopageWebhook = async (req: any, res: any): Promise => { + res.status(200).end() // Responding is important + + const loginElopgaeBuy = new LoginElopageBuys() + let firstName = '' + let lastName = '' + const entries = req.body.split('&') + entries.map((entry: string) => { + const keyVal = entry.split('=') + if (keyVal.length !== 2) { + throw new Error(`Error parsing entry '${entry}'`) + } + const key = keyVal[0] + const val = decodeURIComponent(keyVal[1]).replace('+', ' ').trim() + switch (key) { + case 'product[affiliate_program_id]': + loginElopgaeBuy.affiliateProgramId = parseInt(val) + break + case 'publisher[id]': + loginElopgaeBuy.publisherId = parseInt(val) + break + case 'order_id': + loginElopgaeBuy.orderId = parseInt(val) + break + case 'product_id': + loginElopgaeBuy.productId = parseInt(val) + break + case 'product[price]': + // TODO: static_cast(round(stof(temp) * 100.0f)); + loginElopgaeBuy.productPrice = parseFloat(val) + break + case 'payer[email]': + loginElopgaeBuy.payerEmail = val + break + case 'publisher[email]': + loginElopgaeBuy.publisherEmail = val + break + case 'payment_state': + loginElopgaeBuy.payed = val === 'paid' + break + case 'success_date': + loginElopgaeBuy.successDate = new Date(val) + break + case 'event': + loginElopgaeBuy.event = val + break + case 'membership[id]': + // TODO this was never set on login_server - its unclear if this is the correct value + loginElopgaeBuy.elopageUserId = parseInt(val) + break + case 'payer[first_name]': + firstName = val + break + case 'payer[last_name]': + lastName = val + break + default: + // eslint-disable-next-line no-console + console.log(`Unknown Elopage Value '${entry}'`) + } + return null // we write things into the loginElopgaeBuy object, no return value needed + }) + + // Do not process certain events + if (['lesson.viewed', 'lesson.completed', 'lesson.commented'].includes(loginElopgaeBuy.event)) { + // eslint-disable-next-line no-console + console.log('User viewed, completed or commented - not saving hook') + return + } + + // Save the hook data + await loginElopgaeBuy.save() + + // create user for certain products + /* + Registrierung - Schritt 1 von 3, 36001 + Gradido-Basis, 43741 + Premium-Mitgliedschaft, 43870 + Gold-Mitgliedschaft, 43944 + Business-Mitgliedschaft, 43960 + Förderbeitrag: 49106 + */ + if ([36001, 43741, 43870, 43944, 43960, 49106].includes(loginElopgaeBuy.productId)) { + const email = loginElopgaeBuy.payerEmail + + const VALIDATE_EMAIL = /^[a-zA-Z0-9.!#$%&?*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/ + const VALIDATE_NAME = /^<>&;]{2,}$/ + + // Validate inputs + if ( + email === '' || + !email.match(VALIDATE_EMAIL) || + firstName === '' || + firstName.match(VALIDATE_NAME) || + lastName === '' || + lastName.match(VALIDATE_NAME) + ) { + // eslint-disable-next-line no-console + console.log(`Could not create User ${firstName} ${lastName} with email: ${email}`) + return + } + + // Do we already have such a user? + if ((await LoginUser.count({ email })) !== 0) { + // eslint-disable-next-line no-console + console.log(`Did not create User - already exists with email: ${email}`) + return + } + + // generate a random password - 8 random bytes, the email, special char, capital & small letter, number and another set of 8 random bytes + // TODO: The user will be forced to reset his password - how was this done before? + const password = + randomBytes(8).toString('hex') + email + '!aA1' + randomBytes(8).toString('hex') + + const userResolver = new UserResolver() + userResolver.createUser({ + email, + firstName, + lastName, + password, + language: 'default', + publisherId: loginElopgaeBuy.publisherId, + }) + } +} + +/* +Known unused fields: + + order_token=y22MJxHr9XzzPiaaH9GU + payment_session_id=849951 + payment_session_token=y22MJxHr9XzzPiaaH9GU + action=payment_processed + initiator + payer[first_name]=Theodora + payer[last_name]=Mis + payer[country]=Schweiz + payer[country_code]=CH + payer[city]=St.+Gallen + payer[street]=Vonwilstrasse+23 + payer[street_number] + payer[zip]=9000 + payer[company] + payer[vat_no] + payer[phone] + gift_receiver + publisher[first_name]=Bernd + publisher[last_name]=H%C3%BCckst%C3%A4dt + publisher[street]=Pfarrweg+2 + publisher[zip]=74653 + publisher[city]=K%C3%BCnzelsau + publisher[country]=Deutschland + publisher[phone]=%2B4979405460810 + team_members + product[id]=43944 + product[slug]=gold-de + product[name]=Gold-Mitgliedschaft + product[type]=membership + upsell + membership[name]=Gold-Mitgliedschaft + membership[membership_product_1]=Werkzeuge+%26+Ressourcen+%28Gold%29 + membership[membership_product_1_id]=44982 + membership[membership_product_2]=Zertifizierung+zum%2Fr+Gradido-Botschafter%2Fin + membership[membership_product_2_id]=43970 + membership[membership_product_3]=Seminar+3+Nat%C3%BCrliche+%C3%96konomie+des+Lebens + membership[membership_product_3_id]=43969 + membership[membership_product_4]=Potential-Entfaltungs-Techniken + membership[membership_product_4_id]=43954 + membership[membership_product_5]=Seminar+2+Nat%C3%BCrliche+%C3%96konomie+des+Lebens + membership[membership_product_5_id]=43896 + membership[membership_product_6]=Kongresspaket%3A+Gesundes+Geld+f%C3%BCr+eine+gesunde+Welt + membership[membership_product_6_id]=14590 + membership[membership_product_7]=Deine+Gold-Mitgliedschaft+bei+Gradido + membership[membership_product_7_id]=43951 + membership[membership_product_8]=Gradido+E-Book%2C+H%C3%B6rspiel+%22Joytopia%22++%E2%80%93+und+100+Vorteile + membership[membership_product_8_id]=7312 + membership[membership_product_9]=Danke%2C+dass+Du+hilfst+Gradido+in+die+Welt+zu+bringen%21 + membership[membership_product_9_id]=43744 + membership[membership_product_10]=Basis-Informationen+zu+Gradido + membership[membership_product_10_id]=42600 + membership[membership_product_11]=Seminar+1+Nat%C3%BCrliche+%C3%96konomie+des+Lebens + membership[membership_product_11_id]=43882 + membership[membership_product_12]=Musical+%22Gradido+%E2%80%93+gemeinsam+retten+wir+die+Welt%22 + membership[membership_product_12_id]=43886 + membership[membership_product_13]=Premium+Community+%26+Markt + membership[membership_product_13_id]=43885 + membership[membership_product_14]=Gradido+Buch+ungek%C3%BCrzte+Version+%26+%C3%9Cbersetzungen + membership[membership_product_14_id]=43887 + membership[membership_product_15]=Online-Konferenzen + membership[membership_product_15_id]=43919 + membership[membership_product_16]=Gradido+H%C3%B6rbuch + membership[membership_product_16_id]=43920 + events[] + events[] + events[] + events[] + events[] + events[] + events[] + events[] + events[] + events[] + events[] + events[] + events[] + events[] + events[] + events[] + tickets[][codes] + tickets[][ticket_attendees] + tickets[][codes] + tickets[][ticket_attendees] + tickets[][codes] + tickets[][ticket_attendees] + tickets[][codes] + tickets[][ticket_attendees] + tickets[][codes] + tickets[][ticket_attendees] + tickets[][codes] + tickets[][ticket_attendees] + tickets[][codes] + tickets[][ticket_attendees] + tickets[][codes] + tickets[][ticket_attendees] + tickets[][codes] + tickets[][ticket_attendees] + tickets[][codes] + tickets[][ticket_attendees] + tickets[][codes] + tickets[][ticket_attendees] + tickets[][codes] + tickets[][ticket_attendees] + tickets[][codes] + tickets[][ticket_attendees] + tickets[][codes] + tickets[][ticket_attendees] + tickets[][codes] + tickets[][ticket_attendees] + tickets[][codes] + tickets[][ticket_attendees] + pricing_plan[name]=Monatlich + add_id_1 + add_id_2 + campaign_id + currency=EUR + coupon_code + recurring=yes + recurring_form=subscription + payment_method=sepa + opt_ins + payments_schedule[][rate]=1 + payments_schedule[][state]=debt + payments_schedule[][amount]=40.0 + payments_schedule[][date]=29.10.2019 + payments_schedule[][rate]=2 + payments_schedule[][state]=paid + payments_schedule[][amount]=40.0 + payments_schedule[][date]=29.11.2019 + payments_schedule[][rate]=3 + payments_schedule[][state]=to_be_paid + payments_schedule[][amount]=40.0 + payments_schedule[][date]=29.12.2019 + payments_schedule[][rate]=4 + payments_schedule[][state]=to_be_paid + payments_schedule[][amount]=40.0 + payments_schedule[][date]=29.01.2020 + payments_schedule[][rate]=5 + payments_schedule[][state]=to_be_paid + payments_schedule[][amount]=40.0 + payments_schedule[][date]=29.02.2020 + payments_schedule[][rate]=6 + payments_schedule[][state]=to_be_paid + payments_schedule[][amount]=40.0 + payments_schedule[][date]=29.03.2020 + payments_schedule[][rate]=7 + payments_schedule[][state]=to_be_paid + payments_schedule[][amount]=40.0 + payments_schedule[][date]=29.04.2020 + payments_schedule[][rate]=8 + payments_schedule[][state]=to_be_paid + payments_schedule[][amount]=40.0 + payments_schedule[][date]=29.05.2020 + payments_schedule[][rate]=9 + payments_schedule[][state]=to_be_paid + payments_schedule[][amount]=40.0 + payments_schedule[][date]=29.06.2020 + payments_schedule[][rate]=10 + payments_schedule[][state]=to_be_paid + payments_schedule[][amount]=40.0 + payments_schedule[][date]=29.07.2020 + payments_schedule[][rate]=11 + payments_schedule[][state]=to_be_paid + payments_schedule[][amount]=40.0 + payments_schedule[][date]=29.08.2020 + payments_schedule[][rate]=12 + payments_schedule[][state]=to_be_paid + payments_schedule[][amount]=40.0 + payments_schedule[][date]=29.09.2020 + payments_schedule[][rate]=13 + payments_schedule[][state]=to_be_paid + payments_schedule[][amount]=40.0 + payments_schedule[][date]=29.10.2020 + payments_schedule[][rate]=14 + payments_schedule[][state]=to_be_paid + payments_schedule[][amount]=0.0 + payments_schedule[][date]=29.11.2020 + payments_schedule[][rate]=15 + payments_schedule[][state]=to_be_paid + payments_schedule[][amount]=0.0 + payments_schedule[][date]=29.12.2020 + payments_count=1&payments_count_expected + with_test_period=false + with_custom_start=false + created=29.10.2019+13%3A17 + id=57354055 + invoice_number=111-1839-000000677 + revenue=40.0 + amount=23.72 + fee=16.28 + vat_rate=0.0 + vat_amount=0.0 + state=successful + refunded_transfer_id + invoice_link=http%3A%2F%2Felopage.com%2Fcommon%2Finvoices%2F450856%2Fdownload.pdf%3Ftoken%3DGR7bG7zcbgCzNJEPLDss + credit_memo_link + success_link=http%3A%2F%2Felopage.com%2Fs%2Fgradido%2Fpayment%2Fy22MJxHr9XzzPiaaH9GU + error_msg + created_date=2019-11-29T07%3A19Z + success_date_short=2019-12-06 + created_date_utc=29.11.2019+07%3A19 + success_date_utc=06.12.2019+13%3A12 + team_member_commissions +*/ From 52b6026ed836ce3f07599399d4798315f166c09c Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Wed, 17 Nov 2021 16:58:04 +0100 Subject: [PATCH 007/101] missing .env.dist value --- backend/.env.dist | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/backend/.env.dist b/backend/.env.dist index b4a91026a..1b485b8e4 100644 --- a/backend/.env.dist +++ b/backend/.env.dist @@ -30,4 +30,6 @@ COMMUNITY_URL= COMMUNITY_REGISTER_URL= COMMUNITY_DESCRIPTION= LOGIN_APP_SECRET=21ffbbc616fe -LOGIN_SERVER_KEY=a51ef8ac7ef1abf162fb7a65261acd7a \ No newline at end of file +LOGIN_SERVER_KEY=a51ef8ac7ef1abf162fb7a65261acd7a + +WEBHOOK_ELOPAGE_SECRET=secret \ No newline at end of file From c2a3866ae53c034e171406945dd0edfd26ba8f34 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Wed, 17 Nov 2021 19:32:11 +0100 Subject: [PATCH 008/101] reduce coverage --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 0e89057cf..f4d48c5c4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -394,7 +394,7 @@ jobs: report_name: Coverage Backend type: lcov result_path: ./backend/coverage/lcov.info - min_coverage: 39 + min_coverage: 38 token: ${{ github.token }} ############################################################################## From 5335d128021d54eb4a90efd0bd90d425d5487ae7 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Wed, 17 Nov 2021 19:37:35 +0100 Subject: [PATCH 009/101] catch error on createUser and log them --- backend/src/webhook/elopage.ts | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/backend/src/webhook/elopage.ts b/backend/src/webhook/elopage.ts index 0db26bf9c..945a2a24c 100644 --- a/backend/src/webhook/elopage.ts +++ b/backend/src/webhook/elopage.ts @@ -145,14 +145,19 @@ export const elopageWebhook = async (req: any, res: any): Promise => { randomBytes(8).toString('hex') + email + '!aA1' + randomBytes(8).toString('hex') const userResolver = new UserResolver() - userResolver.createUser({ - email, - firstName, - lastName, - password, - language: 'default', - publisherId: loginElopgaeBuy.publisherId, - }) + try { + await userResolver.createUser({ + email, + firstName, + lastName, + password, + language: 'default', + publisherId: loginElopgaeBuy.publisherId, + }) + } catch (error) { + // eslint-disable-next-line no-console + console.log(`Could not create User for ${email}. Following Error occured:`, error) + } } } From 2aba37e60c5a76d749a66bd62e94f2d2aa630b8a Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Fri, 19 Nov 2021 01:00:55 +0100 Subject: [PATCH 010/101] replace map with foreach since we don't need a return - thanks moriz --- backend/src/webhook/elopage.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/src/webhook/elopage.ts b/backend/src/webhook/elopage.ts index 945a2a24c..10dc35b61 100644 --- a/backend/src/webhook/elopage.ts +++ b/backend/src/webhook/elopage.ts @@ -37,7 +37,7 @@ export const elopageWebhook = async (req: any, res: any): Promise => { let firstName = '' let lastName = '' const entries = req.body.split('&') - entries.map((entry: string) => { + entries.foreach((entry: string) => { const keyVal = entry.split('=') if (keyVal.length !== 2) { throw new Error(`Error parsing entry '${entry}'`) @@ -90,7 +90,6 @@ export const elopageWebhook = async (req: any, res: any): Promise => { // eslint-disable-next-line no-console console.log(`Unknown Elopage Value '${entry}'`) } - return null // we write things into the loginElopgaeBuy object, no return value needed }) // Do not process certain events From a44a3ee6d06df5bf6dc465680791e71a0d2df553 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Fri, 19 Nov 2021 01:08:53 +0100 Subject: [PATCH 011/101] make language an optional parameter for createUser and do not set it on the elopage webhook --- backend/src/graphql/arg/CreateUserArgs.ts | 2 +- backend/src/graphql/resolver/UserResolver.ts | 2 +- backend/src/webhook/elopage.ts | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/backend/src/graphql/arg/CreateUserArgs.ts b/backend/src/graphql/arg/CreateUserArgs.ts index 3d09e56eb..906e14aed 100644 --- a/backend/src/graphql/arg/CreateUserArgs.ts +++ b/backend/src/graphql/arg/CreateUserArgs.ts @@ -15,7 +15,7 @@ export default class CreateUserArgs { password: string @Field(() => String) - language: string + language?: string @Field(() => Int, { nullable: true }) publisherId: number diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 888a1aa00..ba71fef7a 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -280,7 +280,7 @@ export class UserResolver { // default int publisher_id = 0; // Validate Language (no throw) - if (!isLanguage(language)) { + if (!language || !isLanguage(language)) { language = DEFAULT_LANGUAGE } diff --git a/backend/src/webhook/elopage.ts b/backend/src/webhook/elopage.ts index 10dc35b61..fb25e9068 100644 --- a/backend/src/webhook/elopage.ts +++ b/backend/src/webhook/elopage.ts @@ -150,7 +150,6 @@ export const elopageWebhook = async (req: any, res: any): Promise => { firstName, lastName, password, - language: 'default', publisherId: loginElopgaeBuy.publisherId, }) } catch (error) { From ad82cda48933929c7b13188ac998acbe6cd1cbf6 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Fri, 19 Nov 2021 01:12:01 +0100 Subject: [PATCH 012/101] remove unused fields comments to reduce file lengrh --- backend/src/webhook/elopage.ts | 208 --------------------------------- 1 file changed, 208 deletions(-) diff --git a/backend/src/webhook/elopage.ts b/backend/src/webhook/elopage.ts index fb25e9068..62af89f2f 100644 --- a/backend/src/webhook/elopage.ts +++ b/backend/src/webhook/elopage.ts @@ -158,211 +158,3 @@ export const elopageWebhook = async (req: any, res: any): Promise => { } } } - -/* -Known unused fields: - - order_token=y22MJxHr9XzzPiaaH9GU - payment_session_id=849951 - payment_session_token=y22MJxHr9XzzPiaaH9GU - action=payment_processed - initiator - payer[first_name]=Theodora - payer[last_name]=Mis - payer[country]=Schweiz - payer[country_code]=CH - payer[city]=St.+Gallen - payer[street]=Vonwilstrasse+23 - payer[street_number] - payer[zip]=9000 - payer[company] - payer[vat_no] - payer[phone] - gift_receiver - publisher[first_name]=Bernd - publisher[last_name]=H%C3%BCckst%C3%A4dt - publisher[street]=Pfarrweg+2 - publisher[zip]=74653 - publisher[city]=K%C3%BCnzelsau - publisher[country]=Deutschland - publisher[phone]=%2B4979405460810 - team_members - product[id]=43944 - product[slug]=gold-de - product[name]=Gold-Mitgliedschaft - product[type]=membership - upsell - membership[name]=Gold-Mitgliedschaft - membership[membership_product_1]=Werkzeuge+%26+Ressourcen+%28Gold%29 - membership[membership_product_1_id]=44982 - membership[membership_product_2]=Zertifizierung+zum%2Fr+Gradido-Botschafter%2Fin - membership[membership_product_2_id]=43970 - membership[membership_product_3]=Seminar+3+Nat%C3%BCrliche+%C3%96konomie+des+Lebens - membership[membership_product_3_id]=43969 - membership[membership_product_4]=Potential-Entfaltungs-Techniken - membership[membership_product_4_id]=43954 - membership[membership_product_5]=Seminar+2+Nat%C3%BCrliche+%C3%96konomie+des+Lebens - membership[membership_product_5_id]=43896 - membership[membership_product_6]=Kongresspaket%3A+Gesundes+Geld+f%C3%BCr+eine+gesunde+Welt - membership[membership_product_6_id]=14590 - membership[membership_product_7]=Deine+Gold-Mitgliedschaft+bei+Gradido - membership[membership_product_7_id]=43951 - membership[membership_product_8]=Gradido+E-Book%2C+H%C3%B6rspiel+%22Joytopia%22++%E2%80%93+und+100+Vorteile - membership[membership_product_8_id]=7312 - membership[membership_product_9]=Danke%2C+dass+Du+hilfst+Gradido+in+die+Welt+zu+bringen%21 - membership[membership_product_9_id]=43744 - membership[membership_product_10]=Basis-Informationen+zu+Gradido - membership[membership_product_10_id]=42600 - membership[membership_product_11]=Seminar+1+Nat%C3%BCrliche+%C3%96konomie+des+Lebens - membership[membership_product_11_id]=43882 - membership[membership_product_12]=Musical+%22Gradido+%E2%80%93+gemeinsam+retten+wir+die+Welt%22 - membership[membership_product_12_id]=43886 - membership[membership_product_13]=Premium+Community+%26+Markt - membership[membership_product_13_id]=43885 - membership[membership_product_14]=Gradido+Buch+ungek%C3%BCrzte+Version+%26+%C3%9Cbersetzungen - membership[membership_product_14_id]=43887 - membership[membership_product_15]=Online-Konferenzen - membership[membership_product_15_id]=43919 - membership[membership_product_16]=Gradido+H%C3%B6rbuch - membership[membership_product_16_id]=43920 - events[] - events[] - events[] - events[] - events[] - events[] - events[] - events[] - events[] - events[] - events[] - events[] - events[] - events[] - events[] - events[] - tickets[][codes] - tickets[][ticket_attendees] - tickets[][codes] - tickets[][ticket_attendees] - tickets[][codes] - tickets[][ticket_attendees] - tickets[][codes] - tickets[][ticket_attendees] - tickets[][codes] - tickets[][ticket_attendees] - tickets[][codes] - tickets[][ticket_attendees] - tickets[][codes] - tickets[][ticket_attendees] - tickets[][codes] - tickets[][ticket_attendees] - tickets[][codes] - tickets[][ticket_attendees] - tickets[][codes] - tickets[][ticket_attendees] - tickets[][codes] - tickets[][ticket_attendees] - tickets[][codes] - tickets[][ticket_attendees] - tickets[][codes] - tickets[][ticket_attendees] - tickets[][codes] - tickets[][ticket_attendees] - tickets[][codes] - tickets[][ticket_attendees] - tickets[][codes] - tickets[][ticket_attendees] - pricing_plan[name]=Monatlich - add_id_1 - add_id_2 - campaign_id - currency=EUR - coupon_code - recurring=yes - recurring_form=subscription - payment_method=sepa - opt_ins - payments_schedule[][rate]=1 - payments_schedule[][state]=debt - payments_schedule[][amount]=40.0 - payments_schedule[][date]=29.10.2019 - payments_schedule[][rate]=2 - payments_schedule[][state]=paid - payments_schedule[][amount]=40.0 - payments_schedule[][date]=29.11.2019 - payments_schedule[][rate]=3 - payments_schedule[][state]=to_be_paid - payments_schedule[][amount]=40.0 - payments_schedule[][date]=29.12.2019 - payments_schedule[][rate]=4 - payments_schedule[][state]=to_be_paid - payments_schedule[][amount]=40.0 - payments_schedule[][date]=29.01.2020 - payments_schedule[][rate]=5 - payments_schedule[][state]=to_be_paid - payments_schedule[][amount]=40.0 - payments_schedule[][date]=29.02.2020 - payments_schedule[][rate]=6 - payments_schedule[][state]=to_be_paid - payments_schedule[][amount]=40.0 - payments_schedule[][date]=29.03.2020 - payments_schedule[][rate]=7 - payments_schedule[][state]=to_be_paid - payments_schedule[][amount]=40.0 - payments_schedule[][date]=29.04.2020 - payments_schedule[][rate]=8 - payments_schedule[][state]=to_be_paid - payments_schedule[][amount]=40.0 - payments_schedule[][date]=29.05.2020 - payments_schedule[][rate]=9 - payments_schedule[][state]=to_be_paid - payments_schedule[][amount]=40.0 - payments_schedule[][date]=29.06.2020 - payments_schedule[][rate]=10 - payments_schedule[][state]=to_be_paid - payments_schedule[][amount]=40.0 - payments_schedule[][date]=29.07.2020 - payments_schedule[][rate]=11 - payments_schedule[][state]=to_be_paid - payments_schedule[][amount]=40.0 - payments_schedule[][date]=29.08.2020 - payments_schedule[][rate]=12 - payments_schedule[][state]=to_be_paid - payments_schedule[][amount]=40.0 - payments_schedule[][date]=29.09.2020 - payments_schedule[][rate]=13 - payments_schedule[][state]=to_be_paid - payments_schedule[][amount]=40.0 - payments_schedule[][date]=29.10.2020 - payments_schedule[][rate]=14 - payments_schedule[][state]=to_be_paid - payments_schedule[][amount]=0.0 - payments_schedule[][date]=29.11.2020 - payments_schedule[][rate]=15 - payments_schedule[][state]=to_be_paid - payments_schedule[][amount]=0.0 - payments_schedule[][date]=29.12.2020 - payments_count=1&payments_count_expected - with_test_period=false - with_custom_start=false - created=29.10.2019+13%3A17 - id=57354055 - invoice_number=111-1839-000000677 - revenue=40.0 - amount=23.72 - fee=16.28 - vat_rate=0.0 - vat_amount=0.0 - state=successful - refunded_transfer_id - invoice_link=http%3A%2F%2Felopage.com%2Fcommon%2Finvoices%2F450856%2Fdownload.pdf%3Ftoken%3DGR7bG7zcbgCzNJEPLDss - credit_memo_link - success_link=http%3A%2F%2Felopage.com%2Fs%2Fgradido%2Fpayment%2Fy22MJxHr9XzzPiaaH9GU - error_msg - created_date=2019-11-29T07%3A19Z - success_date_short=2019-12-06 - created_date_utc=29.11.2019+07%3A19 - success_date_utc=06.12.2019+13%3A12 - team_member_commissions -*/ From f6f6314eb170358c23b2a6f41bf5239c19edb062 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Fri, 19 Nov 2021 01:22:24 +0100 Subject: [PATCH 013/101] save price as integer --- backend/src/webhook/elopage.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/webhook/elopage.ts b/backend/src/webhook/elopage.ts index 62af89f2f..da9d1a171 100644 --- a/backend/src/webhook/elopage.ts +++ b/backend/src/webhook/elopage.ts @@ -58,8 +58,8 @@ export const elopageWebhook = async (req: any, res: any): Promise => { loginElopgaeBuy.productId = parseInt(val) break case 'product[price]': - // TODO: static_cast(round(stof(temp) * 100.0f)); - loginElopgaeBuy.productPrice = parseFloat(val) + // TODO: WHAT THE ACTUAL FUK? Please save this as float in the future directly in the database + loginElopgaeBuy.productPrice = Math.trunc(parseFloat(val) * 100) break case 'payer[email]': loginElopgaeBuy.payerEmail = val From a6e4e84c9bc484bccc3dbc2fcfcb0310a3da1aab Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Fri, 19 Nov 2021 01:51:13 +0100 Subject: [PATCH 014/101] do not generate a password for a user, but change the process to set the password later. --- backend/src/graphql/arg/CreateUserArgs.ts | 5 +- backend/src/graphql/resolver/UserResolver.ts | 54 +++++++++++--------- backend/src/webhook/elopage.ts | 6 --- 3 files changed, 32 insertions(+), 33 deletions(-) diff --git a/backend/src/graphql/arg/CreateUserArgs.ts b/backend/src/graphql/arg/CreateUserArgs.ts index 906e14aed..0d63e76bb 100644 --- a/backend/src/graphql/arg/CreateUserArgs.ts +++ b/backend/src/graphql/arg/CreateUserArgs.ts @@ -12,10 +12,7 @@ export default class CreateUserArgs { lastName: string @Field(() => String) - password: string - - @Field(() => String) - language?: string + language?: string // Will default to DEFAULT_LANGUAGE @Field(() => Int, { nullable: true }) publisherId: number diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index ba71fef7a..471ca7384 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -274,7 +274,7 @@ export class UserResolver { @Mutation(() => String) async createUser( - @Args() { email, firstName, lastName, password, language, publisherId }: CreateUserArgs, + @Args() { email, firstName, lastName, language, publisherId }: CreateUserArgs, ): Promise { // TODO: wrong default value (should be null), how does graphql work here? Is it an required field? // default int publisher_id = 0; @@ -284,12 +284,13 @@ export class UserResolver { language = DEFAULT_LANGUAGE } + // TODO: Register process // Validate Password - if (!isPassword(password)) { - throw new Error( - 'Please enter a valid password with at least 8 characters, upper and lower case letters, at least one number and one special character!', - ) - } + // if (!isPassword(password)) { + // throw new Error( + // 'Please enter a valid password with at least 8 characters, upper and lower case letters, at least one number and one special character!', + // ) + // } // Validate username // TODO: never true @@ -307,11 +308,13 @@ export class UserResolver { throw new Error(`User already exists.`) } - const passphrase = PassphraseGenerate() - const keyPair = KeyPairEd25519Create(passphrase) // return pub, priv Key - const passwordHash = SecretKeyCryptographyCreateKey(email, password) // return short and long hash + // TODO: Register process + // const passphrase = PassphraseGenerate() + // const keyPair = KeyPairEd25519Create(passphrase) // return pub, priv Key + // const passwordHash = SecretKeyCryptographyCreateKey(email, password) // return short and long hash + // const encryptedPrivkey = SecretKeyCryptographyEncrypt(keyPair[1], passwordHash[1]) + const emailHash = getEmailHash(email) - const encryptedPrivkey = SecretKeyCryptographyEncrypt(keyPair[1], passwordHash[1]) // Table: login_users const loginUser = new LoginUser() @@ -320,13 +323,15 @@ export class UserResolver { loginUser.lastName = lastName loginUser.username = username loginUser.description = '' - loginUser.password = passwordHash[0].readBigUInt64LE() // using the shorthash + // TODO: Register process + // loginUser.password = passwordHash[0].readBigUInt64LE() // using the shorthash loginUser.emailHash = emailHash loginUser.language = language loginUser.groupId = 1 loginUser.publisherId = publisherId - loginUser.pubKey = keyPair[0] - loginUser.privKey = encryptedPrivkey + // TODO: Register process + // loginUser.pubKey = keyPair[0] + // loginUser.privKey = encryptedPrivkey const queryRunner = getConnection().createQueryRunner() await queryRunner.connect() @@ -338,21 +343,24 @@ export class UserResolver { throw new Error('insert user failed') }) + // TODO: Register process // Table: login_user_backups - const loginUserBackup = new LoginUserBackup() - loginUserBackup.userId = loginUserId - loginUserBackup.passphrase = passphrase.join(' ') + ' ' // login server saves trailing space - loginUserBackup.mnemonicType = 2 // ServerConfig::MNEMONIC_BIP0039_SORTED_ORDER; + // const loginUserBackup = new LoginUserBackup() + // loginUserBackup.userId = loginUserId + // loginUserBackup.passphrase = passphrase.join(' ') + ' ' // login server saves trailing space + // loginUserBackup.mnemonicType = 2 // ServerConfig::MNEMONIC_BIP0039_SORTED_ORDER; - await queryRunner.manager.save(loginUserBackup).catch((error) => { - // eslint-disable-next-line no-console - console.log('insert LoginUserBackup failed', error) - throw new Error('insert user backup failed') - }) + // TODO: Register process + // await queryRunner.manager.save(loginUserBackup).catch((error) => { + // // eslint-disable-next-line no-console + // console.log('insert LoginUserBackup failed', error) + // throw new Error('insert user backup failed') + // }) // Table: state_users const dbUser = new DbUser() - dbUser.pubkey = keyPair[0] + // TODO: Register process + // dbUser.pubkey = keyPair[0] dbUser.email = email dbUser.firstName = firstName dbUser.lastName = lastName diff --git a/backend/src/webhook/elopage.ts b/backend/src/webhook/elopage.ts index da9d1a171..90cdb159f 100644 --- a/backend/src/webhook/elopage.ts +++ b/backend/src/webhook/elopage.ts @@ -138,18 +138,12 @@ export const elopageWebhook = async (req: any, res: any): Promise => { return } - // generate a random password - 8 random bytes, the email, special char, capital & small letter, number and another set of 8 random bytes - // TODO: The user will be forced to reset his password - how was this done before? - const password = - randomBytes(8).toString('hex') + email + '!aA1' + randomBytes(8).toString('hex') - const userResolver = new UserResolver() try { await userResolver.createUser({ email, firstName, lastName, - password, publisherId: loginElopgaeBuy.publisherId, }) } catch (error) { From 686f9bfd4e6aeaaad9be451ddcdcf04f54e3cbe5 Mon Sep 17 00:00:00 2001 From: ogerly Date: Fri, 19 Nov 2021 11:14:16 +0100 Subject: [PATCH 015/101] admin area extended according to concept and functions added and improved. workflow stands for the mass creation and for the confirmation of creations. all changes made which were indicated by moritz. all translations will be done in one step at a later date. --- admin/package.json | 3 +- admin/src/App.vue | 3 + admin/src/components/CreationFormular.spec.js | 8 +- admin/src/components/CreationFormular.vue | 201 +++++++++++++---- admin/src/components/Footer.vue | 10 + admin/src/components/NavBar.spec.js | 4 +- admin/src/components/NavBar.vue | 18 +- admin/src/components/UserTable.spec.js | 4 +- admin/src/components/UserTable.vue | 208 ++++++++++++++---- admin/src/store/store.js | 22 ++ admin/src/views/Creation.vue | 109 ++++----- admin/src/views/CreationConfirm.vue | 48 ++-- admin/src/views/Overview.vue | 31 ++- admin/yarn.lock | 13 ++ 14 files changed, 497 insertions(+), 185 deletions(-) create mode 100644 admin/src/components/Footer.vue diff --git a/admin/package.json b/admin/package.json index 5dff9145e..f3ba786bc 100644 --- a/admin/package.json +++ b/admin/package.json @@ -41,7 +41,8 @@ "vue-jest": "^3.0.7", "vue-moment": "^4.1.0", "vue-router": "^3.5.3", - "vuex": "^3.6.2" + "vuex": "^3.6.2", + "vuex-persistedstate": "^4.1.0" }, "devDependencies": { "@babel/eslint-parser": "^7.15.8", diff --git a/admin/src/App.vue b/admin/src/App.vue index 1a15d5d7c..70bc2978a 100644 --- a/admin/src/App.vue +++ b/admin/src/App.vue @@ -2,15 +2,18 @@
+
diff --git a/admin/src/components/CreationFormular.spec.js b/admin/src/components/CreationFormular.spec.js index c2098768c..9f4fc3f1b 100644 --- a/admin/src/components/CreationFormular.spec.js +++ b/admin/src/components/CreationFormular.spec.js @@ -3,11 +3,13 @@ import CreationFormular from './CreationFormular.vue' const localVue = global.localVue +const mocks = { $moment: jest.fn() } + describe('CreationFormular', () => { let wrapper const Wrapper = () => { - return mount(CreationFormular, { localVue }) + return mount(CreationFormular, { localVue, mocks }) } describe('mount', () => { @@ -15,8 +17,8 @@ describe('CreationFormular', () => { wrapper = Wrapper() }) - it('have a DIV element with the class.componente-creation-formular', () => { - expect(wrapper.find('.componente-creation-formular').exists()).toBeTruthy() + it('has a DIV element with the class.component-creation-formular', () => { + expect(wrapper.find('.component-creation-formular').exists()).toBeTruthy() }) }) }) diff --git a/admin/src/components/CreationFormular.vue b/admin/src/components/CreationFormular.vue index dbc40c13c..995640c72 100644 --- a/admin/src/components/CreationFormular.vue +++ b/admin/src/components/CreationFormular.vue @@ -1,72 +1,108 @@ From 03e5df5ece7dd4984b062644f59e853621d876bf Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Fri, 19 Nov 2021 21:26:12 +0100 Subject: [PATCH 065/101] convenience mode to disable the auth mode for development --- admin/.env.dist | 3 ++- admin/src/App.vue | 8 +++++++- admin/src/config/index.js | 5 +++++ admin/src/router/guards.js | 14 +++++++++----- 4 files changed, 23 insertions(+), 7 deletions(-) diff --git a/admin/.env.dist b/admin/.env.dist index a056837ab..6d78e6782 100644 --- a/admin/.env.dist +++ b/admin/.env.dist @@ -1,2 +1,3 @@ GRAPHQL_URI=http://localhost:4000/graphql -WALLET_AUTH_URL=http://localhost/vue/authenticate?token=$1 \ No newline at end of file +WALLET_AUTH_URL=http://localhost/vue/authenticate?token=$1 +DEBUG_DISABLE_AUTH=false \ No newline at end of file diff --git a/admin/src/App.vue b/admin/src/App.vue index 40460eda4..7c3dd8514 100644 --- a/admin/src/App.vue +++ b/admin/src/App.vue @@ -1,15 +1,21 @@ diff --git a/admin/src/config/index.js b/admin/src/config/index.js index 1ef44fe60..236274d1f 100644 --- a/admin/src/config/index.js +++ b/admin/src/config/index.js @@ -23,6 +23,10 @@ const endpoints = { WALLET_AUTH_URL: process.env.WALLET_AUTH_URL || 'http://localhost:3000/vue/authenticate?token=$1' } +const debug = { + DEBUG_DISABLE_AUTH: process.env.DEBUG_DISABLE_AUTH === 'true' || false +} + const options = {} const CONFIG = { @@ -30,6 +34,7 @@ const CONFIG = { ...environment, ...endpoints, ...options, + ...debug, } export default CONFIG diff --git a/admin/src/router/guards.js b/admin/src/router/guards.js index 6207f443e..a8bdaa2e2 100644 --- a/admin/src/router/guards.js +++ b/admin/src/router/guards.js @@ -1,5 +1,7 @@ +import CONFIG from "../config" + const addNavigationGuards = (router, store) => { - // store token on authenticate + // store token on `authenticate` router.beforeEach((to, from, next) => { if (to.path === '/authenticate' && to.query.token) { store.commit('token',to.query.token) @@ -9,11 +11,13 @@ const addNavigationGuards = (router, store) => { } }) - // protect all routes but not-found + // protect all routes but `not-found` router.beforeEach((to, from, next) => { - console.log('protect', to.path, from.path) - // handle authentication - if (!store.state.token && to.path !== '/not-found' && to.path !== '/logout') { + if (!CONFIG.DEBUG_DISABLE_AUTH && // we did not disabled the auth module for debug purposes + !store.state.token && // we do not have a token + to.path !== '/not-found' && // we are not on `not-found` + to.path !== '/logout') { // we are not on `logout` + console.log(!CONFIG.DEBUG_DISABLE_AUTH,!store.state.token,to.path !== '/not-found',to.path !== '/logout') next({ path: '/not-found' }) } else { next() From c3801f37ab00a144bb2c82195510566287b00ca3 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Sat, 20 Nov 2021 16:30:05 +0100 Subject: [PATCH 066/101] corrected ports --- 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 236274d1f..9f33b59cb 100644 --- a/admin/src/config/index.js +++ b/admin/src/config/index.js @@ -20,7 +20,7 @@ const environment = { const endpoints = { GRAPHQL_URI: process.env.GRAPHQL_URI || 'http://localhost:4000/graphql', // TODO port - WALLET_AUTH_URL: process.env.WALLET_AUTH_URL || 'http://localhost:3000/vue/authenticate?token=$1' + WALLET_AUTH_URL: process.env.WALLET_AUTH_URL || 'http://localhost/vue/authenticate?token=$1' } const debug = { diff --git a/frontend/src/config/index.js b/frontend/src/config/index.js index 01c6c009a..0f8e58c1c 100644 --- a/frontend/src/config/index.js +++ b/frontend/src/config/index.js @@ -21,7 +21,7 @@ const environment = { const endpoints = { GRAPHQL_URI: process.env.GRAPHQL_URI || 'http://localhost:4000/graphql', // TODO port - ADMIN_AUTH_URL: process.env.ADMIN_AUTH_URL || 'http://localhost:8080/admin/authenticate?token=$1' + ADMIN_AUTH_URL: process.env.ADMIN_AUTH_URL || 'http://localhost/admin/authenticate?token=$1' } const options = {} From 41d6a7ba45659f5f129ea0a31a30d927f71f37a2 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Sat, 20 Nov 2021 16:30:22 +0100 Subject: [PATCH 067/101] implemented `isAdmin` from backend --- backend/src/graphql/model/User.ts | 4 +++ backend/src/graphql/resolver/UserResolver.ts | 31 ++++++++++++++++++++ frontend/src/graphql/queries.js | 1 + frontend/src/store/store.js | 7 ++++- 4 files changed, 42 insertions(+), 1 deletion(-) diff --git a/backend/src/graphql/model/User.ts b/backend/src/graphql/model/User.ts index 5b7682e01..33dce434b 100644 --- a/backend/src/graphql/model/User.ts +++ b/backend/src/graphql/model/User.ts @@ -20,6 +20,7 @@ export class User { this.pubkey = json.public_hex this.language = json.language this.publisherId = json.publisher_id + this.isAdmin = json.isAdmin } } @@ -71,6 +72,9 @@ export class User { @Field(() => Int, { nullable: true }) publisherId?: number + @Field(() => Boolean) + isAdmin: boolean + @Field(() => Boolean) coinanimation: boolean diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 25f83bb09..1fd441935 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -194,6 +194,36 @@ const SecretKeyCryptographyDecrypt = (encryptedMessage: Buffer, encryptionKey: B @Resolver() export class UserResolver { + /* + @Authorized() + @Query(() => User) + async verifyLogin(@Ctx() context: any): Promise { + const loginUserRepository = getCustomRepository(LoginUserRepository) + loginUser = loginUserRepository.findByPubkeyHex() + const user = new User(result.data.user) + + this.email = json.email + this.firstName = json.first_name + this.lastName = json.last_name + this.username = json.username + this.description = json.description + this.pubkey = json.public_hex + this.language = json.language + this.publisherId = json.publisher_id + this.isAdmin = json.isAdmin + + const userSettingRepository = getCustomRepository(UserSettingRepository) + const coinanimation = await userSettingRepository + .readBoolean(userEntity.id, Setting.COIN_ANIMATION) + .catch((error) => { + throw new Error(error) + }) + user.coinanimation = coinanimation + user.isAdmin = true // TODO implement + return user + } + */ + @Query(() => User) @UseMiddleware(klicktippNewsletterStateMiddleware) async login( @@ -265,6 +295,7 @@ export class UserResolver { throw new Error(error) }) user.coinanimation = coinanimation + user.isAdmin = true // TODO implement context.setHeaders.push({ key: 'token', diff --git a/frontend/src/graphql/queries.js b/frontend/src/graphql/queries.js index 01021f601..9cd364ed7 100644 --- a/frontend/src/graphql/queries.js +++ b/frontend/src/graphql/queries.js @@ -15,6 +15,7 @@ export const login = gql` } hasElopage publisherId + isAdmin } } ` diff --git a/frontend/src/store/store.js b/frontend/src/store/store.js index 1173a8685..c49197059 100644 --- a/frontend/src/store/store.js +++ b/frontend/src/store/store.js @@ -34,6 +34,9 @@ export const mutations = { if (isNaN(pubId)) pubId = null state.publisherId = pubId }, + isAdmin: (state, isAdmin) => { + state.isAdmin = !!isAdmin + }, community: (state, community) => { state.community = community }, @@ -57,6 +60,7 @@ export const actions = { commit('newsletterState', data.klickTipp.newsletterState) commit('hasElopage', data.hasElopage) commit('publisherId', data.publisherId) + commit('isAdmin', data.isAdmin) }, logout: ({ commit, state }) => { commit('token', null) @@ -69,6 +73,7 @@ export const actions = { commit('newsletterState', null) commit('hasElopage', false) commit('publisherId', null) + commit('isAdmin', false) localStorage.clear() }, } @@ -87,7 +92,7 @@ export const store = new Vuex.Store({ username: '', description: '', token: null, - isAdmin: true, // TODO implement this properly + isAdmin: false, coinanimation: true, newsletterState: null, community: { From f21587ae3abb1ed8125d4de277bfbef990047176 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Sat, 20 Nov 2021 16:37:25 +0100 Subject: [PATCH 068/101] frontend lint --- frontend/src/components/SidebarPlugin/SideBar.vue | 2 +- frontend/src/config/index.js | 3 +-- frontend/src/routes/guards.js | 9 ++++----- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/frontend/src/components/SidebarPlugin/SideBar.vue b/frontend/src/components/SidebarPlugin/SideBar.vue index d8b26318f..8277b17eb 100755 --- a/frontend/src/components/SidebarPlugin/SideBar.vue +++ b/frontend/src/components/SidebarPlugin/SideBar.vue @@ -122,7 +122,7 @@ export default { this.$emit('logout') }, admin() { - window.location = CONFIG.ADMIN_AUTH_URL.replace('$1',this.$store.state.token) + window.location = CONFIG.ADMIN_AUTH_URL.replace('$1', this.$store.state.token) this.$store.dispatch('logout') // logout without redirect }, getElopageLink() { diff --git a/frontend/src/config/index.js b/frontend/src/config/index.js index 0f8e58c1c..b3a9366b7 100644 --- a/frontend/src/config/index.js +++ b/frontend/src/config/index.js @@ -20,8 +20,7 @@ const environment = { const endpoints = { GRAPHQL_URI: process.env.GRAPHQL_URI || 'http://localhost:4000/graphql', - // TODO port - ADMIN_AUTH_URL: process.env.ADMIN_AUTH_URL || 'http://localhost/admin/authenticate?token=$1' + ADMIN_AUTH_URL: process.env.ADMIN_AUTH_URL || 'http://localhost/admin/authenticate?token=$1', } const options = {} diff --git a/frontend/src/routes/guards.js b/frontend/src/routes/guards.js index bb55ba0cf..005ed720f 100644 --- a/frontend/src/routes/guards.js +++ b/frontend/src/routes/guards.js @@ -11,16 +11,15 @@ const addNavigationGuards = (router, store) => { // store token on authenticate router.beforeEach((to, from, next) => { - console.log('token', to.path, from.path, to.query) if (to.path === '/authenticate' && to.query.token) { - console.log('token', to.query.token, to) - store.commit('token',to.query.token) - next({path: '/overview'}) + // TODO verify user in order to get user data + store.commit('token', to.query.token) + next({ path: '/overview' }) } else { next() } }) - + // handle authentication router.beforeEach((to, from, next) => { if (to.meta.requiresAuth && !store.state.token) { From 84684fe51f3cae31c3d3bb7384c500de54037276 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Sat, 20 Nov 2021 16:40:38 +0100 Subject: [PATCH 069/101] lint admin --- admin/src/App.vue | 4 ++-- admin/src/components/NavBar.vue | 4 ++-- admin/src/config/index.js | 5 ++--- admin/src/layouts/defaultLayout.vue | 2 +- admin/src/router/guards.js | 18 ++++++++++-------- 5 files changed, 17 insertions(+), 16 deletions(-) diff --git a/admin/src/App.vue b/admin/src/App.vue index 7c3dd8514..359b63b3a 100644 --- a/admin/src/App.vue +++ b/admin/src/App.vue @@ -14,8 +14,8 @@ export default { components: { defaultLayout }, data() { return { - showLayout: CONFIG.DEBUG_DISABLE_AUTH || this.$store.state.token + showLayout: CONFIG.DEBUG_DISABLE_AUTH || this.$store.state.token, } - } + }, } diff --git a/admin/src/components/NavBar.vue b/admin/src/components/NavBar.vue index 260c066b3..6fb0cb31f 100644 --- a/admin/src/components/NavBar.vue +++ b/admin/src/components/NavBar.vue @@ -50,9 +50,9 @@ export default { this.$router.push('/logout') }, wallet() { - window.location = CONFIG.WALLET_AUTH_URL.replace('$1',this.$store.state.token) + window.location = CONFIG.WALLET_AUTH_URL.replace('$1', this.$store.state.token) this.$store.dispatch('logout') // logout without redirect }, - } + }, } diff --git a/admin/src/config/index.js b/admin/src/config/index.js index 9f33b59cb..69d30a66a 100644 --- a/admin/src/config/index.js +++ b/admin/src/config/index.js @@ -19,12 +19,11 @@ const environment = { const endpoints = { GRAPHQL_URI: process.env.GRAPHQL_URI || 'http://localhost:4000/graphql', - // TODO port - WALLET_AUTH_URL: process.env.WALLET_AUTH_URL || 'http://localhost/vue/authenticate?token=$1' + WALLET_AUTH_URL: process.env.WALLET_AUTH_URL || 'http://localhost/vue/authenticate?token=$1', } const debug = { - DEBUG_DISABLE_AUTH: process.env.DEBUG_DISABLE_AUTH === 'true' || false + DEBUG_DISABLE_AUTH: process.env.DEBUG_DISABLE_AUTH === 'true' || false, } const options = {} diff --git a/admin/src/layouts/defaultLayout.vue b/admin/src/layouts/defaultLayout.vue index 71d2f894b..4f6cbbe4d 100644 --- a/admin/src/layouts/defaultLayout.vue +++ b/admin/src/layouts/defaultLayout.vue @@ -16,4 +16,4 @@ export default { FooTer, }, } - \ No newline at end of file + diff --git a/admin/src/router/guards.js b/admin/src/router/guards.js index a8bdaa2e2..f6d8058aa 100644 --- a/admin/src/router/guards.js +++ b/admin/src/router/guards.js @@ -1,11 +1,12 @@ -import CONFIG from "../config" +import CONFIG from '../config' const addNavigationGuards = (router, store) => { // store token on `authenticate` router.beforeEach((to, from, next) => { if (to.path === '/authenticate' && to.query.token) { - store.commit('token',to.query.token) - next({path: '/'}) + // TODO verify user to get user data + store.commit('token', to.query.token) + next({ path: '/' }) } else { next() } @@ -13,11 +14,12 @@ const addNavigationGuards = (router, store) => { // protect all routes but `not-found` router.beforeEach((to, from, next) => { - if (!CONFIG.DEBUG_DISABLE_AUTH && // we did not disabled the auth module for debug purposes - !store.state.token && // we do not have a token - to.path !== '/not-found' && // we are not on `not-found` - to.path !== '/logout') { // we are not on `logout` - console.log(!CONFIG.DEBUG_DISABLE_AUTH,!store.state.token,to.path !== '/not-found',to.path !== '/logout') + if ( + !CONFIG.DEBUG_DISABLE_AUTH && // we did not disabled the auth module for debug purposes + !store.state.token && // we do not have a token + to.path !== '/not-found' && // we are not on `not-found` + to.path !== '/logout' // we are not on `logout` + ) { next({ path: '/not-found' }) } else { next() From 47bce06f95d74a851e1e69e22eda90466f77a1ce Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Sat, 20 Nov 2021 16:48:10 +0100 Subject: [PATCH 070/101] properly handle auth shortcut in oder to not break layout on logout --- admin/src/App.vue | 8 +------- admin/src/store/store.js | 3 ++- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/admin/src/App.vue b/admin/src/App.vue index 359b63b3a..40460eda4 100644 --- a/admin/src/App.vue +++ b/admin/src/App.vue @@ -1,21 +1,15 @@ diff --git a/admin/src/store/store.js b/admin/src/store/store.js index 4df9f6f39..7820296c6 100644 --- a/admin/src/store/store.js +++ b/admin/src/store/store.js @@ -1,6 +1,7 @@ import Vuex from 'vuex' import Vue from 'vue' import createPersistedState from 'vuex-persistedstate' +import CONFIG from '../config' Vue.use(Vuex) @@ -33,7 +34,7 @@ const store = new Vuex.Store({ }), ], state: { - token: null, + token: CONFIG.DEBUG_DISABLE_AUTH ? 'validToken' : null, moderator: 'Dertest Moderator', openCreations: 0, }, From c8d188279fe0995671cb96bdf6d2f0cc6a9f6518 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Sat, 20 Nov 2021 16:51:21 +0100 Subject: [PATCH 071/101] add infos about jq software requirement --- frontend/README.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/frontend/README.md b/frontend/README.md index e9ac0b097..f7c60552c 100755 --- a/frontend/README.md +++ b/frontend/README.md @@ -385,4 +385,13 @@ TODO: Update GDT-Server um paging und Zugriff auf alle Einträge zu erhalten, op GET https://staging.gradido.net/state-balances/ajaxGdtTransactions Liefert wenn alles in Ordnung ist: -wenn nicht type 7 dann "amount" in euro ansonsten in GDT \ No newline at end of file +wenn nicht type 7 dann "amount" in euro ansonsten in GDT + +## Additional Software + +For `yarn locales` you will need `jq` to use it. +You can install it (on arch) via + +``` +sudo pacman -S jq +``` \ No newline at end of file From 024eb306127b6c8efebacef9bccdd1363e56c3b1 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Sat, 20 Nov 2021 16:51:45 +0100 Subject: [PATCH 072/101] fixed locales --- frontend/src/locales/de.json | 2 +- frontend/src/locales/en.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index 3f981450d..b0dfe36d4 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -1,4 +1,5 @@ { + "admin_area": "Adminbereich", "back": "Zurück", "community": { "choose-another-community": "Eine andere Gemeinschaft auswählen", @@ -110,7 +111,6 @@ "login": "Anmeldung", "logout": "Abmelden", "members_area": "Mitgliederbereich", - "admin_area": "Adminbereich", "message": "hallo gradido !!", "overview": "Übersicht", "privacy_policy": "Datenschutzerklärung", diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index 08c29d646..135729ffa 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -1,4 +1,5 @@ { + "admin_area": "Admin's area", "back": "Back", "community": { "choose-another-community": "Choose another community", @@ -110,7 +111,6 @@ "login": "Login", "logout": "Logout", "members_area": "Member's area", - "admin_area": "Admin's area", "message": "hello gradido !!", "overview": "Overview", "privacy_policy": "Privacy policy", From b2bb67ab9c04a570cc780f94fd7fa4cf45d4c4a2 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Sat, 20 Nov 2021 17:01:28 +0100 Subject: [PATCH 073/101] fix tests --- frontend/src/routes/guards.test.js | 2 +- frontend/src/routes/router.test.js | 4 ++-- frontend/src/store/store.test.js | 19 +++++++++++++++---- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/frontend/src/routes/guards.test.js b/frontend/src/routes/guards.test.js index cf366eac8..f271c5427 100644 --- a/frontend/src/routes/guards.test.js +++ b/frontend/src/routes/guards.test.js @@ -30,7 +30,7 @@ describe('navigation guards', () => { }) describe('authorization', () => { - const navGuard = router.beforeHooks[0] + const navGuard = router.beforeHooks[2] const next = jest.fn() it('redirects to login when not authorized', () => { diff --git a/frontend/src/routes/router.test.js b/frontend/src/routes/router.test.js index df4f9c229..cd26b6f6b 100644 --- a/frontend/src/routes/router.test.js +++ b/frontend/src/routes/router.test.js @@ -49,8 +49,8 @@ describe('router', () => { expect(routes.find((r) => r.path === '/').redirect()).toEqual({ path: '/login' }) }) - it('has fourteen routes defined', () => { - expect(routes).toHaveLength(14) + it('has fifteen routes defined', () => { + expect(routes).toHaveLength(15) }) describe('overview', () => { diff --git a/frontend/src/store/store.test.js b/frontend/src/store/store.test.js index bdb98d03b..829678b44 100644 --- a/frontend/src/store/store.test.js +++ b/frontend/src/store/store.test.js @@ -148,11 +148,12 @@ describe('Vuex store', () => { }, hasElopage: false, publisherId: 1234, + isAdmin: true, } - it('calls ten commits', () => { + it('calls eleven commits', () => { login({ commit, state }, commitedData) - expect(commit).toHaveBeenCalledTimes(10) + expect(commit).toHaveBeenCalledTimes(11) }) it('commits email', () => { @@ -204,15 +205,20 @@ describe('Vuex store', () => { login({ commit, state }, commitedData) expect(commit).toHaveBeenNthCalledWith(10, 'publisherId', 1234) }) + + it('commits isAdmin', () => { + login({ commit, state }, commitedData) + expect(commit).toHaveBeenNthCalledWith(11, 'isAdmin', true) + }) }) describe('logout', () => { const commit = jest.fn() const state = {} - it('calls ten commits', () => { + it('calls eleven commits', () => { logout({ commit, state }) - expect(commit).toHaveBeenCalledTimes(10) + expect(commit).toHaveBeenCalledTimes(11) }) it('commits token', () => { @@ -265,6 +271,11 @@ describe('Vuex store', () => { expect(commit).toHaveBeenNthCalledWith(10, 'publisherId', null) }) + it('commits isAdmin', () => { + logout({ commit, state }) + expect(commit).toHaveBeenNthCalledWith(11, 'isAdmin', false) + }) + // how to get this working? it.skip('calls localStorage.clear()', () => { const clearStorageMock = jest.fn() From c1381da2407d43f05b38daabe245a268d7b49aa4 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Mon, 22 Nov 2021 17:51:09 +0100 Subject: [PATCH 074/101] test admin link, correct pointer class --- .../components/SidebarPlugin/SideBar.spec.js | 28 +++++++++++++++++++ .../src/components/SidebarPlugin/SideBar.vue | 6 ++-- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/SidebarPlugin/SideBar.spec.js b/frontend/src/components/SidebarPlugin/SideBar.spec.js index 8204eb604..0a3b0ec1a 100644 --- a/frontend/src/components/SidebarPlugin/SideBar.spec.js +++ b/frontend/src/components/SidebarPlugin/SideBar.spec.js @@ -24,6 +24,7 @@ describe('SideBar', () => { hasElopage: false, }, commit: jest.fn(), + dispatch: jest.fn(), }, $i18n: { locale: 'en', @@ -154,6 +155,33 @@ describe('SideBar', () => { expect(wrapper.emitted('logout')).toEqual([[]]) }) }) + + describe('admin-area', () => { + it('is not visible when not an admin', () => { + expect(wrapper.findAll('li').at(1).text()).not.toBe('admin_area') + }) + describe('logged in as admin', () => { + const assignLocationSpy = jest.fn() + beforeEach(() => { + mocks.$store.state.isAdmin = true + mocks.$store.state.token = 'valid token' + // const { location } = window; + delete window.location + window.location = {} + Object.defineProperty(window, 'location', assignLocationSpy) + wrapper = Wrapper() + }) + + it('is visible', () => { + expect(wrapper.findAll('li').at(1).text()).toBe('admin_area') + }) + it.skip('opens a new window when clicked', async () => { + wrapper.findAll('li').at(1).find('a').trigger('click') + await wrapper.vm.$nextTick() + expect(assignLocationSpy).toHaveBeenCalledWith('peter') + }) + }) + }) }) }) }) diff --git a/frontend/src/components/SidebarPlugin/SideBar.vue b/frontend/src/components/SidebarPlugin/SideBar.vue index 8277b17eb..9cf6b6185 100755 --- a/frontend/src/components/SidebarPlugin/SideBar.vue +++ b/frontend/src/components/SidebarPlugin/SideBar.vue @@ -50,14 +50,14 @@ -