From 1cb8b185ac8786f4386305af61d756eb6a8e4427 Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 18 Nov 2021 09:14:02 +0100 Subject: [PATCH 001/278] Create tables on an already exsting table breaks the script, so fix with a create table if not exists. Insert statement breaks if their is a duplicate key that is imported change so that it does not break. --- database/migrations/0002-add_settings.ts | 2 +- .../migrations/0003-login_server_tables.ts | 20 +++++++++---------- database/migrations/0004-login_server_data.ts | 20 +++++++++---------- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/database/migrations/0002-add_settings.ts b/database/migrations/0002-add_settings.ts index d26a2b4cc..4c5300e49 100644 --- a/database/migrations/0002-add_settings.ts +++ b/database/migrations/0002-add_settings.ts @@ -11,7 +11,7 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promise>) { await queryFn(` - CREATE TABLE \`user_setting\` ( + CREATE TABLE IF NOT EXISTS \`user_setting\` ( \`id\` int(10) unsigned NOT NULL AUTO_INCREMENT, \`userId\` int(11) NOT NULL, \`key\` varchar(255) NOT NULL, diff --git a/database/migrations/0003-login_server_tables.ts b/database/migrations/0003-login_server_tables.ts index dacc211ac..ee8a4cfe2 100644 --- a/database/migrations/0003-login_server_tables.ts +++ b/database/migrations/0003-login_server_tables.ts @@ -11,7 +11,7 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promise>) { await queryFn(` - CREATE TABLE \`login_app_access_tokens\` ( + CREATE TABLE IF NOT EXISTS \`login_app_access_tokens\` ( \`id\` int unsigned NOT NULL AUTO_INCREMENT, \`user_id\` int NOT NULL, \`access_code\` bigint unsigned NOT NULL, @@ -22,7 +22,7 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; `) await queryFn(` - CREATE TABLE \`login_elopage_buys\` ( + CREATE TABLE IF NOT EXISTS \`login_elopage_buys\` ( \`id\` int unsigned NOT NULL AUTO_INCREMENT, \`elopage_user_id\` int DEFAULT NULL, \`affiliate_program_id\` int NOT NULL, @@ -39,7 +39,7 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; `) await queryFn(` - CREATE TABLE \`login_email_opt_in_types\` ( + CREATE TABLE IF NOT EXISTS \`login_email_opt_in_types\` ( \`id\` int unsigned NOT NULL AUTO_INCREMENT, \`name\` varchar(255) NOT NULL, \`description\` varchar(255) NOT NULL, @@ -47,7 +47,7 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; `) await queryFn(` - CREATE TABLE \`login_email_opt_in\` ( + CREATE TABLE IF NOT EXISTS \`login_email_opt_in\` ( \`id\` int unsigned NOT NULL AUTO_INCREMENT, \`user_id\` int NOT NULL, \`verification_code\` bigint unsigned NOT NULL, @@ -60,7 +60,7 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; `) await queryFn(` - CREATE TABLE \`login_groups\` ( + CREATE TABLE IF NOT EXISTS \`login_groups\` ( \`id\` int unsigned NOT NULL AUTO_INCREMENT, \`alias\` varchar(190) NOT NULL, \`name\` varchar(255) NOT NULL, @@ -73,7 +73,7 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; `) await queryFn(` - CREATE TABLE \`login_pending_tasks\` ( + CREATE TABLE IF NOT EXISTS \`login_pending_tasks\` ( \`id\` int UNSIGNED NOT NULL AUTO_INCREMENT, \`user_id\` int UNSIGNED DEFAULT 0, \`request\` varbinary(2048) NOT NULL, @@ -88,7 +88,7 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis ) ENGINE = InnoDB DEFAULT CHARSET=utf8mb4; `) await queryFn(` - CREATE TABLE \`login_roles\` ( + CREATE TABLE IF NOT EXISTS \`login_roles\` ( \`id\` int unsigned NOT NULL AUTO_INCREMENT, \`name\` varchar(255) NOT NULL, \`description\` varchar(255) NOT NULL, @@ -97,7 +97,7 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; `) await queryFn(` - CREATE TABLE \`login_user_backups\` ( + CREATE TABLE IF NOT EXISTS \`login_user_backups\` ( \`id\` int unsigned NOT NULL AUTO_INCREMENT, \`user_id\` int NOT NULL, \`passphrase\` text NOT NULL, @@ -106,7 +106,7 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; `) await queryFn(` - CREATE TABLE \`login_user_roles\` ( + CREATE TABLE IF NOT EXISTS \`login_user_roles\` ( \`id\` int unsigned NOT NULL AUTO_INCREMENT, \`user_id\` int NOT NULL, \`role_id\` int NOT NULL, @@ -114,7 +114,7 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; `) await queryFn(` - CREATE TABLE \`login_users\` ( + CREATE TABLE IF NOT EXISTS \`login_users\` ( \`id\` int unsigned NOT NULL AUTO_INCREMENT, \`email\` varchar(191) NOT NULL, \`first_name\` varchar(150) NOT NULL, diff --git a/database/migrations/0004-login_server_data.ts b/database/migrations/0004-login_server_data.ts index dad7d1e34..bd4cf2d18 100644 --- a/database/migrations/0004-login_server_data.ts +++ b/database/migrations/0004-login_server_data.ts @@ -22,34 +22,34 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis } await queryFn(` - INSERT INTO \`login_app_access_tokens\` SELECT * FROM ${LOGIN_SERVER_DB}.\`app_access_tokens\`; + INSERT IGNORE INTO \`login_app_access_tokens\` SELECT * FROM ${LOGIN_SERVER_DB}.\`app_access_tokens\`; `) await queryFn(` - INSERT INTO \`login_elopage_buys\` SELECT * FROM ${LOGIN_SERVER_DB}.\`elopage_buys\`; + INSERT IGNORE INTO \`login_elopage_buys\` SELECT * FROM ${LOGIN_SERVER_DB}.\`elopage_buys\`; `) await queryFn(` - INSERT INTO \`login_email_opt_in_types\` SELECT * FROM ${LOGIN_SERVER_DB}.\`email_opt_in_types\`; + INSERT IGNORE INTO \`login_email_opt_in_types\` SELECT * FROM ${LOGIN_SERVER_DB}.\`email_opt_in_types\`; `) await queryFn(` - INSERT INTO \`login_email_opt_in\` SELECT * FROM ${LOGIN_SERVER_DB}.\`email_opt_in\`; + INSERT IGNORE INTO \`login_email_opt_in\` SELECT * FROM ${LOGIN_SERVER_DB}.\`email_opt_in\`; `) await queryFn(` - INSERT INTO \`login_groups\` SELECT * FROM ${LOGIN_SERVER_DB}.\`groups\`; + INSERT IGNORE INTO \`login_groups\` SELECT * FROM ${LOGIN_SERVER_DB}.\`groups\`; `) await queryFn(` - INSERT INTO \`login_pending_tasks\` SELECT * FROM ${LOGIN_SERVER_DB}.\`pending_tasks\`; + INSERT IGNORE INTO \`login_pending_tasks\` SELECT * FROM ${LOGIN_SERVER_DB}.\`pending_tasks\`; `) await queryFn(` - INSERT INTO \`login_roles\` SELECT * FROM ${LOGIN_SERVER_DB}.\`roles\`; + INSERT IGNORE INTO \`login_roles\` SELECT * FROM ${LOGIN_SERVER_DB}.\`roles\`; `) await queryFn(` - INSERT INTO \`login_user_backups\` SELECT * FROM ${LOGIN_SERVER_DB}.\`user_backups\`; + INSERT IGNORE INTO \`login_user_backups\` SELECT * FROM ${LOGIN_SERVER_DB}.\`user_backups\`; `) await queryFn(` - INSERT INTO \`login_user_roles\` SELECT * FROM ${LOGIN_SERVER_DB}.\`user_roles\`; + INSERT IGNORE INTO \`login_user_roles\` SELECT * FROM ${LOGIN_SERVER_DB}.\`user_roles\`; `) await queryFn(` - INSERT INTO \`login_users\` SELECT * FROM ${LOGIN_SERVER_DB}.\`users\`; + INSERT IGNORE INTO \`login_users\` SELECT * FROM ${LOGIN_SERVER_DB}.\`users\`; `) // TODO clarify if we need this on non docker environment? From 728aaa095f42467dc68092c58616f12e86074615 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 23 Nov 2021 03:04:28 +0100 Subject: [PATCH 002/278] first of several calls regarding password reset --- backend/src/config/index.ts | 2 + .../model/SendPasswordResetEmailResponse.ts | 17 ----- backend/src/graphql/resolver/UserResolver.ts | 68 +++++++++++++++---- frontend/src/graphql/queries.js | 4 +- 4 files changed, 56 insertions(+), 35 deletions(-) delete mode 100644 backend/src/graphql/model/SendPasswordResetEmailResponse.ts diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index 7a55de8e8..820261bb1 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -53,6 +53,8 @@ const email = { EMAIL_SMTP_PORT: process.env.EMAIL_SMTP_PORT || '587', EMAIL_LINK_VERIFICATION: process.env.EMAIL_LINK_VERIFICATION || 'http://localhost/vue/checkEmail/$1', + EMAIL_LINK_SETPASSWORD: + process.env.EMAIL_LINK_SETPASSWORD || 'http://localhost/vue/setPassword/$1', } // This is needed by graphql-directive-auth diff --git a/backend/src/graphql/model/SendPasswordResetEmailResponse.ts b/backend/src/graphql/model/SendPasswordResetEmailResponse.ts deleted file mode 100644 index d387efede..000000000 --- a/backend/src/graphql/model/SendPasswordResetEmailResponse.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -import { ObjectType, Field } from 'type-graphql' - -@ObjectType() -export class SendPasswordResetEmailResponse { - constructor(json: any) { - this.state = json.state - this.msg = json.msg - } - - @Field(() => String) - state: string - - @Field(() => String) - msg?: string -} diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 25f83bb09..ffa78e8aa 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -6,7 +6,6 @@ import { Resolver, Query, Args, Arg, Authorized, Ctx, UseMiddleware, Mutation } import { getConnection, getCustomRepository } from 'typeorm' import CONFIG from '../../config' import { LoginViaVerificationCode } from '../model/LoginViaVerificationCode' -import { SendPasswordResetEmailResponse } from '../model/SendPasswordResetEmailResponse' import { User } from '../model/User' import { User as DbUser } from '@entity/User' import encode from '../../jwt/encode' @@ -30,6 +29,7 @@ import { LoginUserBackup } from '@entity/LoginUserBackup' import { LoginEmailOptIn } from '@entity/LoginEmailOptIn' import { sendEMail } from '../../util/sendEMail' import { LoginElopageBuysRepository } from '../../typeorm/repository/LoginElopageBuys' +import { randomBytes } from 'crypto' // eslint-disable-next-line @typescript-eslint/no-var-requires const sodium = require('sodium-native') @@ -201,8 +201,6 @@ export class UserResolver { @Ctx() context: any, ): Promise { email = email.trim().toLowerCase() - // const result = await apiPost(CONFIG.LOGIN_API_URL + 'unsecureLogin', { email, password }) - // UnsecureLogin const loginUserRepository = getCustomRepository(LoginUserRepository) const loginUser = await loginUserRepository.findByEmail(email).catch(() => { throw new Error('No user with this credentials') @@ -440,20 +438,60 @@ export class UserResolver { return 'success' } - @Query(() => SendPasswordResetEmailResponse) - async sendResetPasswordEmail( - @Arg('email') email: string, - ): Promise { - const payload = { - email, - email_text: 7, - email_verification_code_type: 'resetPassword', + @Query(() => Boolean) + async sendResetPasswordEmail(@Arg('email') email: string): Promise { + let emailAlreadySend = false + const EMAIL_OPT_IN_RESET_PASSWORD = 2 + + const loginUser = await LoginUser.findOneOrFail({ email }) + + let optInCode = await LoginEmailOptIn.findOne({ + userId: loginUser.id, + emailOptInTypeId: EMAIL_OPT_IN_RESET_PASSWORD, + }) + if (optInCode) { + emailAlreadySend = true + } else { + optInCode = new LoginEmailOptIn() + optInCode.verificationCode = randomBytes(16).readBigInt64LE() + optInCode.userId = loginUser.id + optInCode.emailOptInTypeId = EMAIL_OPT_IN_RESET_PASSWORD + await optInCode.save() } - const response = await apiPost(CONFIG.LOGIN_API_URL + 'sendEmail', payload) - if (!response.success) { - throw new Error(response.data) + + const link = CONFIG.EMAIL_LINK_SETPASSWORD.replace( + /\$1/g, + optInCode.verificationCode.toString(), + ) + + if (emailAlreadySend) { + const timeElapsed = Date.now() - new Date(optInCode.updatedAt).getTime() + if (timeElapsed < 10 * 60 * 1000) { + throw new Error('email already sent less than a 10 minutes before') + } } - return new SendPasswordResetEmailResponse(response.data) + + const emailSent = await sendEMail({ + from: `Gradido (nicht antworten) <${CONFIG.EMAIL_SENDER}>`, + to: `${loginUser.firstName} ${loginUser.lastName} <${email}>`, + subject: 'Gradido: Reset Password', + text: `Hallo ${loginUser.firstName} ${loginUser.lastName}, + + Du oder jemand anderes hat für dieses Konto ein Zurücksetzen des Passworts angefordert. + Wenn du es warst, klicke bitte auf den Link: ${link} + oder kopiere den obigen Link in Dein Browserfenster. + + Mit freundlichen Grüßen, + dein Gradido-Team`, + }) + + // In case EMails are disabled log the activation link for the user + if (!emailSent) { + // eslint-disable-next-line no-console + console.log(`Reset password link: ${link}`) + } + + return true } @Mutation(() => String) diff --git a/frontend/src/graphql/queries.js b/frontend/src/graphql/queries.js index 01021f601..bf4d07253 100644 --- a/frontend/src/graphql/queries.js +++ b/frontend/src/graphql/queries.js @@ -67,9 +67,7 @@ export const transactionsQuery = gql` export const sendResetPasswordEmail = gql` query($email: String!) { - sendResetPasswordEmail(email: $email) { - state - } + sendResetPasswordEmail(email: $email) } ` From 87714f0089c395f8d8b72eec9b925303353fea83 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 23 Nov 2021 03:05:29 +0100 Subject: [PATCH 003/278] corrected error typo --- backend/src/graphql/resolver/UserResolver.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index ffa78e8aa..9322ffc52 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -467,7 +467,7 @@ export class UserResolver { if (emailAlreadySend) { const timeElapsed = Date.now() - new Date(optInCode.updatedAt).getTime() if (timeElapsed < 10 * 60 * 1000) { - throw new Error('email already sent less than a 10 minutes before') + throw new Error('email already sent less than 10 minutes before') } } From 1802dbf06da9d0074a7dca4a200a8d37bba9c431 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 23 Nov 2021 03:08:43 +0100 Subject: [PATCH 004/278] use correct optin for register --- backend/src/graphql/resolver/UserResolver.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 9322ffc52..05ada134f 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -394,7 +394,7 @@ export class UserResolver { const emailOptIn = new LoginEmailOptIn() emailOptIn.userId = loginUserId emailOptIn.verificationCode = random(64) - emailOptIn.emailOptInTypeId = 2 + emailOptIn.emailOptInTypeId = 1 await queryRunner.manager.save(emailOptIn).catch((error) => { // eslint-disable-next-line no-console From bead60ac7f4010f53c52e1f977a5b57409c06659 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 23 Nov 2021 03:10:34 +0100 Subject: [PATCH 005/278] use correct constants for email optins --- backend/src/graphql/resolver/UserResolver.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 05ada134f..68788f470 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -31,6 +31,9 @@ import { sendEMail } from '../../util/sendEMail' import { LoginElopageBuysRepository } from '../../typeorm/repository/LoginElopageBuys' import { randomBytes } from 'crypto' +const EMAIL_OPT_IN_RESET_PASSWORD = 2 +const EMAIL_OPT_IN_REGISTER = 1 + // eslint-disable-next-line @typescript-eslint/no-var-requires const sodium = require('sodium-native') // eslint-disable-next-line @typescript-eslint/no-var-requires @@ -394,7 +397,7 @@ export class UserResolver { const emailOptIn = new LoginEmailOptIn() emailOptIn.userId = loginUserId emailOptIn.verificationCode = random(64) - emailOptIn.emailOptInTypeId = 1 + emailOptIn.emailOptInTypeId = EMAIL_OPT_IN_REGISTER await queryRunner.manager.save(emailOptIn).catch((error) => { // eslint-disable-next-line no-console @@ -441,7 +444,6 @@ export class UserResolver { @Query(() => Boolean) async sendResetPasswordEmail(@Arg('email') email: string): Promise { let emailAlreadySend = false - const EMAIL_OPT_IN_RESET_PASSWORD = 2 const loginUser = await LoginUser.findOneOrFail({ email }) From a9941faafb752951d047ca8d8f09bb2183d5ec18 Mon Sep 17 00:00:00 2001 From: elweyn Date: Tue, 23 Nov 2021 09:34:54 +0100 Subject: [PATCH 006/278] Added locale for activate email & reset email. --- frontend/src/locales/de.json | 5 +++++ frontend/src/locales/en.json | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index faa61886d..cc3f781ee 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -145,6 +145,11 @@ "text": "Jetzt kannst du ein neues Passwort speichern, mit dem du dich zukünftig in der Gradido-App anmelden kannst." }, "send_now": "Jetzt senden", + "set": "Passwort festsetzen", + "set-password": { + "not-authenticated": "Leider konnten wir dich nicht authentifizieren. Bitte wende dich an den Support.", + "text": "Jetzt kannst du ein neues Passwort speichern, mit dem du dich zukünftig in der Gradido-App anmelden kannst." + }, "subtitle": "Wenn du dein Passwort vergessen hast, kannst du es hier zurücksetzen." } }, diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index 91e25f61d..0598f66ad 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -144,7 +144,12 @@ "not-authenticated": "Unfortunately we could not authenticate you. Please contact the support.", "text": "Now you can save a new password to login to the Gradido-App in the future." }, - "send_now": "Send now", + "send_now": "Jetzt senden", + "set": "Passwort festsetzen", + "set-password": { + "not-authenticated": "Leider konnten wir dich nicht authentifizieren. Bitte wende dich an den Support.", + "text": "Jetzt kannst du ein neues Passwort speichern, mit dem du dich zukünftig in der Gradido-App anmelden kannst." + }, "subtitle": "If you have forgotten your password, you can reset it here." } }, From 3ce3370e80045f9bde028eab6823dd974eaf502f Mon Sep 17 00:00:00 2001 From: elweyn Date: Tue, 23 Nov 2021 09:35:27 +0100 Subject: [PATCH 007/278] Changed the vue test so that we get information of the locale. --- frontend/src/views/Pages/ResetPassword.spec.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/frontend/src/views/Pages/ResetPassword.spec.js b/frontend/src/views/Pages/ResetPassword.spec.js index 81ea7ed0f..fb607708b 100644 --- a/frontend/src/views/Pages/ResetPassword.spec.js +++ b/frontend/src/views/Pages/ResetPassword.spec.js @@ -72,9 +72,7 @@ describe('ResetPassword', () => { it('has a message suggesting to contact the support', () => { expect(wrapper.find('div.header').text()).toContain('settings.password.reset') - expect(wrapper.find('div.header').text()).toContain( - 'settings.password.reset-password.not-authenticated', - ) + expect(wrapper.find('div.header').text()).toContain('settings.password.not-authenticated') }) }) From 7afbc8dc3c1f3cd4b6aaed2247564043864de34e Mon Sep 17 00:00:00 2001 From: elweyn Date: Tue, 23 Nov 2021 09:36:10 +0100 Subject: [PATCH 008/278] Implemented a switch for reset & checkEmail so that both send to ResetPassword.vue but show different textes. --- frontend/src/views/Pages/ResetPassword.vue | 34 ++++++++++++++++++---- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/frontend/src/views/Pages/ResetPassword.vue b/frontend/src/views/Pages/ResetPassword.vue index 81b3d7df7..15c14b5ac 100644 --- a/frontend/src/views/Pages/ResetPassword.vue +++ b/frontend/src/views/Pages/ResetPassword.vue @@ -8,10 +8,10 @@

{{ $t('settings.password.reset') }}

- {{ $t('settings.password.reset-password.text') }} + {{ $t(displaySetup.authenticated) }} - {{ $t('settings.password.reset-password.not-authenticated') }} + {{ $t(displaySetup.notAuthenticated) }}
@@ -29,7 +29,7 @@
- {{ $t('settings.password.reset') }} + {{ $t(displaySetup.button) }}
@@ -38,9 +38,9 @@ - + - {{ $t('back') }} + {{ $t('back') }} @@ -51,6 +51,25 @@ import InputPasswordConfirmation from '../../components/Inputs/InputPasswordConf import { loginViaEmailVerificationCode } from '../../graphql/queries' import { resetPassword } from '../../graphql/mutations' +const textFields = { + reset: { + authenticated: 'settings.password.reset-password.text', + notAuthenticated: 'settings.password.not-authenticated', + button: 'settings.password.reset', + linkTo: '/login', + }, + checkEmail: { + authenticated: 'settings.password.set-password.text', + notAuthenticated: 'settings.password.not-authenticated', + button: 'settings.password.set', + linkTo: '/login', + }, + login: { + headline: 'site.thx.errorTitle', + subtitle: 'site.thx.activateEmail', + }, +} + export default { name: 'ResetPassword', components: { @@ -67,6 +86,7 @@ export default { email: null, pending: true, register: false, + displaySetup: {}, } }, methods: { @@ -111,9 +131,13 @@ export default { loader.hide() this.pending = false }, + setDisplaySetup(from) { + this.displaySetup = textFields[this.$route.params.comingFrom] + }, }, mounted() { this.authenticate() + this.setDisplaySetup() }, } From a1a24d155304f3d05383b793f091d62b85f87634 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 23 Nov 2021 11:24:42 +0100 Subject: [PATCH 009/278] prototype setPassword call --- backend/src/graphql/resolver/UserResolver.ts | 79 +++++++++++++------- 1 file changed, 51 insertions(+), 28 deletions(-) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 68788f470..82de72c0a 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -275,21 +275,6 @@ export class UserResolver { return user } - @Query(() => LoginViaVerificationCode) - async loginViaEmailVerificationCode( - @Arg('optin') optin: string, - ): Promise { - // I cannot use number as type here. - // The value received is not the same as sent by the query - const result = await apiGet( - CONFIG.LOGIN_API_URL + 'loginViaEmailVerificationCode?emailVerificationCode=' + optin, - ) - if (!result.success) { - throw new Error(result.data) - } - return new LoginViaVerificationCode(result.data) - } - @Authorized() @Query(() => String) async logout(): Promise { @@ -468,7 +453,7 @@ export class UserResolver { if (emailAlreadySend) { const timeElapsed = Date.now() - new Date(optInCode.updatedAt).getTime() - if (timeElapsed < 10 * 60 * 1000) { + if (timeElapsed <= 10 * 60 * 1000) { throw new Error('email already sent less than 10 minutes before') } } @@ -513,6 +498,56 @@ export class UserResolver { return 'success' } + @Query(() => CheckEmailResponse) + @UseMiddleware(klicktippRegistrationMiddleware) + async checkEmail(@Arg('optin') optin: string): Promise { + const result = await apiGet( + CONFIG.LOGIN_API_URL + 'loginViaEmailVerificationCode?emailVerificationCode=' + optin, + ) + if (!result.success) { + throw new Error(result.data) + } + return new CheckEmailResponse(result.data) + } + + @Query(() => Boolean) + async setPassword( + @Arg('code') code: string, + @Arg('password') password: string, + ): Promise { + + const optInCode = await LoginEmailOptIn.findOneOrFail({verificationCode: code}).catch(()=>{ + throw new Error('Could not login with emailVerificationCode') + }) + + // Code is only valid for 10minutes + const timeElapsed = Date.now() - new Date(optInCode.updatedAt).getTime() + if (timeElapsed > 10 * 60 * 1000) { + throw new Error('Code is older than 10 minutes') + } + + // load user + const loginUser = await LoginUser.findOneOrFail({id: optInCode.userId}).catch(()=> { + throw new Error('Could not find corresponding User') + }) + + // Activate EMail + loginUser.emailChecked = true + + // Update Password + + // Save loginUser + await loginUser.save() + + // Sign into Klicktipp + if(optInCode.emailOptInTypeId === EMAIL_OPT_IN_REGISTER){ + // TODO + } + + // Delete Code + await optInCode.remove() + } + @Authorized() @Mutation(() => Boolean) async updateUserInfos( @@ -645,18 +680,6 @@ export class UserResolver { return true } - @Query(() => CheckEmailResponse) - @UseMiddleware(klicktippRegistrationMiddleware) - async checkEmail(@Arg('optin') optin: string): Promise { - const result = await apiGet( - CONFIG.LOGIN_API_URL + 'loginViaEmailVerificationCode?emailVerificationCode=' + optin, - ) - if (!result.success) { - throw new Error(result.data) - } - return new CheckEmailResponse(result.data) - } - @Authorized() @Query(() => Boolean) async hasElopage(@Ctx() context: any): Promise { From d1dfda81ce503578a4aee79534eb2455c6444a97 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 23 Nov 2021 12:00:14 +0100 Subject: [PATCH 010/278] removed password from createUser & implement setPassword --- backend/src/graphql/arg/CreateUserArgs.ts | 3 - .../src/graphql/model/CheckEmailResponse.ts | 29 -------- backend/src/graphql/resolver/UserResolver.ts | 69 ++++++++++--------- frontend/src/graphql/queries.js | 9 --- 4 files changed, 37 insertions(+), 73 deletions(-) delete mode 100644 backend/src/graphql/model/CheckEmailResponse.ts diff --git a/backend/src/graphql/arg/CreateUserArgs.ts b/backend/src/graphql/arg/CreateUserArgs.ts index 3d09e56eb..75897e3fc 100644 --- a/backend/src/graphql/arg/CreateUserArgs.ts +++ b/backend/src/graphql/arg/CreateUserArgs.ts @@ -11,9 +11,6 @@ export default class CreateUserArgs { @Field(() => String) lastName: string - @Field(() => String) - password: string - @Field(() => String) language: string diff --git a/backend/src/graphql/model/CheckEmailResponse.ts b/backend/src/graphql/model/CheckEmailResponse.ts deleted file mode 100644 index 948739722..000000000 --- a/backend/src/graphql/model/CheckEmailResponse.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ -/* eslint-disable @typescript-eslint/explicit-module-boundary-types */ -import { ObjectType, Field } from 'type-graphql' - -@ObjectType() -export class CheckEmailResponse { - constructor(json: any) { - this.sessionId = json.session_id - this.email = json.user.email - this.language = json.user.language - this.firstName = json.user.first_name - this.lastName = json.user.last_name - } - - @Field(() => Number) - sessionId: number - - @Field(() => String) - email: string - - @Field(() => String) - firstName: string - - @Field(() => String) - lastName: string - - @Field(() => String) - language: string -} diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 82de72c0a..1c4bc2b50 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -19,7 +19,6 @@ import { klicktippRegistrationMiddleware, klicktippNewsletterStateMiddleware, } from '../../middleware/klicktippMiddleware' -import { CheckEmailResponse } from '../model/CheckEmailResponse' import { UserSettingRepository } from '../../typeorm/repository/UserSettingRepository' import { LoginUserRepository } from '../../typeorm/repository/LoginUser' import { Setting } from '../enum/Setting' @@ -288,7 +287,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; @@ -298,13 +297,6 @@ export class UserResolver { language = DEFAULT_LANGUAGE } - // 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!', - ) - } - // Validate username // TODO: never true const username = '' @@ -322,10 +314,7 @@ export class UserResolver { } const passphrase = PassphraseGenerate() - const keyPair = KeyPairEd25519Create(passphrase) // return pub, priv Key - const passwordHash = SecretKeyCryptographyCreateKey(email, password) // return short and long hash const emailHash = getEmailHash(email) - const encryptedPrivkey = SecretKeyCryptographyEncrypt(keyPair[1], passwordHash[1]) // Table: login_users const loginUser = new LoginUser() @@ -334,13 +323,13 @@ export class UserResolver { loginUser.lastName = lastName loginUser.username = username loginUser.description = '' - loginUser.password = passwordHash[0].readBigUInt64LE() // using the shorthash + // 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 + // loginUser.pubKey = keyPair[0] + // loginUser.privKey = encryptedPrivkey const queryRunner = getConnection().createQueryRunner() await queryRunner.connect() @@ -498,25 +487,12 @@ export class UserResolver { return 'success' } - @Query(() => CheckEmailResponse) - @UseMiddleware(klicktippRegistrationMiddleware) - async checkEmail(@Arg('optin') optin: string): Promise { - const result = await apiGet( - CONFIG.LOGIN_API_URL + 'loginViaEmailVerificationCode?emailVerificationCode=' + optin, - ) - if (!result.success) { - throw new Error(result.data) - } - return new CheckEmailResponse(result.data) - } - @Query(() => Boolean) async setPassword( @Arg('code') code: string, @Arg('password') password: string, ): Promise { - - const optInCode = await LoginEmailOptIn.findOneOrFail({verificationCode: code}).catch(()=>{ + const optInCode = await LoginEmailOptIn.findOneOrFail({ verificationCode: code }).catch(() => { throw new Error('Could not login with emailVerificationCode') }) @@ -527,25 +503,54 @@ export class UserResolver { } // load user - const loginUser = await LoginUser.findOneOrFail({id: optInCode.userId}).catch(()=> { + const loginUser = await LoginUser.findOneOrFail({ id: optInCode.userId }).catch(() => { throw new Error('Could not find corresponding User') }) + const loginUserBackup = await LoginUserBackup.findOneOrFail({ userId: loginUser.id }).catch( + () => { + throw new Error('Could not find corresponding BackupUser') + }, + ) + + const passphrase = loginUserBackup.passphrase.slice(0, -1).split(' ') + if (passphrase.length < PHRASE_WORD_COUNT) { + // TODO if this can happen we cannot recover from that + throw new Error('Could not load a correct passphrase') + } + // Activate EMail loginUser.emailChecked = true + // 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!', + ) + } + // Update Password + const passwordHash = SecretKeyCryptographyCreateKey(loginUser.email, password) // return short and long hash + const keyPair = KeyPairEd25519Create(passphrase) // return pub, priv Key + const encryptedPrivkey = SecretKeyCryptographyEncrypt(keyPair[1], passwordHash[1]) + loginUser.password = passwordHash[0].readBigUInt64LE() // using the shorthash + loginUser.pubKey = keyPair[0] + loginUser.privKey = encryptedPrivkey // Save loginUser + // TODO transaction await loginUser.save() // Sign into Klicktipp - if(optInCode.emailOptInTypeId === EMAIL_OPT_IN_REGISTER){ - // TODO + if (optInCode.emailOptInTypeId === EMAIL_OPT_IN_REGISTER) { + // TODO klicktippRegistrationMiddleware } // Delete Code + // TODO transaction await optInCode.remove() + + return true } @Authorized() diff --git a/frontend/src/graphql/queries.js b/frontend/src/graphql/queries.js index bf4d07253..f1b1ac768 100644 --- a/frontend/src/graphql/queries.js +++ b/frontend/src/graphql/queries.js @@ -95,15 +95,6 @@ export const listGDTEntriesQuery = gql` } ` -export const checkEmailQuery = gql` - query($optin: String!) { - checkEmail(optin: $optin) { - email - sessionId - } - } -` - export const communityInfo = gql` query { getCommunityInfo { From d5b2356caf86b252deb022b15f6a7aef977d7312 Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Tue, 23 Nov 2021 12:08:23 +0100 Subject: [PATCH 011/278] setPassword in frontend remove resetPassword --- backend/src/graphql/resolver/UserResolver.ts | 17 ------------ frontend/src/graphql/mutations.js | 6 ++--- frontend/src/views/Pages/ResetPassword.vue | 28 +++----------------- 3 files changed, 7 insertions(+), 44 deletions(-) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 1c4bc2b50..8057dec15 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -470,23 +470,6 @@ export class UserResolver { return true } - @Mutation(() => String) - async resetPassword( - @Args() - { sessionId, email, password }: ChangePasswordArgs, - ): Promise { - const payload = { - session_id: sessionId, - email, - password, - } - const result = await apiPost(CONFIG.LOGIN_API_URL + 'resetPassword', payload) - if (!result.success) { - throw new Error(result.data) - } - return 'success' - } - @Query(() => Boolean) async setPassword( @Arg('code') code: string, diff --git a/frontend/src/graphql/mutations.js b/frontend/src/graphql/mutations.js index d1d3d583c..eafffd957 100644 --- a/frontend/src/graphql/mutations.js +++ b/frontend/src/graphql/mutations.js @@ -12,9 +12,9 @@ export const unsubscribeNewsletter = gql` } ` -export const resetPassword = gql` - mutation($sessionId: Float!, $email: String!, $password: String!) { - resetPassword(sessionId: $sessionId, email: $email, password: $password) +export const setPassword = gql` + mutation($code: String!, $password: String!) { + setPassword(code: $code, password: $password) } ` diff --git a/frontend/src/views/Pages/ResetPassword.vue b/frontend/src/views/Pages/ResetPassword.vue index 81b3d7df7..11bf88194 100644 --- a/frontend/src/views/Pages/ResetPassword.vue +++ b/frontend/src/views/Pages/ResetPassword.vue @@ -49,7 +49,7 @@ - From 30079e2039794f6002d5a21338b690234c7afb8d Mon Sep 17 00:00:00 2001 From: Ulf Gebhardt Date: Wed, 24 Nov 2021 03:56:42 +0100 Subject: [PATCH 027/278] fix createUser call --- frontend/src/graphql/mutations.js | 4 +--- frontend/src/views/Pages/Register.vue | 18 +++--------------- 2 files changed, 4 insertions(+), 18 deletions(-) diff --git a/frontend/src/graphql/mutations.js b/frontend/src/graphql/mutations.js index eafffd957..0c6ea51aa 100644 --- a/frontend/src/graphql/mutations.js +++ b/frontend/src/graphql/mutations.js @@ -42,12 +42,11 @@ export const updateUserInfos = gql` } ` -export const registerUser = gql` +export const createUser = gql` mutation( $firstName: String! $lastName: String! $email: String! - $password: String! $language: String! $publisherId: Int ) { @@ -55,7 +54,6 @@ export const registerUser = gql` email: $email firstName: $firstName lastName: $lastName - password: $password language: $language publisherId: $publisherId ) diff --git a/frontend/src/views/Pages/Register.vue b/frontend/src/views/Pages/Register.vue index ea4000cff..d6e849345 100755 --- a/frontend/src/views/Pages/Register.vue +++ b/frontend/src/views/Pages/Register.vue @@ -85,10 +85,6 @@
- @@ -158,14 +154,13 @@ From c43b3491f0645e31992faed4ba72b99ef3832d74 Mon Sep 17 00:00:00 2001 From: Hannes Heine Date: Thu, 25 Nov 2021 13:34:13 +0100 Subject: [PATCH 096/278] Created new query for createPendingCreations --- admin/src/graphql/createPendingCreation.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 admin/src/graphql/createPendingCreation.js diff --git a/admin/src/graphql/createPendingCreation.js b/admin/src/graphql/createPendingCreation.js new file mode 100644 index 000000000..a6618e356 --- /dev/null +++ b/admin/src/graphql/createPendingCreation.js @@ -0,0 +1,13 @@ +import gql from 'graphql-tag' + +export const createPendingCreation = gql` + query ($email: String!, $amount: Int!, $note: String!, $creationDate: String!, $moderator: Int!) { + createPendingCreation( + email: $email + amount: $amount + note: $note + creationDate: $creationDate + moderator: $moderator + ) + } +` From 95bdbfefbe738cce7d8bf72a3b2973bfcf04ee93 Mon Sep 17 00:00:00 2001 From: Hannes Heine Date: Thu, 25 Nov 2021 13:35:12 +0100 Subject: [PATCH 097/278] Implemented the apollo createPendingCreation and update rowItem.creations --- admin/src/components/CreationFormular.vue | 27 ++++++++++++++--------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/admin/src/components/CreationFormular.vue b/admin/src/components/CreationFormular.vue index babff9609..0cfcee217 100644 --- a/admin/src/components/CreationFormular.vue +++ b/admin/src/components/CreationFormular.vue @@ -128,6 +128,7 @@ + From b639da68e77371bb9ad9b7c01f017ea4d8c4bffb Mon Sep 17 00:00:00 2001 From: ogerly Date: Fri, 26 Nov 2021 10:07:16 +0100 Subject: [PATCH 113/278] Add CSS Logo img height: 2rem --- admin/src/components/NavBar.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/src/components/NavBar.vue b/admin/src/components/NavBar.vue index 2a58b6f75..ba6bb60ca 100644 --- a/admin/src/components/NavBar.vue +++ b/admin/src/components/NavBar.vue @@ -66,6 +66,6 @@ export default { From 9e45a2168773b1ede494ac99ceb6a7a99af72e26 Mon Sep 17 00:00:00 2001 From: Hannes Heine Date: Fri, 26 Nov 2021 10:59:32 +0100 Subject: [PATCH 114/278] Call Apollo query to get the pendingCreations. --- admin/src/graphql/getPendingCreations.js | 7 +++++++ admin/src/pages/CreationConfirm.vue | 11 +++++++++++ 2 files changed, 18 insertions(+) create mode 100644 admin/src/graphql/getPendingCreations.js diff --git a/admin/src/graphql/getPendingCreations.js b/admin/src/graphql/getPendingCreations.js new file mode 100644 index 000000000..322d46269 --- /dev/null +++ b/admin/src/graphql/getPendingCreations.js @@ -0,0 +1,7 @@ +import gql from 'graphql-tag' + +export const getPendingCreations = gql` + query { + getPendingCreations + } +` diff --git a/admin/src/pages/CreationConfirm.vue b/admin/src/pages/CreationConfirm.vue index 0d68635e0..d035e1b74 100644 --- a/admin/src/pages/CreationConfirm.vue +++ b/admin/src/pages/CreationConfirm.vue @@ -15,6 +15,7 @@ diff --git a/admin/src/store/store.js b/admin/src/store/store.js index 140a92391..9559e3d58 100644 --- a/admin/src/store/store.js +++ b/admin/src/store/store.js @@ -18,6 +18,9 @@ export const mutations = { token: (state, token) => { state.token = token }, + setOpenCreations: (state, openCreations) => { + state.openCreations = openCreations + }, } export const actions = { From 99749eebb2a6459a59844dd4d060aa3b6297054b Mon Sep 17 00:00:00 2001 From: Hannes Heine Date: Fri, 26 Nov 2021 11:28:14 +0100 Subject: [PATCH 116/278] Apollo first steps getPendingCreations. --- admin/src/pages/CreationConfirm.vue | 1 + backend/src/graphql/resolver/AdminResolver.ts | 11 ++++++++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/admin/src/pages/CreationConfirm.vue b/admin/src/pages/CreationConfirm.vue index d035e1b74..5e5078283 100644 --- a/admin/src/pages/CreationConfirm.vue +++ b/admin/src/pages/CreationConfirm.vue @@ -153,6 +153,7 @@ export default { }, }, created() { + this.getPendingCreations() this.$store.commit('resetOpenCreations') this.$store.commit('openCreationsPlus', Object.keys(this.confirmResult).length) }, diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index f08b1a4dc..6b81ce220 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -1,5 +1,5 @@ import { Resolver, Query, Arg, Args, Authorized } from 'type-graphql' -import { getCustomRepository, Raw } from 'typeorm' +import { getCustomRepository, Raw, Any } from 'typeorm' import { UserAdmin } from '../model/UserAdmin' import { LoginUserRepository } from '../../typeorm/repository/LoginUser' import { RIGHTS } from '../../auth/RIGHTS' @@ -7,6 +7,7 @@ import { TransactionCreationRepository } from '../../typeorm/repository/Transact import { PendingCreationRepository } from '../../typeorm/repository/PendingCreation' import { UserRepository } from '../../typeorm/repository/User' import CreatePendingCreationArgs from '../arg/CreatePendingCreationArgs' +import { LoginPendingTasksAdmin } from '@entity/LoginPendingTasksAdmin' import moment from 'moment' @Resolver() @@ -52,6 +53,14 @@ export class AdminResolver { } return await getUserCreations(user.id) } + + @Query(() => String) + async getPendingCreations(): Promise { + const pendingCreationRepository = getCustomRepository(PendingCreationRepository) + const pendingCreations = await pendingCreationRepository.find() + console.log('pendingCreations', pendingCreations) + return pendingCreations.toString() + } } async function getUserCreations(id: number): Promise { From 602dfd64f1edb5ac5ada8ce34c3859ced92c6922 Mon Sep 17 00:00:00 2001 From: Hannes Heine Date: Fri, 26 Nov 2021 12:36:01 +0100 Subject: [PATCH 117/278] Corected return type for getPendingCreations and corected query. --- admin/src/graphql/getPendingCreations.js | 10 +++++- backend/src/graphql/model/PendingCreation.ts | 31 +++++++++++++++++++ backend/src/graphql/resolver/AdminResolver.ts | 25 ++++++++++++--- 3 files changed, 61 insertions(+), 5 deletions(-) create mode 100644 backend/src/graphql/model/PendingCreation.ts diff --git a/admin/src/graphql/getPendingCreations.js b/admin/src/graphql/getPendingCreations.js index 322d46269..c387c368e 100644 --- a/admin/src/graphql/getPendingCreations.js +++ b/admin/src/graphql/getPendingCreations.js @@ -2,6 +2,14 @@ import gql from 'graphql-tag' export const getPendingCreations = gql` query { - getPendingCreations + getPendingCreations { + firstName + lastName + email + amount + note + date + moderator + } } ` diff --git a/backend/src/graphql/model/PendingCreation.ts b/backend/src/graphql/model/PendingCreation.ts new file mode 100644 index 000000000..56bbe6d27 --- /dev/null +++ b/backend/src/graphql/model/PendingCreation.ts @@ -0,0 +1,31 @@ +import { ObjectType, Field, Int } from 'type-graphql' + +@ObjectType() +export class PendingCreation { + @Field(() => String) + firstName: string + + @Field(() => Int) + id?: number + + @Field(() => String) + lastName: string + + @Field(() => Number) + userId: number + + @Field(() => String) + email: string + + @Field(() => Date) + date: Date + + @Field(() => String) + note: string + + @Field(() => Number) + amount: BigInt + + @Field(() => Number) + moderator: number +} diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index 6b81ce220..8dd0293ce 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -1,6 +1,7 @@ import { Resolver, Query, Arg, Args, Authorized } from 'type-graphql' import { getCustomRepository, Raw, Any } from 'typeorm' import { UserAdmin } from '../model/UserAdmin' +import { PendingCreation } from '../model/PendingCreation' import { LoginUserRepository } from '../../typeorm/repository/LoginUser' import { RIGHTS } from '../../auth/RIGHTS' import { TransactionCreationRepository } from '../../typeorm/repository/TransactionCreation' @@ -54,12 +55,28 @@ export class AdminResolver { return await getUserCreations(user.id) } - @Query(() => String) - async getPendingCreations(): Promise { + @Query(() => [PendingCreation]) + async getPendingCreations(): Promise { const pendingCreationRepository = getCustomRepository(PendingCreationRepository) const pendingCreations = await pendingCreationRepository.find() - console.log('pendingCreations', pendingCreations) - return pendingCreations.toString() + + const pendingCreationsPromise = await Promise.all( + pendingCreations.map(async (pendingCreation) => { + const userRepository = getCustomRepository(UserRepository) + const user = await userRepository.findOneOrFail({ id: pendingCreation.userId }) + + const newPendingCreation = { + ...pendingCreation, + firstName: user.firstName, + lastName: user.lastName, + email: user.email, + } + + return newPendingCreation + }), + ) + console.log('pendingCreations', pendingCreationsPromise) + return pendingCreationsPromise } } From 48c0b687d6be249025dc512c12038b7c5fca33a4 Mon Sep 17 00:00:00 2001 From: ogerly Date: Fri, 26 Nov 2021 15:05:49 +0100 Subject: [PATCH 118/278] Query changed to Type PendingCreation, changed the login user search to state user search, adding parameters to PendingCreation object, changed frontend to map the query informations. --- admin/src/graphql/getPendingCreations.js | 1 + admin/src/pages/CreationConfirm.vue | 98 +++---------------- backend/src/graphql/model/PendingCreation.ts | 3 + backend/src/graphql/resolver/AdminResolver.ts | 24 ++--- backend/src/typeorm/repository/User.ts | 13 +++ 5 files changed, 43 insertions(+), 96 deletions(-) diff --git a/admin/src/graphql/getPendingCreations.js b/admin/src/graphql/getPendingCreations.js index c387c368e..f359c79db 100644 --- a/admin/src/graphql/getPendingCreations.js +++ b/admin/src/graphql/getPendingCreations.js @@ -10,6 +10,7 @@ export const getPendingCreations = gql` note date moderator + creation } } ` diff --git a/admin/src/pages/CreationConfirm.vue b/admin/src/pages/CreationConfirm.vue index 5e5078283..660436d6c 100644 --- a/admin/src/pages/CreationConfirm.vue +++ b/admin/src/pages/CreationConfirm.vue @@ -31,98 +31,25 @@ export default { { key: 'firstName', label: 'Vorname' }, { key: 'lastName', label: 'Nachname' }, { - key: 'creation_gdd', + key: 'amount', label: 'Schöpfung', formatter: (value) => { return value + ' GDD' }, }, - { key: 'text', label: 'Text' }, + { key: 'note', label: 'Text' }, { - key: 'creation_date', + key: 'date', label: 'Datum', formatter: (value) => { - return value.long + return this.$moment(value).format('ll') }, }, - { key: 'creation_moderator', label: 'Moderator' }, + { key: 'moderator', label: 'Moderator' }, { key: 'edit_creation', label: 'ändern' }, { key: 'confirm', label: 'speichern' }, ], - confirmResult: [ - { - id: 1, - email: 'dickerson@web.de', - firstName: 'Dickerson', - lastName: 'Macdonald', - creation: '[450,200,700]', - creation_gdd: '1000', - text: 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam ', - - creation_date: { - short: 'November', - long: '22/11/2021', - }, - creation_moderator: 'Manuela Gast', - }, - { - id: 2, - email: 'larsen@woob.de', - firstName: 'Larsen', - lastName: 'Shaw', - creation: '[300,200,1000]', - creation_gdd: '1000', - text: 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam ', - - creation_date: { - short: 'November', - long: '03/11/2021', - }, - creation_moderator: 'Manuela Gast', - }, - { - id: 3, - email: 'geneva@tete.de', - firstName: 'Geneva', - lastName: 'Wilson', - creation: '[350,200,900]', - creation_gdd: '1000', - text: 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam', - creation_date: { - short: 'September', - long: '27/09/2021', - }, - creation_moderator: 'Manuela Gast', - }, - { - id: 4, - email: 'viewrter@asdfvb.com', - firstName: 'Soledare', - lastName: 'Takker', - creation: '[100,400,800]', - creation_gdd: '500', - text: 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo ', - creation_date: { - short: 'Oktober', - long: '12/10/2021', - }, - creation_moderator: 'Evelyn Roller', - }, - { - id: 5, - email: 'dickerson@web.de', - firstName: 'Dickerson', - lastName: 'Macdonald', - creation: '[100,400,800]', - creation_gdd: '200', - text: 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At', - creation_date: { - short: 'September', - long: '05/09/2021', - }, - creation_moderator: 'Manuela Gast', - }, - ], + confirmResult: [], } }, @@ -141,20 +68,21 @@ export default { this.$store.commit('openCreationsMinus', 1) } }, - getPendingCreations() { + async getPendingCreations() { this.$apollo .query({ query: getPendingCreations, }) .then((result) => { - console.log('getPendingCreations.Result', result) + this.confirmResult = result.data.getPendingCreations + }) + .catch((error) => { + this.$toasted.error(error.message) }) - .catch() }, }, - created() { - this.getPendingCreations() - this.$store.commit('resetOpenCreations') + async created() { + await this.getPendingCreations() this.$store.commit('openCreationsPlus', Object.keys(this.confirmResult).length) }, } diff --git a/backend/src/graphql/model/PendingCreation.ts b/backend/src/graphql/model/PendingCreation.ts index 56bbe6d27..aa12bd94b 100644 --- a/backend/src/graphql/model/PendingCreation.ts +++ b/backend/src/graphql/model/PendingCreation.ts @@ -28,4 +28,7 @@ export class PendingCreation { @Field(() => Number) moderator: number + + @Field(() => [Number]) + creation: number[] } diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index 8dd0293ce..3c960b0fa 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -16,19 +16,19 @@ export class AdminResolver { @Authorized([RIGHTS.SEARCH_USERS]) @Query(() => [UserAdmin]) async searchUsers(@Arg('searchText') searchText: string): Promise { - const loginUserRepository = getCustomRepository(LoginUserRepository) - const loginUsers = await loginUserRepository.findBySearchCriteria(searchText) - const users = await Promise.all( - loginUsers.map(async (loginUser) => { - const user = new UserAdmin() - user.firstName = loginUser.firstName - user.lastName = loginUser.lastName - user.email = loginUser.email - user.creation = await getUserCreations(loginUser.id) - return user + const userRepository = getCustomRepository(UserRepository) + const users = await userRepository.findBySearchCriteria(searchText) + const adminUsers = await Promise.all( + users.map(async (user) => { + const adminUser = new UserAdmin() + adminUser.firstName = user.firstName + adminUser.lastName = user.lastName + adminUser.email = user.email + adminUser.creation = await getUserCreations(user.id) + return adminUser }), ) - return users + return adminUsers } @Query(() => [Number]) @@ -38,6 +38,7 @@ export class AdminResolver { const userRepository = getCustomRepository(UserRepository) const user = await userRepository.findByEmail(email) + console.log('User', user) const creations = await getUserCreations(user.id) const creationDateObj = new Date(creationDate) if (isCreationValid(creations, amount, creationDateObj)) { @@ -70,6 +71,7 @@ export class AdminResolver { firstName: user.firstName, lastName: user.lastName, email: user.email, + creation: await getUserCreations(user.id), } return newPendingCreation diff --git a/backend/src/typeorm/repository/User.ts b/backend/src/typeorm/repository/User.ts index e127c179c..cf67c837b 100644 --- a/backend/src/typeorm/repository/User.ts +++ b/backend/src/typeorm/repository/User.ts @@ -30,4 +30,17 @@ export class UserRepository extends Repository { }) return usersIndiced } + + async findBySearchCriteria(searchCriteria: string): Promise { + return await this.createQueryBuilder('user') + .where( + 'user.firstName like :name or user.lastName like :lastName or user.email like :email', + { + name: `%${searchCriteria}%`, + lastName: `%${searchCriteria}%`, + email: `%${searchCriteria}%`, + }, + ) + .getMany() + } } From 18a530b1b129cb270b85ac651a24bcfdb9b17c32 Mon Sep 17 00:00:00 2001 From: ogerly Date: Fri, 26 Nov 2021 15:11:03 +0100 Subject: [PATCH 119/278] Withdrew console.logs. --- backend/src/graphql/resolver/AdminResolver.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index 3c960b0fa..ca903f49b 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -38,7 +38,6 @@ export class AdminResolver { const userRepository = getCustomRepository(UserRepository) const user = await userRepository.findByEmail(email) - console.log('User', user) const creations = await getUserCreations(user.id) const creationDateObj = new Date(creationDate) if (isCreationValid(creations, amount, creationDateObj)) { @@ -77,7 +76,6 @@ export class AdminResolver { return newPendingCreation }), ) - console.log('pendingCreations', pendingCreationsPromise) return pendingCreationsPromise } } From e0ad9ab40a609728127c26ca0597a9f196033c8c Mon Sep 17 00:00:00 2001 From: ogerly Date: Fri, 26 Nov 2021 15:11:46 +0100 Subject: [PATCH 120/278] Removed unused imports. --- backend/src/graphql/resolver/AdminResolver.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index ca903f49b..a93696814 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -1,14 +1,12 @@ import { Resolver, Query, Arg, Args, Authorized } from 'type-graphql' -import { getCustomRepository, Raw, Any } from 'typeorm' +import { getCustomRepository, Raw } from 'typeorm' import { UserAdmin } from '../model/UserAdmin' import { PendingCreation } from '../model/PendingCreation' -import { LoginUserRepository } from '../../typeorm/repository/LoginUser' import { RIGHTS } from '../../auth/RIGHTS' import { TransactionCreationRepository } from '../../typeorm/repository/TransactionCreation' import { PendingCreationRepository } from '../../typeorm/repository/PendingCreation' import { UserRepository } from '../../typeorm/repository/User' import CreatePendingCreationArgs from '../arg/CreatePendingCreationArgs' -import { LoginPendingTasksAdmin } from '@entity/LoginPendingTasksAdmin' import moment from 'moment' @Resolver() From a618ac678e3685c26a83c68a31ab710286368bbb Mon Sep 17 00:00:00 2001 From: ogerly Date: Fri, 26 Nov 2021 15:35:21 +0100 Subject: [PATCH 121/278] Created delete query. --- admin/src/graphql/getPendingCreations.js | 1 + backend/src/graphql/resolver/AdminResolver.ts | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/admin/src/graphql/getPendingCreations.js b/admin/src/graphql/getPendingCreations.js index f359c79db..add9efc29 100644 --- a/admin/src/graphql/getPendingCreations.js +++ b/admin/src/graphql/getPendingCreations.js @@ -3,6 +3,7 @@ import gql from 'graphql-tag' export const getPendingCreations = gql` query { getPendingCreations { + id firstName lastName email diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index a93696814..70f6c35ec 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -8,6 +8,7 @@ import { PendingCreationRepository } from '../../typeorm/repository/PendingCreat import { UserRepository } from '../../typeorm/repository/User' import CreatePendingCreationArgs from '../arg/CreatePendingCreationArgs' import moment from 'moment' +import { LoginPendingTasksAdmin } from '@entity/LoginPendingTasksAdmin' @Resolver() export class AdminResolver { @@ -76,6 +77,15 @@ export class AdminResolver { ) return pendingCreationsPromise } + + @Query(() => Boolean) + async deletePendingCreation(@Arg('id') id: number): Promise { + const pendingCreationRepository = getCustomRepository(PendingCreationRepository) + const entity = await pendingCreationRepository.findOne(id) + if (!entity) throw new Error('Not pending creation with this id.') + const res = await pendingCreationRepository.manager.remove(entity) + return res ? true : false + } } async function getUserCreations(id: number): Promise { From 2f6a1a06300c58bbfa567352bdf632de84a9d367 Mon Sep 17 00:00:00 2001 From: ogerly Date: Fri, 26 Nov 2021 17:43:24 +0100 Subject: [PATCH 122/278] In CreationConfirm.vue number of all open creations and transferred to the store --- admin/src/pages/CreationConfirm.vue | 3 ++- admin/src/pages/Overview.vue | 16 +++++++++++----- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/admin/src/pages/CreationConfirm.vue b/admin/src/pages/CreationConfirm.vue index 660436d6c..c44402a1e 100644 --- a/admin/src/pages/CreationConfirm.vue +++ b/admin/src/pages/CreationConfirm.vue @@ -75,6 +75,8 @@ export default { }) .then((result) => { this.confirmResult = result.data.getPendingCreations + this.$store.commit('resetOpenCreations') + this.$store.commit('openCreationsPlus', Object.keys(this.confirmResult).length) }) .catch((error) => { this.$toasted.error(error.message) @@ -83,7 +85,6 @@ export default { }, async created() { await this.getPendingCreations() - this.$store.commit('openCreationsPlus', Object.keys(this.confirmResult).length) }, } diff --git a/admin/src/pages/Overview.vue b/admin/src/pages/Overview.vue index d63c46199..329843cad 100644 --- a/admin/src/pages/Overview.vue +++ b/admin/src/pages/Overview.vue @@ -76,21 +76,27 @@ From f2c31b7d6837ef22e9c79a65d1d4f60323c3a724 Mon Sep 17 00:00:00 2001 From: ogerly Date: Fri, 26 Nov 2021 17:49:29 +0100 Subject: [PATCH 124/278] pendingCreationRepository.manager.remove res - fix prettier --- backend/src/graphql/resolver/AdminResolver.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index 70f6c35ec..5d2ed47a2 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -84,7 +84,7 @@ export class AdminResolver { const entity = await pendingCreationRepository.findOne(id) if (!entity) throw new Error('Not pending creation with this id.') const res = await pendingCreationRepository.manager.remove(entity) - return res ? true : false + return !!res } } From 30ba6e473b176d02614a6360e93cd8cc854b7f7a Mon Sep 17 00:00:00 2001 From: ogerly Date: Fri, 26 Nov 2021 18:02:18 +0100 Subject: [PATCH 125/278] chnaged simpler counting, number of open creations --- admin/src/pages/CreationConfirm.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/src/pages/CreationConfirm.vue b/admin/src/pages/CreationConfirm.vue index c44402a1e..1b53dc85b 100644 --- a/admin/src/pages/CreationConfirm.vue +++ b/admin/src/pages/CreationConfirm.vue @@ -76,7 +76,7 @@ export default { .then((result) => { this.confirmResult = result.data.getPendingCreations this.$store.commit('resetOpenCreations') - this.$store.commit('openCreationsPlus', Object.keys(this.confirmResult).length) + this.$store.commit('openCreationsPlus', result.data.getPendingCreations.length) }) .catch((error) => { this.$toasted.error(error.message) From 38da2dcdfd34d7b4331a4593849dffdeee2cbdaa Mon Sep 17 00:00:00 2001 From: ogerly Date: Fri, 26 Nov 2021 18:09:10 +0100 Subject: [PATCH 126/278] Remove hint text for test creations on CreationConfirm Table. --- admin/src/pages/CreationConfirm.vue | 4 ---- 1 file changed, 4 deletions(-) diff --git a/admin/src/pages/CreationConfirm.vue b/admin/src/pages/CreationConfirm.vue index 1b53dc85b..ec0e6e7af 100644 --- a/admin/src/pages/CreationConfirm.vue +++ b/admin/src/pages/CreationConfirm.vue @@ -1,9 +1,5 @@