From 1cb8b185ac8786f4386305af61d756eb6a8e4427 Mon Sep 17 00:00:00 2001 From: elweyn Date: Thu, 18 Nov 2021 09:14:02 +0100 Subject: [PATCH 01/74] 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 02/74] 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 03/74] 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 04/74] 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 05/74] 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 06/74] 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 07/74] 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 08/74] 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 09/74] 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 10/74] 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 11/74] 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 27/74] 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 @@ diff --git a/frontend/src/views/Pages/ResetPassword.vue b/frontend/src/views/Pages/ResetPassword.vue index 8dc7ee5bc..a4d06a914 100644 --- a/frontend/src/views/Pages/ResetPassword.vue +++ b/frontend/src/views/Pages/ResetPassword.vue @@ -77,6 +77,7 @@ export default { password: '', passwordRepeat: '', }, + displaySetup: {}, } }, methods: { @@ -94,20 +95,29 @@ export default { this.$router.push('/thx/reset') }) .catch((error) => { - this.$toasted.error(error.message) + if (error.message.includes('Code is older than 10 minutes')) { + this.$toasted.error(error.message) + this.$router.push('/password/reset') + } else { + this.$toasted.error(error.message) + } }) }, async authenticate() { // TODO validate somehow if present and looks good? // const optin = this.$route.params.optin }, - setDisplaySetup(from) { - this.displaySetup = textFields[this.$route.params.comingFrom] + setDisplaySetup() { + if (!this.$route.params.comingFrom) { + this.displaySetup = textFields.reset + } else { + this.displaySetup = textFields[this.$route.params.comingFrom] + } }, }, - async mounted() { - await this.authenticate() + created() { this.setDisplaySetup() + // await this.authenticate() }, } From 03faac6ecbc4d6d1c3f56eb5349fd9dac00dfb70 Mon Sep 17 00:00:00 2001 From: elweyn Date: Tue, 7 Dec 2021 10:14:52 +0100 Subject: [PATCH 54/74] Case where a user has not activated his email he gets redirected to /thx/login with a message to check his eamils. --- frontend/src/routes/routes.js | 2 +- frontend/src/views/Pages/ForgotPassword.vue | 1 - frontend/src/views/Pages/Login.vue | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/frontend/src/routes/routes.js b/frontend/src/routes/routes.js index 26f21f9cf..418422997 100755 --- a/frontend/src/routes/routes.js +++ b/frontend/src/routes/routes.js @@ -50,7 +50,7 @@ const routes = [ path: '/thx/:comingFrom', component: () => import('../views/Pages/thx.vue'), beforeEnter: (to, from, next) => { - const validFrom = ['password', 'reset', 'register', 'login'] + const validFrom = ['password', 'reset', 'register', 'login', 'Login'] if (!validFrom.includes(from.path.split('/')[1])) { next({ path: '/login' }) } else { diff --git a/frontend/src/views/Pages/ForgotPassword.vue b/frontend/src/views/Pages/ForgotPassword.vue index c27afae6a..c8b31246f 100644 --- a/frontend/src/views/Pages/ForgotPassword.vue +++ b/frontend/src/views/Pages/ForgotPassword.vue @@ -88,7 +88,6 @@ export default { }, }, created() { - console.log('comingFrom', this.$route.params.comingFrom) if (this.$route.params.comingFrom) { this.displaySetup = textFields[this.$route.params.comingFrom] } else { diff --git a/frontend/src/views/Pages/Login.vue b/frontend/src/views/Pages/Login.vue index 45e700099..5f86b1600 100755 --- a/frontend/src/views/Pages/Login.vue +++ b/frontend/src/views/Pages/Login.vue @@ -105,11 +105,11 @@ export default { loader.hide() }) .catch((error) => { - if (!error.message.includes('user email not validated')) { + if (!error.message.includes('User email not validated')) { this.$toasted.error(this.$t('error.no-account')) } else { // : this.$t('error.no-email-verify') - this.$router.push('/thx/login') + this.$router.push('/reset/login') } loader.hide() }) From c7fbb9b0bf4bb7b4ba70276c10f7cbcc231e4c73 Mon Sep 17 00:00:00 2001 From: elweyn Date: Tue, 7 Dec 2021 10:19:29 +0100 Subject: [PATCH 55/74] Changed the Login error handling so that we get the no-account message in case of a specific error, else we send the user to /reset/login --- backend/src/graphql/resolver/UserResolver.ts | 1 - frontend/src/views/Pages/Login.vue | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 9856e1968..bebc32e1e 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -199,7 +199,6 @@ export class UserResolver { throw new Error('No user with this credentials') }) if (!loginUser.emailChecked) { - // TODO we want to catch this on the frontend and ask the user to check his emails or resend code throw new Error('User email not validated') } if (loginUser.password === BigInt(0)) { diff --git a/frontend/src/views/Pages/Login.vue b/frontend/src/views/Pages/Login.vue index 5f86b1600..0ce209551 100755 --- a/frontend/src/views/Pages/Login.vue +++ b/frontend/src/views/Pages/Login.vue @@ -105,7 +105,7 @@ export default { loader.hide() }) .catch((error) => { - if (!error.message.includes('User email not validated')) { + if (error.message.includes('No user with this credentials')) { this.$toasted.error(this.$t('error.no-account')) } else { // : this.$t('error.no-email-verify') From ca6f8076d6f5a7b6319de25fe719ad2150b3749e Mon Sep 17 00:00:00 2001 From: elweyn Date: Tue, 7 Dec 2021 10:41:43 +0100 Subject: [PATCH 56/74] Logic change on error message included in test. --- frontend/src/views/Pages/Login.spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/views/Pages/Login.spec.js b/frontend/src/views/Pages/Login.spec.js index 53bb9446f..a16a8ad54 100644 --- a/frontend/src/views/Pages/Login.spec.js +++ b/frontend/src/views/Pages/Login.spec.js @@ -238,7 +238,7 @@ describe('Login', () => { describe('login fails', () => { beforeEach(() => { apolloQueryMock.mockRejectedValue({ - message: 'Ouch!', + message: '..No user with this credentials', }) }) From 4b49d85d1aa387a10130984b49c2f3578673e7ce Mon Sep 17 00:00:00 2001 From: elweyn Date: Tue, 7 Dec 2021 10:44:24 +0100 Subject: [PATCH 57/74] Router got a new route test had to be fixed. --- frontend/src/routes/router.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/routes/router.test.js b/frontend/src/routes/router.test.js index 12c028fba..a85c7a291 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 fifteen routes defined', () => { - expect(routes).toHaveLength(15) + it('has sixteen routes defined', () => { + expect(routes).toHaveLength(16) }) describe('overview', () => { From cee7c66a45ff66068685251a2e09ee02f6458fcf Mon Sep 17 00:00:00 2001 From: elweyn Date: Tue, 7 Dec 2021 10:59:00 +0100 Subject: [PATCH 58/74] ForgotPassword logic change implemented in tests. --- .../src/views/Pages/ForgotPassword.spec.js | 68 ++++++++++++++----- 1 file changed, 50 insertions(+), 18 deletions(-) diff --git a/frontend/src/views/Pages/ForgotPassword.spec.js b/frontend/src/views/Pages/ForgotPassword.spec.js index 91247d8a6..c77689425 100644 --- a/frontend/src/views/Pages/ForgotPassword.spec.js +++ b/frontend/src/views/Pages/ForgotPassword.spec.js @@ -8,30 +8,52 @@ const localVue = global.localVue const mockRouterPush = jest.fn() + +const mocks = { + $t: jest.fn((t) => t), + $router: { + push: mockRouterPush, + }, + $apollo: { + query: mockAPIcall, + }, +} + +const stubs = { + RouterLink: RouterLinkStub, +} + +const createMockObject = (comingFrom) => { + return { + localVue, + mocks: { + $t: jest.fn((t) => t), + $router: { + push: mockRouterPush, + }, + $apollo: { + query: mockAPIcall, + }, + $route: { + params: { + comingFrom, + }, + }, + }, + stubs, + } +} + describe('ForgotPassword', () => { let wrapper - const mocks = { - $t: jest.fn((t) => t), - $router: { - push: mockRouterPush, - }, - $apollo: { - query: mockAPIcall, - }, - } - - const stubs = { - RouterLink: RouterLinkStub, - } - - const Wrapper = () => { - return mount(ForgotPassword, { localVue, mocks, stubs }) + const Wrapper = (functionN) => { + return mount(ForgotPassword, functionN) } describe('mount', () => { beforeEach(() => { - wrapper = Wrapper() + wrapper = Wrapper(createMockObject()) }) it('renders the component', () => { @@ -41,7 +63,7 @@ describe('ForgotPassword', () => { it('has a title', () => { expect(wrapper.find('h1').text()).toEqual('settings.password.reset') }) - + it('has a subtitle', () => { expect(wrapper.find('p.text-lead').text()).toEqual('settings.password.subtitle') }) @@ -144,5 +166,15 @@ describe('ForgotPassword', () => { }) }) }) + + describe('comingFrom login', () => { + beforeEach(() => { + wrapper = Wrapper(createMockObject('reset')) + }) + + it('has another subtitle', () => { + expect(wrapper.find('p.text-lead').text()).toEqual('settings.password.resend_subtitle') + }) + }) }) }) From 28e4fa1bda86db3b84ae4f443d7abfc58b380cd0 Mon Sep 17 00:00:00 2001 From: einhornimmond Date: Tue, 7 Dec 2021 11:41:01 +0100 Subject: [PATCH 59/74] fix message --- login_server/src/cpp/model/gradido/Transaction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/login_server/src/cpp/model/gradido/Transaction.cpp b/login_server/src/cpp/model/gradido/Transaction.cpp index a1fd5790c..ac1c2d088 100644 --- a/login_server/src/cpp/model/gradido/Transaction.cpp +++ b/login_server/src/cpp/model/gradido/Transaction.cpp @@ -491,7 +491,7 @@ namespace model { break; case TRANSACTION_VALID_INVALID_TARGET_DATE: error_name = t->gettext_str("Creation Error"); - error_description = t->gettext_str("Invalid target date! No future and only 3 month in the past."); + error_description = t->gettext_str("Invalid target date! No future and only 2 month in the past."); break; case TRANSACTION_VALID_CREATION_OUT_OF_BORDER: error_name = t->gettext_str("Creation Error"); From 202ab2863ce5915e0409b692b96a49b6d3666860 Mon Sep 17 00:00:00 2001 From: elweyn Date: Tue, 7 Dec 2021 12:28:12 +0100 Subject: [PATCH 60/74] Fixing ResetPassword. --- .../src/views/Pages/ResetPassword.spec.js | 167 +++++++++--------- frontend/src/views/Pages/ResetPassword.vue | 8 +- 2 files changed, 90 insertions(+), 85 deletions(-) diff --git a/frontend/src/views/Pages/ResetPassword.spec.js b/frontend/src/views/Pages/ResetPassword.spec.js index 91306b854..36a2f169c 100644 --- a/frontend/src/views/Pages/ResetPassword.spec.js +++ b/frontend/src/views/Pages/ResetPassword.spec.js @@ -6,59 +6,58 @@ import flushPromises from 'flush-promises' const localVue = global.localVue -const apolloQueryMock = jest.fn().mockRejectedValue({ message: 'error' }) const apolloMutationMock = jest.fn() const toasterMock = jest.fn() const routerPushMock = jest.fn() +const stubs = { + RouterLink: RouterLinkStub, +} + +const createMockObject = (comingFrom) => { + return { + localVue, + mocks: { + $i18n: { + locale: 'en', + }, + $t: jest.fn((t) => t), + $route: { + params: { + optin: '123', + comingFrom, + }, + }, + $toasted: { + error: toasterMock, + }, + $router: { + push: routerPushMock, + }, + $loading: { + show: jest.fn(() => { + return { hide: jest.fn() } + }), + }, + $apollo: { + mutate: apolloMutationMock, + }, + }, + stubs, + } +} + describe('ResetPassword', () => { let wrapper - const mocks = { - $i18n: { - locale: 'en', - }, - $t: jest.fn((t) => t), - $route: { - params: { - optin: '123', - }, - }, - $toasted: { - error: toasterMock, - }, - $router: { - push: routerPushMock, - }, - $loading: { - show: jest.fn(() => { - return { hide: jest.fn() } - }), - }, - $apollo: { - mutate: apolloMutationMock, - query: apolloQueryMock, - }, - } - - const stubs = { - RouterLink: RouterLinkStub, - } - - const Wrapper = () => { - return mount(ResetPassword, { localVue, mocks, stubs }) + const Wrapper = (functionName) => { + return mount(ResetPassword, functionName) } describe('mount', () => { beforeEach(() => { - wrapper = Wrapper() - }) - - it.skip('calls the email verification when created', async () => { - expect(apolloQueryMock).toBeCalledWith( - expect.objectContaining({ variables: { optin: '123' } }), - ) + wrapper = Wrapper(createMockObject()) }) describe('No valid optin', () => { @@ -77,28 +76,12 @@ describe('ResetPassword', () => { }) describe('is authenticated', () => { - beforeEach(() => { - apolloQueryMock.mockResolvedValue({ - data: { - loginViaEmailVerificationCode: { - sessionId: 1, - email: 'user@example.org', - }, - }, - }) - }) - - it.skip('Has sessionId from API call', async () => { - await wrapper.vm.$nextTick() - expect(wrapper.vm.sessionId).toBe(1) - }) - - it.skip('renders the Reset Password form when authenticated', () => { + it('renders the Reset Password form when authenticated', () => { expect(wrapper.find('div.resetpwd-form').exists()).toBeTruthy() }) describe('Register header', () => { - it.skip('has a welcome message', async () => { + it('has a welcome message', async () => { expect(wrapper.find('div.header').text()).toContain('settings.password.reset') expect(wrapper.find('div.header').text()).toContain( 'settings.password.reset-password.text', @@ -107,31 +90,31 @@ describe('ResetPassword', () => { }) describe('links', () => { - it.skip('has a link "Back"', async () => { + it('has a link "Back"', async () => { expect(wrapper.findAllComponents(RouterLinkStub).at(0).text()).toEqual('back') }) - it.skip('links to /login when clicking "Back"', async () => { - expect(wrapper.findAllComponents(RouterLinkStub).at(0).props().to).toBe('/Login') + it('links to /login when clicking "Back"', async () => { + expect(wrapper.findAllComponents(RouterLinkStub).at(0).props().to).toBe('/login') }) }) describe('reset password form', () => { - it.skip('has a register form', async () => { + it('has a register form', async () => { expect(wrapper.find('form').exists()).toBeTruthy() }) - it.skip('has 2 password input fields', async () => { + it('has 2 password input fields', async () => { expect(wrapper.findAll('input[type="password"]').length).toBe(2) }) - it.skip('toggles the first input field to text when eye icon is clicked', async () => { - wrapper.findAll('button').at(0).trigger('click') + it('toggles the first input field to text when eye icon is clicked', async () => { + await wrapper.findAll('button').at(0).trigger('click') await wrapper.vm.$nextTick() expect(wrapper.findAll('input').at(0).attributes('type')).toBe('text') }) - it.skip('toggles the second input field to text when eye icon is clicked', async () => { + it('toggles the second input field to text when eye icon is clicked', async () => { wrapper.findAll('button').at(1).trigger('click') await wrapper.vm.$nextTick() expect(wrapper.findAll('input').at(1).attributes('type')).toBe('text') @@ -140,44 +123,68 @@ describe('ResetPassword', () => { describe('submit form', () => { beforeEach(async () => { - await wrapper.setData({ authenticated: true, sessionId: 1 }) - await wrapper.vm.$nextTick() + // wrapper = Wrapper(createMockObject()) await wrapper.findAll('input').at(0).setValue('Aa123456_') await wrapper.findAll('input').at(1).setValue('Aa123456_') await flushPromises() - await wrapper.find('form').trigger('submit') }) - describe('server response with error', () => { - beforeEach(() => { - apolloMutationMock.mockRejectedValue({ message: 'error' }) + describe('server response with error code > 10min', () => { + beforeEach(async () => { + jest.clearAllMocks() + apolloMutationMock.mockRejectedValue({ message: '...Code is older than 10 minutes' }) + await wrapper.find('form').trigger('submit') + await flushPromises() }) - it.skip('toasts an error message', () => { - expect(toasterMock).toHaveBeenCalledWith('error') + + it('toasts an error message', () => { + expect(toasterMock).toHaveBeenCalledWith('...Code is older than 10 minutes') + }) + + it('router pushes to /password/reset', () => { + expect(routerPushMock).toHaveBeenCalledWith('/password/reset') + }) + }) + + describe('server response with error code > 10min', () => { + beforeEach(async () => { + jest.clearAllMocks() + apolloMutationMock.mockRejectedValueOnce({ message: 'Error' }) + await wrapper.find('form').trigger('submit') + await flushPromises() + }) + + it('toasts an error message', () => { + expect(toasterMock).toHaveBeenCalledWith('Error') }) }) describe('server response with success', () => { - beforeEach(() => { + beforeEach(async () => { apolloMutationMock.mockResolvedValue({ data: { resetPassword: 'success', }, }) + wrapper = Wrapper(createMockObject('checkEmail')) + await wrapper.findAll('input').at(0).setValue('Aa123456_') + await wrapper.findAll('input').at(1).setValue('Aa123456_') + await wrapper.find('form').trigger('submit') + await flushPromises() }) - it.skip('calls the API', () => { + + it('calls the API', () => { expect(apolloMutationMock).toBeCalledWith( expect.objectContaining({ variables: { - sessionId: 1, - email: 'user@example.org', + code: '123', password: 'Aa123456_', }, }), ) }) - it.skip('redirects to "/thx/reset"', () => { + it('redirects to "/thx/reset"', () => { expect(routerPushMock).toHaveBeenCalledWith('/thx/reset') }) }) diff --git a/frontend/src/views/Pages/ResetPassword.vue b/frontend/src/views/Pages/ResetPassword.vue index a4d06a914..9ee3a2fa6 100644 --- a/frontend/src/views/Pages/ResetPassword.vue +++ b/frontend/src/views/Pages/ResetPassword.vue @@ -82,6 +82,7 @@ export default { }, methods: { async onSubmit() { + console.log('OnSubmit', this.$route.params.optin, this.form.password) this.$apollo .mutate({ mutation: setPassword, @@ -91,10 +92,12 @@ export default { }, }) .then(() => { + console.log('then') this.form.password = '' this.$router.push('/thx/reset') }) .catch((error) => { + console.log('catch', error.message) if (error.message.includes('Code is older than 10 minutes')) { this.$toasted.error(error.message) this.$router.push('/password/reset') @@ -103,10 +106,6 @@ export default { } }) }, - async authenticate() { - // TODO validate somehow if present and looks good? - // const optin = this.$route.params.optin - }, setDisplaySetup() { if (!this.$route.params.comingFrom) { this.displaySetup = textFields.reset @@ -117,7 +116,6 @@ export default { }, created() { this.setDisplaySetup() - // await this.authenticate() }, } From 4afd3ffe0a76d7821b20f639052df6b3fae2ae58 Mon Sep 17 00:00:00 2001 From: elweyn Date: Tue, 7 Dec 2021 12:34:10 +0100 Subject: [PATCH 61/74] Remove console.log coverage of frontend set to 86% --- .github/workflows/test.yml | 2 +- frontend/src/views/Pages/ForgotPassword.spec.js | 13 +------------ frontend/src/views/Pages/ResetPassword.vue | 3 --- 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 470b3efbb..2996ffeec 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -399,7 +399,7 @@ jobs: report_name: Coverage Frontend type: lcov result_path: ./coverage/lcov.info - min_coverage: 84 + min_coverage: 86 token: ${{ github.token }} ############################################################################## diff --git a/frontend/src/views/Pages/ForgotPassword.spec.js b/frontend/src/views/Pages/ForgotPassword.spec.js index c77689425..47c9fad56 100644 --- a/frontend/src/views/Pages/ForgotPassword.spec.js +++ b/frontend/src/views/Pages/ForgotPassword.spec.js @@ -8,17 +8,6 @@ const localVue = global.localVue const mockRouterPush = jest.fn() - -const mocks = { - $t: jest.fn((t) => t), - $router: { - push: mockRouterPush, - }, - $apollo: { - query: mockAPIcall, - }, -} - const stubs = { RouterLink: RouterLinkStub, } @@ -63,7 +52,7 @@ describe('ForgotPassword', () => { it('has a title', () => { expect(wrapper.find('h1').text()).toEqual('settings.password.reset') }) - + it('has a subtitle', () => { expect(wrapper.find('p.text-lead').text()).toEqual('settings.password.subtitle') }) diff --git a/frontend/src/views/Pages/ResetPassword.vue b/frontend/src/views/Pages/ResetPassword.vue index 9ee3a2fa6..478a8db8c 100644 --- a/frontend/src/views/Pages/ResetPassword.vue +++ b/frontend/src/views/Pages/ResetPassword.vue @@ -82,7 +82,6 @@ export default { }, methods: { async onSubmit() { - console.log('OnSubmit', this.$route.params.optin, this.form.password) this.$apollo .mutate({ mutation: setPassword, @@ -92,12 +91,10 @@ export default { }, }) .then(() => { - console.log('then') this.form.password = '' this.$router.push('/thx/reset') }) .catch((error) => { - console.log('catch', error.message) if (error.message.includes('Code is older than 10 minutes')) { this.$toasted.error(error.message) this.$router.push('/password/reset') From 64adf1ddbb8469af3149f7cd41df6b719f3762d3 Mon Sep 17 00:00:00 2001 From: Hannes Heine Date: Tue, 7 Dec 2021 13:21:51 +0100 Subject: [PATCH 62/74] Upgrade backend coverage to 37% --- .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 2996ffeec..d5b02cc76 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -491,7 +491,7 @@ jobs: report_name: Coverage Backend type: lcov result_path: ./backend/coverage/lcov.info - min_coverage: 36 + min_coverage: 37 token: ${{ github.token }} ############################################################################## From 10df58071a865cb64a6496ac3bcfb53a2a5df40a Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 7 Dec 2021 13:57:50 +0100 Subject: [PATCH 63/74] fix: Pending Creations are Updated Without Page Reload --- admin/src/pages/CreationConfirm.vue | 1 + admin/src/pages/Overview.vue | 1 + 2 files changed, 2 insertions(+) diff --git a/admin/src/pages/CreationConfirm.vue b/admin/src/pages/CreationConfirm.vue index 42ff6da50..0f180ffbc 100644 --- a/admin/src/pages/CreationConfirm.vue +++ b/admin/src/pages/CreationConfirm.vue @@ -76,6 +76,7 @@ export default { this.$apollo .query({ query: getPendingCreations, + fetchPolicy: 'network-only', }) .then((result) => { this.$store.commit('resetOpenCreations') diff --git a/admin/src/pages/Overview.vue b/admin/src/pages/Overview.vue index f45f588e5..524e03f07 100644 --- a/admin/src/pages/Overview.vue +++ b/admin/src/pages/Overview.vue @@ -62,6 +62,7 @@ export default { this.$apollo .query({ query: getPendingCreations, + fetchPolicy: 'network-only', }) .then((result) => { this.$store.commit('setOpenCreations', result.data.getPendingCreations.length) From 165ed1801ba1aba862d0b0006d8c17e322c4b7ff Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 7 Dec 2021 18:00:59 +0100 Subject: [PATCH 64/74] update jest, install transform-require-context --- frontend/babel.config.js | 1 + frontend/jest.config.js | 1 + frontend/package.json | 4 +- frontend/src/main.js | 35 +- frontend/src/plugins/apolloProvider.js | 37 + frontend/src/plugins/apolloProvider.test.js | 116 +++ frontend/yarn.lock | 889 ++++++++++++++++---- 7 files changed, 864 insertions(+), 219 deletions(-) create mode 100644 frontend/src/plugins/apolloProvider.js create mode 100644 frontend/src/plugins/apolloProvider.test.js diff --git a/frontend/babel.config.js b/frontend/babel.config.js index 5907ab074..7acdca661 100644 --- a/frontend/babel.config.js +++ b/frontend/babel.config.js @@ -1,6 +1,7 @@ module.exports = { presets: ['@babel/preset-env'], plugins: [ + 'transform-require-context', [ 'component', { diff --git a/frontend/jest.config.js b/frontend/jest.config.js index 774aa6bf9..5caae815c 100644 --- a/frontend/jest.config.js +++ b/frontend/jest.config.js @@ -22,4 +22,5 @@ module.exports = { testMatch: ['**/?(*.)+(spec|test).js?(x)'], // snapshotSerializers: ['jest-serializer-vue'], transformIgnorePatterns: ['/node_modules/(?!vee-validate/dist/rules)'], + testEnvironment: 'jest-environment-jsdom-sixteen', } diff --git a/frontend/package.json b/frontend/package.json index e50c5fe89..86b127676 100755 --- a/frontend/package.json +++ b/frontend/package.json @@ -22,8 +22,9 @@ "apollo-boost": "^0.4.9", "axios": "^0.21.1", "babel-core": "^7.0.0-bridge.0", - "babel-jest": "^26.6.3", + "babel-jest": "^27.3.1", "babel-plugin-require-context-hook": "^1.0.0", + "babel-plugin-transform-require-context": "^0.1.1", "babel-preset-vue": "^2.0.2", "bootstrap": "4.3.1", "bootstrap-vue": "^2.5.0", @@ -51,6 +52,7 @@ "identity-obj-proxy": "^3.0.0", "jest": "^26.6.3", "jest-canvas-mock": "^2.3.1", + "jest-environment-jsdom-sixteen": "^2.0.0", "nouislider": "^12.1.0", "particles-bg-vue": "1.2.3", "perfect-scrollbar": "^1.3.0", diff --git a/frontend/src/main.js b/frontend/src/main.js index 1aa945608..75dfdcedb 100755 --- a/frontend/src/main.js +++ b/frontend/src/main.js @@ -3,9 +3,6 @@ import DashboardPlugin from './plugins/dashboard-plugin' import App from './App.vue' import i18n from './i18n.js' import { loadAllRules } from './validation-rules' -import { ApolloClient, ApolloLink, InMemoryCache, HttpLink } from 'apollo-boost' -import VueApollo from 'vue-apollo' -import CONFIG from './config' import addNavigationGuards from './routes/guards' @@ -13,37 +10,7 @@ import { store } from './store/store' import router from './routes/router' -const httpLink = new HttpLink({ uri: CONFIG.GRAPHQL_URI }) - -const authLink = new ApolloLink((operation, forward) => { - const token = store.state.token - operation.setContext({ - headers: { - Authorization: token && token.length > 0 ? `Bearer ${token}` : '', - }, - }) - return forward(operation).map((response) => { - if (response.errors && response.errors[0].message === '403.13 - Client certificate revoked') { - response.errors[0].message = i18n.t('error.session-expired') - store.dispatch('logout', null) - if (router.currentRoute.path !== '/login') router.push('/login') - return response - } - const newToken = operation.getContext().response.headers.get('token') - if (newToken) store.commit('token', newToken) - return response - }) -}) - -const apolloClient = new ApolloClient({ - link: authLink.concat(httpLink), - cache: new InMemoryCache(), - uri: CONFIG.GRAPHQL_URI, -}) - -const apolloProvider = new VueApollo({ - defaultClient: apolloClient, -}) +import { apolloProvider } from './plugins/apolloProvider' // plugin setup Vue.use(DashboardPlugin) diff --git a/frontend/src/plugins/apolloProvider.js b/frontend/src/plugins/apolloProvider.js new file mode 100644 index 000000000..73452e5ba --- /dev/null +++ b/frontend/src/plugins/apolloProvider.js @@ -0,0 +1,37 @@ +import { ApolloClient, ApolloLink, InMemoryCache, HttpLink } from 'apollo-boost' +import VueApollo from 'vue-apollo' +import CONFIG from '../config' +import { store } from '../store/store' +import router from '../routes/router' +import i18n from '../i18n' + +const httpLink = new HttpLink({ uri: CONFIG.GRAPHQL_URI }) + +const authLink = new ApolloLink((operation, forward) => { + const token = store.state.token + operation.setContext({ + headers: { + Authorization: token && token.length > 0 ? `Bearer ${token}` : '', + }, + }) + return forward(operation).map((response) => { + if (response.errors && response.errors[0].message === '403.13 - Client certificate revoked') { + response.errors[0].message = i18n.t('error.session-expired') + store.dispatch('logout', null) + if (router.currentRoute.path !== '/login') router.push('/login') + return response + } + const newToken = operation.getContext().response.headers.get('token') + if (newToken) store.commit('token', newToken) + return response + }) +}) + +const apolloClient = new ApolloClient({ + link: authLink.concat(httpLink), + cache: new InMemoryCache(), +}) + +export const apolloProvider = new VueApollo({ + defaultClient: apolloClient, +}) diff --git a/frontend/src/plugins/apolloProvider.test.js b/frontend/src/plugins/apolloProvider.test.js new file mode 100644 index 000000000..75a7045ea --- /dev/null +++ b/frontend/src/plugins/apolloProvider.test.js @@ -0,0 +1,116 @@ +import { ApolloClient, ApolloLink, InMemoryCache, HttpLink } from 'apollo-boost' +import './apolloProvider' +import CONFIG from '../config' + +import VueApollo from 'vue-apollo' +import { store } from '../store/store.js' +import router from '../routes/router' +import i18n from '../i18n' + +jest.mock('vue-apollo') +jest.mock('../store/store') +jest.mock('../routes/router') +jest.mock('../i18n') + +jest.mock('apollo-boost', () => { + return { + __esModule: true, + ApolloClient: jest.fn(), + ApolloLink: jest.fn(() => { + return { concat: jest.fn() } + }), + InMemoryCache: jest.fn(), + HttpLink: jest.fn(), + } +}) + +describe('apolloProvider', () => { + it('calls the HttpLink', () => { + expect(HttpLink).toBeCalledWith({ uri: CONFIG.GRAPHQL_URI }) + }) + + it('calls the ApolloLink', () => { + expect(ApolloLink).toBeCalled() + }) + + it('calls the ApolloClient', () => { + expect(ApolloClient).toBeCalled() + }) + + it('calls the VueApollo', () => { + expect(VueApollo).toBeCalled() + }) + + describe('ApolloLink', () => { + // mock store + const storeDispatchMock = jest.fn() + store.state = { + token: 'some-token', + } + store.dispatch = storeDispatchMock + + // mock i18n.t + i18n.t = jest.fn((t) => t) + + // mock apllo response + const responseMock = { + errors: [{ message: '403.13 - Client certificate revoked' }], + } + + // mock router + const routerPushMock = jest.fn() + router.push = routerPushMock + router.currentRoute = { + path: '/overview', + } + + // mock context + const setContextMock = jest.fn() + const getContextMock = jest.fn(() => { + return { + response: { + headers: { + get: jest.fn(), + }, + }, + } + }) + + // mock apollo link function params + const operationMock = { + setContext: setContextMock, + getContext: getContextMock, + } + + const forwardMock = jest.fn(() => { + return [responseMock] + }) + + // get apollo link callback + const middleware = ApolloLink.mock.calls[0][0] + + beforeEach(() => { + jest.clearAllMocks() + // run the callback with mocked params + middleware(operationMock, forwardMock) + }) + + it('sets authorization header', () => { + expect(setContextMock).toBeCalledWith({ + headers: { + Authorization: 'Bearer some-token', + }, + }) + }) + + describe('apollo response is 403.13', () => { + it.skip('dispatches logout', () => { + expect(storeDispatchMock).toBeCalledWith('logout', null) + }) + + it.skip('redirects to logout', () => { + expect(routerPushMock).toBeCalledWith('/logout') + }) + }) + }) +}) diff --git a/frontend/yarn.lock b/frontend/yarn.lock index c9f427f7a..ec95b138a 100644 --- a/frontend/yarn.lock +++ b/frontend/yarn.lock @@ -9,13 +9,20 @@ dependencies: "@babel/highlight" "^7.10.4" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13": +"@babel/code-frame@^7.0.0": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.13.tgz#dcfc826beef65e75c50e21d3837d7d95798dd658" integrity sha512-HV1Cm0Q3ZrpCR93tkWOYiuYIgLxZXZFVG2VgK+MBWjUqZTundupbfx2aXarXuw5Ko5aMcjtJgbSs4vUGBS5v6g== dependencies: "@babel/highlight" "^7.12.13" +"@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.16.0.tgz#0dfc80309beec8411e65e706461c408b0bb9b431" + integrity sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA== + dependencies: + "@babel/highlight" "^7.16.0" + "@babel/compat-data@^7.13.0": version "7.13.6" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.13.6.tgz#11972d07db4c2317afdbf41d6feb3a730301ef4e" @@ -26,10 +33,10 @@ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.13.12.tgz#a8a5ccac19c200f9dd49624cac6e19d7be1236a1" integrity sha512-3eJJ841uKxeV8dcN/2yGEUy+RfgQspPEgQat85umsE1rotuquQ2AbIub4S6j7c50a2d+4myc+zSlnXeIHrOnhQ== -"@babel/compat-data@^7.13.8": - version "7.13.11" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.13.11.tgz#9c8fe523c206979c9a81b1e12fe50c1254f1aa35" - integrity sha512-BwKEkO+2a67DcFeS3RLl0Z3Gs2OvdXewuWjc1Hfokhb5eQWP9YRYH1/+VrVZvql2CfjOiNGqSAFOYt4lsqTHzg== +"@babel/compat-data@^7.13.8", "@babel/compat-data@^7.16.0": + version "7.16.4" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.16.4.tgz#081d6bbc336ec5c2435c6346b2ae1fb98b5ac68e" + integrity sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q== "@babel/core@^7.0.0": version "7.13.1" @@ -53,25 +60,24 @@ semver "7.0.0" source-map "^0.5.0" -"@babel/core@^7.1.0", "@babel/core@^7.7.5": - version "7.13.10" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.13.10.tgz#07de050bbd8193fcd8a3c27918c0890613a94559" - integrity sha512-bfIYcT0BdKeAZrovpMqX2Mx5NrgAckGbwT982AkdS5GNfn3KMGiprlBAtmBcFZRUmpaufS6WZFP8trvx8ptFDw== +"@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.7.5": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.16.0.tgz#c4ff44046f5fe310525cc9eb4ef5147f0c5374d4" + integrity sha512-mYZEvshBRHGsIAiyH5PzCFTCfbWfoYbO/jcSdXQSUQu1/pW0xDZAUP7KEc32heqWTAfAHhV9j1vH8Sav7l+JNQ== dependencies: - "@babel/code-frame" "^7.12.13" - "@babel/generator" "^7.13.9" - "@babel/helper-compilation-targets" "^7.13.10" - "@babel/helper-module-transforms" "^7.13.0" - "@babel/helpers" "^7.13.10" - "@babel/parser" "^7.13.10" - "@babel/template" "^7.12.13" - "@babel/traverse" "^7.13.0" - "@babel/types" "^7.13.0" + "@babel/code-frame" "^7.16.0" + "@babel/generator" "^7.16.0" + "@babel/helper-compilation-targets" "^7.16.0" + "@babel/helper-module-transforms" "^7.16.0" + "@babel/helpers" "^7.16.0" + "@babel/parser" "^7.16.0" + "@babel/template" "^7.16.0" + "@babel/traverse" "^7.16.0" + "@babel/types" "^7.16.0" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.2" json5 "^2.1.2" - lodash "^4.17.19" semver "^6.3.0" source-map "^0.5.0" @@ -97,16 +103,16 @@ semver "^6.3.0" source-map "^0.5.0" -"@babel/generator@^7.13.0": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.13.0.tgz#bd00d4394ca22f220390c56a0b5b85568ec1ec0c" - integrity sha512-zBZfgvBB/ywjx0Rgc2+BwoH/3H+lDtlgD4hBOpEv5LxRnYsm/753iRuLepqnYlynpjC3AdQxtxsoeHJoEEwOAw== +"@babel/generator@^7.13.0", "@babel/generator@^7.13.9", "@babel/generator@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.16.0.tgz#d40f3d1d5075e62d3500bccb67f3daa8a95265b2" + integrity sha512-RR8hUCfRQn9j9RPKEVXo9LiwoxLPYn6hNZlvUOR8tSnaxlD0p0+la00ZP9/SnRt6HchKr+X0fO2r8vrETiJGew== dependencies: - "@babel/types" "^7.13.0" + "@babel/types" "^7.16.0" jsesc "^2.5.1" source-map "^0.5.0" -"@babel/generator@^7.13.9", "@babel/generator@^7.4.0": +"@babel/generator@^7.4.0": version "7.13.9" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.13.9.tgz#3a7aa96f9efb8e2be42d38d80e2ceb4c64d8de39" integrity sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw== @@ -140,14 +146,14 @@ browserslist "^4.14.5" semver "7.0.0" -"@babel/helper-compilation-targets@^7.13.10": - version "7.13.10" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.13.10.tgz#1310a1678cb8427c07a753750da4f8ce442bdd0c" - integrity sha512-/Xju7Qg1GQO4mHZ/Kcs6Au7gfafgZnwm+a7sy/ow/tV1sHeraRUHbjdat8/UvDor4Tez+siGKDk6zIKtCPKVJA== +"@babel/helper-compilation-targets@^7.13.10", "@babel/helper-compilation-targets@^7.16.0": + version "7.16.3" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.3.tgz#5b480cd13f68363df6ec4dc8ac8e2da11363cbf0" + integrity sha512-vKsoSQAyBmxS35JUOOt+07cLc6Nk/2ljLIHwmq2/NM6hdioUaqEXq/S+nXvbvXbZkNDlWOymPanJGOc4CBjSJA== dependencies: - "@babel/compat-data" "^7.13.8" - "@babel/helper-validator-option" "^7.12.17" - browserslist "^4.14.5" + "@babel/compat-data" "^7.16.0" + "@babel/helper-validator-option" "^7.14.5" + browserslist "^4.17.5" semver "^6.3.0" "@babel/helper-compilation-targets@^7.13.13", "@babel/helper-compilation-targets@^7.13.8": @@ -200,21 +206,21 @@ dependencies: "@babel/types" "^7.13.0" -"@babel/helper-function-name@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.12.13.tgz#93ad656db3c3c2232559fd7b2c3dbdcbe0eb377a" - integrity sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA== +"@babel/helper-function-name@^7.12.13", "@babel/helper-function-name@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.16.0.tgz#b7dd0797d00bbfee4f07e9c4ea5b0e30c8bb1481" + integrity sha512-BZh4mEk1xi2h4HFjWUXRQX5AEx4rvaZxHgax9gcjdLWdkjsY7MKt5p0otjsg5noXw+pB+clMCjw+aEVYADMjog== dependencies: - "@babel/helper-get-function-arity" "^7.12.13" - "@babel/template" "^7.12.13" - "@babel/types" "^7.12.13" + "@babel/helper-get-function-arity" "^7.16.0" + "@babel/template" "^7.16.0" + "@babel/types" "^7.16.0" -"@babel/helper-get-function-arity@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.12.13.tgz#bc63451d403a3b3082b97e1d8b3fe5bd4091e583" - integrity sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg== +"@babel/helper-get-function-arity@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.0.tgz#0088c7486b29a9cb5d948b1a1de46db66e089cfa" + integrity sha512-ASCquNcywC1NkYh/z7Cgp3w31YW8aojjYIlNg4VeJiHkqyP4AzIvr4qx7pYDb4/s8YcsZWqqOSxgkvjUz1kpDQ== dependencies: - "@babel/types" "^7.12.13" + "@babel/types" "^7.16.0" "@babel/helper-hoist-variables@^7.12.13", "@babel/helper-hoist-variables@^7.13.0": version "7.13.0" @@ -224,12 +230,19 @@ "@babel/traverse" "^7.13.0" "@babel/types" "^7.13.0" -"@babel/helper-member-expression-to-functions@^7.13.0": - version "7.13.0" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.13.0.tgz#6aa4bb678e0f8c22f58cdb79451d30494461b091" - integrity sha512-yvRf8Ivk62JwisqV1rFRMxiSMDGnN6KH1/mDMmIrij4jztpQNRoHqqMG3U6apYbGRPJpgPalhva9Yd06HlUxJQ== +"@babel/helper-hoist-variables@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.0.tgz#4c9023c2f1def7e28ff46fc1dbcd36a39beaa81a" + integrity sha512-1AZlpazjUR0EQZQv3sgRNfM9mEVWPK3M6vlalczA+EECcPz3XPh6VplbErL5UoMpChhSck5wAJHthlj1bYpcmg== dependencies: - "@babel/types" "^7.13.0" + "@babel/types" "^7.16.0" + +"@babel/helper-member-expression-to-functions@^7.13.0", "@babel/helper-member-expression-to-functions@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.0.tgz#29287040efd197c77636ef75188e81da8bccd5a4" + integrity sha512-bsjlBFPuWT6IWhl28EdrQ+gTvSvj5tqVP5Xeftp07SEuz5pLnsXZuDkDD3Rfcxy0IsHmbZ+7B2/9SHzxO0T+sQ== + dependencies: + "@babel/types" "^7.16.0" "@babel/helper-member-expression-to-functions@^7.13.12": version "7.13.12" @@ -246,13 +259,20 @@ "@babel/types" "7.0.0-beta.35" lodash "^4.2.0" -"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.12.13": +"@babel/helper-module-imports@^7.0.0": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.12.13.tgz#ec67e4404f41750463e455cc3203f6a32e93fcb0" integrity sha512-NGmfvRp9Rqxy0uHSSVP+SRIW1q31a7Ji10cLBcqSDUngGentY4FRiHOFZFE1CLU5eiL0oE8reH7Tg1y99TDM/g== dependencies: "@babel/types" "^7.12.13" +"@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.16.0.tgz#90538e60b672ecf1b448f5f4f5433d37e79a3ec3" + integrity sha512-kkH7sWzKPq0xt3H1n+ghb4xEMP8k0U7XV3kkB+ZGy69kDk2ySFW1qPi06sjKzFY3t1j6XbJSqr4mF9L7CYVyhg== + dependencies: + "@babel/types" "^7.16.0" + "@babel/helper-module-imports@^7.13.12": version "7.13.12" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.13.12.tgz#c6a369a6f3621cb25da014078684da9196b61977" @@ -260,7 +280,7 @@ dependencies: "@babel/types" "^7.13.12" -"@babel/helper-module-transforms@^7.12.13", "@babel/helper-module-transforms@^7.13.0": +"@babel/helper-module-transforms@^7.12.13": version "7.13.0" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.13.0.tgz#42eb4bd8eea68bab46751212c357bfed8b40f6f1" integrity sha512-Ls8/VBwH577+pw7Ku1QkUWIyRRNHpYlts7+qSqBBFCW3I8QteB9DxfcZ5YJpOwH6Ihe/wn8ch7fMGOP1OhEIvw== @@ -275,6 +295,20 @@ "@babel/types" "^7.13.0" lodash "^4.17.19" +"@babel/helper-module-transforms@^7.13.0", "@babel/helper-module-transforms@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.16.0.tgz#1c82a8dd4cb34577502ebd2909699b194c3e9bb5" + integrity sha512-My4cr9ATcaBbmaEa8M0dZNA74cfI6gitvUAskgDtAFmAqyFKDSHQo5YstxPbN+lzHl2D9l/YOEFqb2mtUh4gfA== + dependencies: + "@babel/helper-module-imports" "^7.16.0" + "@babel/helper-replace-supers" "^7.16.0" + "@babel/helper-simple-access" "^7.16.0" + "@babel/helper-split-export-declaration" "^7.16.0" + "@babel/helper-validator-identifier" "^7.15.7" + "@babel/template" "^7.16.0" + "@babel/traverse" "^7.16.0" + "@babel/types" "^7.16.0" + "@babel/helper-module-transforms@^7.13.12": version "7.13.12" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.13.12.tgz#600e58350490828d82282631a1422268e982ba96" @@ -289,14 +323,19 @@ "@babel/traverse" "^7.13.0" "@babel/types" "^7.13.12" -"@babel/helper-optimise-call-expression@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.12.13.tgz#5c02d171b4c8615b1e7163f888c1c81c30a2aaea" - integrity sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA== +"@babel/helper-optimise-call-expression@^7.12.13", "@babel/helper-optimise-call-expression@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.0.tgz#cecdb145d70c54096b1564f8e9f10cd7d193b338" + integrity sha512-SuI467Gi2V8fkofm2JPnZzB/SUuXoJA5zXe/xzyPP2M04686RzFKFHPK6HDVN6JvWBIEW8tt9hPR7fXdn2Lgpw== dependencies: - "@babel/types" "^7.12.13" + "@babel/types" "^7.16.0" -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.8.0": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz#5ac822ce97eec46741ab70a517971e443a70c5a9" + integrity sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ== + +"@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.8.3": version "7.13.0" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.13.0.tgz#806526ce125aed03373bc416a828321e3a6a33af" integrity sha512-ZPafIPSwzUlAoWT8DKs1W2VyF2gOWthGd5NGFMsBcMMol+ZhK+EQY/e6V96poa6PA/Bh+C9plWN0hXO1uB8AfQ== @@ -310,7 +349,7 @@ "@babel/helper-wrap-function" "^7.13.0" "@babel/types" "^7.13.0" -"@babel/helper-replace-supers@^7.12.13", "@babel/helper-replace-supers@^7.13.0": +"@babel/helper-replace-supers@^7.12.13": version "7.13.0" resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.13.0.tgz#6034b7b51943094cb41627848cb219cb02be1d24" integrity sha512-Segd5me1+Pz+rmN/NFBOplMbZG3SqRJOBlY+mA0SxAv6rjj7zJqr1AVr3SfzUVTLCv7ZLU5FycOM/SBGuLPbZw== @@ -320,6 +359,16 @@ "@babel/traverse" "^7.13.0" "@babel/types" "^7.13.0" +"@babel/helper-replace-supers@^7.13.0", "@babel/helper-replace-supers@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.16.0.tgz#73055e8d3cf9bcba8ddb55cad93fedc860f68f17" + integrity sha512-TQxuQfSCdoha7cpRNJvfaYxxxzmbxXw/+6cS7V02eeDYyhxderSoMVALvwupA54/pZcOTtVeJ0xccp1nGWladA== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.16.0" + "@babel/helper-optimise-call-expression" "^7.16.0" + "@babel/traverse" "^7.16.0" + "@babel/types" "^7.16.0" + "@babel/helper-replace-supers@^7.13.12": version "7.13.12" resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.13.12.tgz#6442f4c1ad912502481a564a7386de0c77ff3804" @@ -330,12 +379,12 @@ "@babel/traverse" "^7.13.0" "@babel/types" "^7.13.12" -"@babel/helper-simple-access@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.12.13.tgz#8478bcc5cacf6aa1672b251c1d2dde5ccd61a6c4" - integrity sha512-0ski5dyYIHEfwpWGx5GPWhH35j342JaflmCeQmsPWcrOQDtCN6C1zKAVRFVbK53lPW2c9TsuLLSUDf0tIGJ5hA== +"@babel/helper-simple-access@^7.12.13", "@babel/helper-simple-access@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.16.0.tgz#21d6a27620e383e37534cf6c10bba019a6f90517" + integrity sha512-o1rjBT/gppAqKsYfUdfHq5Rk03lMQrkPHG1OWzHWpLgVXRH4HnMM9Et9CVdIqwkCQlobnGHEJMsgWP/jE1zUiw== dependencies: - "@babel/types" "^7.12.13" + "@babel/types" "^7.16.0" "@babel/helper-simple-access@^7.13.12": version "7.13.12" @@ -351,27 +400,27 @@ dependencies: "@babel/types" "^7.12.1" -"@babel/helper-split-export-declaration@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.12.13.tgz#e9430be00baf3e88b0e13e6f9d4eaf2136372b05" - integrity sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg== +"@babel/helper-split-export-declaration@^7.12.13", "@babel/helper-split-export-declaration@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.0.tgz#29672f43663e936df370aaeb22beddb3baec7438" + integrity sha512-0YMMRpuDFNGTHNRiiqJX19GjNXA4H0E8jZ2ibccfSxaCogbm3am5WN/2nQNj0YnQwGWM1J06GOcQ2qnh3+0paw== dependencies: - "@babel/types" "^7.12.13" + "@babel/types" "^7.16.0" -"@babel/helper-validator-identifier@^7.12.11": - version "7.12.11" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed" - integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw== +"@babel/helper-validator-identifier@^7.12.11", "@babel/helper-validator-identifier@^7.15.7": + version "7.15.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389" + integrity sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w== "@babel/helper-validator-identifier@^7.14.0": version "7.14.0" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz#d26cad8a47c65286b15df1547319a5d0bcf27288" integrity sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A== -"@babel/helper-validator-option@^7.12.17": - version "7.12.17" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.12.17.tgz#d1fbf012e1a79b7eebbfdc6d270baaf8d9eb9831" - integrity sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw== +"@babel/helper-validator-option@^7.12.17", "@babel/helper-validator-option@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz#6e72a1fff18d5dfcb878e1e62f1a021c4b72d5a3" + integrity sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow== "@babel/helper-wrap-function@^7.13.0": version "7.13.0" @@ -392,14 +441,14 @@ "@babel/traverse" "^7.13.0" "@babel/types" "^7.13.0" -"@babel/helpers@^7.13.10": - version "7.13.10" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.13.10.tgz#fd8e2ba7488533cdeac45cc158e9ebca5e3c7df8" - integrity sha512-4VO883+MWPDUVRF3PhiLBUFHoX/bsLTGFpFK/HqvvfBZz2D57u9XzPVNFVBTc0PW/CWR9BXTOKt8NF4DInUHcQ== +"@babel/helpers@^7.13.10", "@babel/helpers@^7.16.0": + version "7.16.3" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.16.3.tgz#27fc64f40b996e7074dc73128c3e5c3e7f55c43c" + integrity sha512-Xn8IhDlBPhvYTvgewPKawhADichOsbkZuzN7qz2BusOM0brChsyXMDJvldWaYMMUNiCQdQzNEioXTp3sC8Nt8w== dependencies: - "@babel/template" "^7.12.13" - "@babel/traverse" "^7.13.0" - "@babel/types" "^7.13.0" + "@babel/template" "^7.16.0" + "@babel/traverse" "^7.16.3" + "@babel/types" "^7.16.0" "@babel/highlight@^7.10.4": version "7.14.0" @@ -410,12 +459,12 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/highlight@^7.12.13": - version "7.12.13" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.12.13.tgz#8ab538393e00370b26271b01fa08f7f27f2e795c" - integrity sha512-kocDQvIbgMKlWxXe9fof3TQ+gkIPOUSEYhJjqUjvKMez3krV7vbzYCDq39Oj11UAVK7JqPVGQPlgE85dPNlQww== +"@babel/highlight@^7.12.13", "@babel/highlight@^7.16.0": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.16.0.tgz#6ceb32b2ca4b8f5f361fb7fd821e3fddf4a1725a" + integrity sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g== dependencies: - "@babel/helper-validator-identifier" "^7.12.11" + "@babel/helper-validator-identifier" "^7.15.7" chalk "^2.0.0" js-tokens "^4.0.0" @@ -431,21 +480,21 @@ regenerator-runtime "^0.13.4" v8flags "^3.1.1" -"@babel/parser@^7.1.0", "@babel/parser@^7.13.10": - version "7.13.11" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.11.tgz#f93ebfc99d21c1772afbbaa153f47e7ce2f50b88" - integrity sha512-PhuoqeHoO9fc4ffMEVk4qb/w/s2iOSWohvbHxLtxui0eBg3Lg5gN1U8wp1V1u61hOWkPQJJyJzGH6Y+grwkq8Q== - -"@babel/parser@^7.12.13", "@babel/parser@^7.13.0", "@babel/parser@^7.7.0": - version "7.13.4" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.4.tgz#340211b0da94a351a6f10e63671fa727333d13ab" - integrity sha512-uvoOulWHhI+0+1f9L4BoozY7U5cIkZ9PgJqvb041d6vypgUmtVPG4vmGm4pSggjl8BELzvHyUeJSUyEMY6b+qA== +"@babel/parser@^7.1.0", "@babel/parser@^7.12.13", "@babel/parser@^7.13.0", "@babel/parser@^7.14.7", "@babel/parser@^7.16.0", "@babel/parser@^7.16.3": + version "7.16.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.16.4.tgz#d5f92f57cf2c74ffe9b37981c0e72fee7311372e" + integrity sha512-6V0qdPUaiVHH3RtZeLIsc+6pDhbYzHR8ogA8w+f+Wc77DuXto19g2QUwveINoS34Uw+W8/hQDGJCx+i4n7xcng== "@babel/parser@^7.13.13", "@babel/parser@^7.4.3": version "7.13.13" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.13.tgz#42f03862f4aed50461e543270916b47dd501f0df" integrity sha512-OhsyMrqygfk5v8HmWwOzlYjJrtLaFhF34MrfG/Z73DgYCI6ojNUTUp2TYbtnjo8PegeJp12eamsNettCQjKjVw== +"@babel/parser@^7.7.0": + version "7.13.4" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.13.4.tgz#340211b0da94a351a6f10e63671fa727333d13ab" + integrity sha512-uvoOulWHhI+0+1f9L4BoozY7U5cIkZ9PgJqvb041d6vypgUmtVPG4vmGm4pSggjl8BELzvHyUeJSUyEMY6b+qA== + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.13.12": version "7.13.12" resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.13.12.tgz#a3484d84d0b549f3fc916b99ee4783f26fabad2a" @@ -712,13 +761,20 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-top-level-await@^7.12.13", "@babel/plugin-syntax-top-level-await@^7.8.3": +"@babel/plugin-syntax-top-level-await@^7.12.13": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.13.tgz#c5f0fa6e249f5b739727f923540cf7a806130178" integrity sha512-A81F9pDwyS7yM//KwbCSDqy3Uj4NMIurtplxphWxoYtNPov7cJsDkAFNNyVlIZ3jwGycVsurZ+LtOA8gZ376iQ== dependencies: "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + "@babel/plugin-transform-arrow-functions@^7.13.0", "@babel/plugin-transform-arrow-functions@^7.2.0": version "7.13.0" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.13.0.tgz#10a59bebad52d637a027afa692e8d5ceff5e3dae" @@ -1161,7 +1217,16 @@ dependencies: regenerator-runtime "^0.13.4" -"@babel/template@^7.12.13", "@babel/template@^7.3.3", "@babel/template@^7.4.0": +"@babel/template@7", "@babel/template@^7.12.13", "@babel/template@^7.16.0", "@babel/template@^7.3.3": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.16.0.tgz#d16a35ebf4cd74e202083356fab21dd89363ddd6" + integrity sha512-MnZdpFD/ZdYhXwiunMqqgyZyucaYsbL0IrjoGjaVhGilz+x8YB++kRfygSOIj1yOtWKPlx7NBp+9I1RQSgsd5A== + dependencies: + "@babel/code-frame" "^7.16.0" + "@babel/parser" "^7.16.0" + "@babel/types" "^7.16.0" + +"@babel/template@^7.4.0": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.12.13.tgz#530265be8a2589dbb37523844c5bcb55947fb327" integrity sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA== @@ -1170,7 +1235,7 @@ "@babel/parser" "^7.12.13" "@babel/types" "^7.12.13" -"@babel/traverse@^7.1.0", "@babel/traverse@^7.13.0", "@babel/traverse@^7.7.0": +"@babel/traverse@^7.1.0", "@babel/traverse@^7.7.0": version "7.13.0" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.13.0.tgz#6d95752475f86ee7ded06536de309a65fc8966cc" integrity sha512-xys5xi5JEhzC3RzEmSGrs/b3pJW/o87SypZ+G/PhaE7uqVQNv/jlmVIBXuoh5atqQ434LfXV+sf23Oxj0bchJQ== @@ -1185,6 +1250,21 @@ globals "^11.1.0" lodash "^4.17.19" +"@babel/traverse@^7.13.0", "@babel/traverse@^7.16.0", "@babel/traverse@^7.16.3": + version "7.16.3" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.16.3.tgz#f63e8a938cc1b780f66d9ed3c54f532ca2d14787" + integrity sha512-eolumr1vVMjqevCpwVO99yN/LoGL0EyHiLO5I043aYQvwOJ9eR5UsZSClHVCzfhBduMAsSzgA/6AyqPjNayJag== + dependencies: + "@babel/code-frame" "^7.16.0" + "@babel/generator" "^7.16.0" + "@babel/helper-function-name" "^7.16.0" + "@babel/helper-hoist-variables" "^7.16.0" + "@babel/helper-split-export-declaration" "^7.16.0" + "@babel/parser" "^7.16.3" + "@babel/types" "^7.16.0" + debug "^4.1.0" + globals "^11.1.0" + "@babel/traverse@^7.13.13", "@babel/traverse@^7.4.3": version "7.13.13" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.13.13.tgz#39aa9c21aab69f74d948a486dd28a2dbdbf5114d" @@ -1208,7 +1288,15 @@ lodash "^4.2.0" to-fast-properties "^2.0.0" -"@babel/types@^7.0.0", "@babel/types@^7.12.1", "@babel/types@^7.12.13", "@babel/types@^7.13.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.7.0": +"@babel/types@^7.0.0", "@babel/types@^7.12.13", "@babel/types@^7.13.0", "@babel/types@^7.16.0", "@babel/types@^7.3.0", "@babel/types@^7.3.3": + version "7.16.0" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.16.0.tgz#db3b313804f96aadd0b776c4823e127ad67289ba" + integrity sha512-PJgg/k3SdLsGb3hhisFvtLOw5ts113klrpLuIPtCJIU+BB24fqq6lf8RWqKJEjzqXR9AEH1rIb5XTqwBHB+kQg== + dependencies: + "@babel/helper-validator-identifier" "^7.15.7" + to-fast-properties "^2.0.0" + +"@babel/types@^7.12.1", "@babel/types@^7.7.0": version "7.13.0" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.13.0.tgz#74424d2816f0171b4100f0ab34e9a374efdf7f80" integrity sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA== @@ -1429,6 +1517,17 @@ jest-message-util "^24.9.0" jest-mock "^24.9.0" +"@jest/fake-timers@^25.1.0": + version "25.5.0" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-25.5.0.tgz#46352e00533c024c90c2bc2ad9f2959f7f114185" + integrity sha512-9y2+uGnESw/oyOI3eww9yaxdZyHq7XvprfP/eeoCsjqKYts2yRlsHS/SgjPDV8FyMfn2nbMy8YzUk6nyvdLOpQ== + dependencies: + "@jest/types" "^25.5.0" + jest-message-util "^25.5.0" + jest-mock "^25.5.0" + jest-util "^25.5.0" + lolex "^5.0.0" + "@jest/fake-timers@^26.6.2": version "26.6.2" resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-26.6.2.tgz#459c329bcf70cee4af4d7e3f3e67848123535aad" @@ -1610,6 +1709,27 @@ source-map "^0.6.1" write-file-atomic "^3.0.0" +"@jest/transform@^27.4.2": + version "27.4.2" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-27.4.2.tgz#459885e96de2e21fc68b8b371e90aa653966dd0d" + integrity sha512-RTKcPZllfcmLfnlxBya7aypofhdz05+E6QITe55Ex0rxyerkgjmmpMlvVn11V0cP719Ps6WcDYCnDzxnnJUwKg== + dependencies: + "@babel/core" "^7.1.0" + "@jest/types" "^27.4.2" + babel-plugin-istanbul "^6.0.0" + chalk "^4.0.0" + convert-source-map "^1.4.0" + fast-json-stable-stringify "^2.0.0" + graceful-fs "^4.2.4" + jest-haste-map "^27.4.2" + jest-regex-util "^27.4.0" + jest-util "^27.4.2" + micromatch "^4.0.4" + pirates "^4.0.1" + slash "^3.0.0" + source-map "^0.6.1" + write-file-atomic "^3.0.0" + "@jest/types@^24.3.0", "@jest/types@^24.9.0": version "24.9.0" resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.9.0.tgz#63cb26cb7500d069e5a389441a7c6ab5e909fc59" @@ -1619,6 +1739,16 @@ "@types/istanbul-reports" "^1.1.1" "@types/yargs" "^13.0.0" +"@jest/types@^25.5.0": + version "25.5.0" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-25.5.0.tgz#4d6a4793f7b9599fc3680877b856a97dbccf2a9d" + integrity sha512-OXD0RgQ86Tu3MazKo8bnrkDRaDXXMGUqd+kTtLtK1Zb7CRzQcaSRPPPV37SvYTdevXEBVxe0HXylEjs8ibkmCw== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^1.1.1" + "@types/yargs" "^15.0.0" + chalk "^3.0.0" + "@jest/types@^26.6.2": version "26.6.2" resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.6.2.tgz#bef5a532030e1d88a2f5a6d933f84e97226ed48e" @@ -1630,6 +1760,17 @@ "@types/yargs" "^15.0.0" chalk "^4.0.0" +"@jest/types@^27.4.2": + version "27.4.2" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.4.2.tgz#96536ebd34da6392c2b7c7737d693885b5dd44a5" + integrity sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg== + dependencies: + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^16.0.0" + chalk "^4.0.0" + "@mrmlnc/readdir-enhanced@^2.2.1": version "2.2.1" resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" @@ -1702,7 +1843,23 @@ string-width "^2.0.0" strip-ansi "^5" -"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.0", "@types/babel__core@^7.1.7": +"@tootallnate/once@1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" + integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== + +"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14", "@types/babel__core@^7.1.7": + version "7.1.17" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.17.tgz#f50ac9d20d64153b510578d84f9643f9a3afbe64" + integrity sha512-6zzkezS9QEIL8yCBvXWxPTJPNuMeECJVxSOhxNY/jfq9LxOTHivaYTqr37n9LknWWRTIkzqH2UilS5QFvfa90A== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__core@^7.1.0": version "7.1.14" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.14.tgz#faaeefc4185ec71c389f4501ee5ec84b170cc402" integrity sha512-zGZJzzBUVDo/eV6KgbE0f0ZI7dInEYvo12Rb70uNQDshC3SkRMb67ja0GgRHZgAX3Za6rhaWlvbDO8rrGyAb1g== @@ -1714,21 +1871,28 @@ "@types/babel__traverse" "*" "@types/babel__generator@*": - version "7.6.2" - resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.2.tgz#f3d71178e187858f7c45e30380f8f1b7415a12d8" - integrity sha512-MdSJnBjl+bdwkLskZ3NGFp9YcXGx5ggLpQQPqtgakVhsWK0hTtNYhjpZLlWQTviGTvF8at+Bvli3jV7faPdgeQ== + version "7.6.3" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.3.tgz#f456b4b2ce79137f768aa130d2423d2f0ccfaba5" + integrity sha512-/GWCmzJWqV7diQW54smJZzWbSFf4QYtF71WCKhcx6Ru/tFyQIY2eiiITcCAeuPbNSvT9YCGkVMqqvSk2Z0mXiA== dependencies: "@babel/types" "^7.0.0" "@types/babel__template@*": - version "7.4.0" - resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.0.tgz#0c888dd70b3ee9eebb6e4f200e809da0076262be" - integrity sha512-NTPErx4/FiPCGScH7foPyr+/1Dkzkni+rHiYHHoTjvwou7AQzJkNeD60A9CXRy+ZEN2B1bggmkTMCDb+Mv5k+A== + version "7.4.1" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.1.tgz#3d1a48fd9d6c0edfd56f2ff578daed48f36c8969" + integrity sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g== dependencies: "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" -"@types/babel__traverse@*", "@types/babel__traverse@^7.0.4", "@types/babel__traverse@^7.0.6": +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": + version "7.14.2" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.14.2.tgz#ffcd470bbb3f8bf30481678fb5502278ca833a43" + integrity sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA== + dependencies: + "@babel/types" "^7.3.0" + +"@types/babel__traverse@^7.0.4": version "7.11.1" resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.11.1.tgz#654f6c4f67568e24c23b367e947098c6206fa639" integrity sha512-Vs0hm0vPahPMYi9tDjtP66llufgO3ST16WXaSTtDGEl9cewAl3AibmxWw6TINOqHPT9z0uABKAYjT9jNSg4npw== @@ -1776,9 +1940,9 @@ "@types/istanbul-lib-report" "*" "@types/istanbul-reports@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.0.tgz#508b13aa344fa4976234e75dddcc34925737d821" - integrity sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA== + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" + integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== dependencies: "@types/istanbul-lib-report" "*" @@ -1815,9 +1979,9 @@ integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== "@types/node@*": - version "14.14.31" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.31.tgz#72286bd33d137aa0d152d47ec7c1762563d34055" - integrity sha512-vFHy/ezP5qI0rFgJ7aQnjDXwAMrG0KqqIH7tQG5PPv3BWBayOPIQNBjVc/P6hhdZfMx51REc6tfDNXHUio893g== + version "16.11.12" + resolved "https://registry.yarnpkg.com/@types/node/-/node-16.11.12.tgz#ac7fb693ac587ee182c3780c26eb65546a1a3c10" + integrity sha512-+2Iggwg7PxoO5Kyhvsq9VarmPbIelXP070HMImEpbtGCoyWNINQj4wzjbQCXzdHTRXnqufutJb5KAURZANNBAw== "@types/node@>=6": version "16.4.12" @@ -1860,9 +2024,9 @@ integrity sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ== "@types/yargs-parser@*": - version "20.2.0" - resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.0.tgz#dd3e6699ba3237f0348cd085e4698780204842f9" - integrity sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA== + version "20.2.1" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.1.tgz#3b9ce2489919d9e4fea439b76916abc34b2df129" + integrity sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw== "@types/yargs@^13.0.0": version "13.0.11" @@ -1872,9 +2036,16 @@ "@types/yargs-parser" "*" "@types/yargs@^15.0.0": - version "15.0.13" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.13.tgz#34f7fec8b389d7f3c1fd08026a5763e072d3c6dc" - integrity sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ== + version "15.0.14" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.14.tgz#26d821ddb89e70492160b66d10a0eb6df8f6fb06" + integrity sha512-yEJzHoxf6SyQGhBhIYGXQDSCkJjB6HohDShto7m8vaKg9Yp0Yn8+71J9eakh2bnPg6BfsH9PRMhiRTZnd4eXGQ== + dependencies: + "@types/yargs-parser" "*" + +"@types/yargs@^16.0.0": + version "16.0.4" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.4.tgz#26aad98dd2c2a38e421086ea9ad42b9e51642977" + integrity sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw== dependencies: "@types/yargs-parser" "*" @@ -2483,11 +2654,23 @@ acorn@^8.0.5: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.1.0.tgz#52311fd7037ae119cbb134309e901aa46295b3fe" integrity sha512-LWCF/Wn0nfHOmJ9rzQApGnxnvgfROzGilS8936rqN/lfcYkY9MYZzdMqN+2NJ4SlTc+m5HiSa+kNfDtI64dwUA== +acorn@^8.2.4: + version "8.6.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.6.0.tgz#e3692ba0eb1a0c83eaa4f37f5fa7368dd7142895" + integrity sha512-U1riIR+lBSNi3IbxtaHOIKdH8sLFv3NYfNv8sg7ZsNhcfl4HF2++BfqqrNAxoCLQW1iiylOj76ecnaUxz+z9yw== + address@^1.0.3: version "1.1.2" resolved "https://registry.yarnpkg.com/address/-/address-1.1.2.tgz#bf1116c9c758c51b7a933d296b72c221ed9428b6" integrity sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA== +agent-base@6: + version "6.0.2" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== + dependencies: + debug "4" + ajv-errors@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" @@ -2622,7 +2805,15 @@ anymatch@^2.0.0: micromatch "^3.1.4" normalize-path "^2.1.1" -anymatch@^3.0.3, anymatch@~3.1.1: +anymatch@^3.0.3: + version "3.1.2" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +anymatch@~3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg== @@ -2992,6 +3183,20 @@ babel-jest@^26.6.3: graceful-fs "^4.2.4" slash "^3.0.0" +babel-jest@^27.3.1: + version "27.4.2" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.4.2.tgz#6edf80971045cfd44f3f10b6eda6007d95f62742" + integrity sha512-MADrjb3KBO2eyZCAc6QaJg6RT5u+6oEdDyHO5HEalnpwQ6LrhTsQF2Kj1Wnz2t6UPXIXPk18dSXXOT0wF5yTxA== + dependencies: + "@jest/transform" "^27.4.2" + "@jest/types" "^27.4.2" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.0.0" + babel-preset-jest "^27.4.0" + chalk "^4.0.0" + graceful-fs "^4.2.4" + slash "^3.0.0" + babel-loader@^8.0.5: version "8.2.2" resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.2.2.tgz#9363ce84c10c9a40e6c753748e1441b60c8a0b81" @@ -3034,14 +3239,14 @@ babel-plugin-istanbul@^5.1.0: test-exclude "^5.2.3" babel-plugin-istanbul@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz#e159ccdc9af95e0b570c75b4573b7c34d671d765" - integrity sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ== + version "6.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" "@istanbuljs/load-nyc-config" "^1.0.0" "@istanbuljs/schema" "^0.1.2" - istanbul-lib-instrument "^4.0.0" + istanbul-lib-instrument "^5.0.4" test-exclude "^6.0.0" babel-plugin-jest-hoist@^24.9.0: @@ -3061,6 +3266,16 @@ babel-plugin-jest-hoist@^26.6.2: "@types/babel__core" "^7.0.0" "@types/babel__traverse" "^7.0.6" +babel-plugin-jest-hoist@^27.4.0: + version "27.4.0" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.4.0.tgz#d7831fc0f93573788d80dee7e682482da4c730d6" + integrity sha512-Jcu7qS4OX5kTWBc45Hz7BMmgXuJqRnhatqpUhnzGC3OBYpOmf2tv6jFNwZpwM7wU7MUuv2r9IPS/ZlYOuburVw== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.0.0" + "@types/babel__traverse" "^7.0.6" + babel-plugin-jsx-event-modifiers@^2.0.2: version "2.0.5" resolved "https://registry.yarnpkg.com/babel-plugin-jsx-event-modifiers/-/babel-plugin-jsx-event-modifiers-2.0.5.tgz#93e6ebb5d7553bb08f9fedbf7a0bee3af09a0472" @@ -3130,6 +3345,13 @@ babel-plugin-transform-es2015-modules-commonjs@^6.26.0, babel-plugin-transform-e babel-template "^6.26.0" babel-types "^6.26.0" +babel-plugin-transform-require-context@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-require-context/-/babel-plugin-transform-require-context-0.1.1.tgz#319b545ca83080b5062776b46cc9b8b346fea9a6" + integrity sha512-4ceqYOtzgmq4/QsB8dP7pUrUOCjY/jrRYdt7YkIOWHxtGDQbcf6YZDyLCiPQf6KsEIcIbSQiTRXOsbLiuJfgNQ== + dependencies: + "@babel/template" "7" + babel-plugin-transform-strict-mode@^6.24.1: version "6.24.1" resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" @@ -3179,6 +3401,14 @@ babel-preset-jest@^26.6.2: babel-plugin-jest-hoist "^26.6.2" babel-preset-current-node-syntax "^1.0.0" +babel-preset-jest@^27.4.0: + version "27.4.0" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-27.4.0.tgz#70d0e676a282ccb200fbabd7f415db5fdf393bca" + integrity sha512-NK4jGYpnBvNxcGo7/ZpZJr51jCGT+3bwwpVIDY2oNfTxJJldRtB4VAcYdgp1loDE50ODuTu+yBjpMAswv5tlpg== + dependencies: + babel-plugin-jest-hoist "^27.4.0" + babel-preset-current-node-syntax "^1.0.0" + babel-preset-vue@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/babel-preset-vue/-/babel-preset-vue-2.0.2.tgz#cfadf1bd736125397481b5f8525ced0049a0c71f" @@ -3240,9 +3470,9 @@ babylon@^6.18.0: integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== base64-js@^1.0.2, base64-js@^1.3.1: version "1.5.1" @@ -3499,7 +3729,7 @@ browserify-zlib@^0.2.0: dependencies: pako "~1.0.5" -browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.14.5, browserslist@^4.16.3, browserslist@^4.3.4, browserslist@^4.5.4: +browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.16.3, browserslist@^4.3.4, browserslist@^4.5.4: version "4.16.3" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.3.tgz#340aa46940d7db878748567c5dea24a48ddf3717" integrity sha512-vIyhWmIkULaq04Gt93txdh+j02yX/JzlyhLYbV3YQCn/zvES3JnY7TifHHvvr1w5hTDluNKMkV05cs4vy8Q7sw== @@ -3510,6 +3740,17 @@ browserslist@^4.0.0, browserslist@^4.12.0, browserslist@^4.14.5, browserslist@^4 escalade "^3.1.1" node-releases "^1.1.70" +browserslist@^4.14.5, browserslist@^4.17.5: + version "4.18.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.18.1.tgz#60d3920f25b6860eb917c6c7b185576f4d8b017f" + integrity sha512-8ScCzdpPwR2wQh8IT82CA2VgDwjHyqMovPBZSNH54+tm4Jk2pCuv90gmAdH6J84OCRWi0b4gMe6O6XPXuJnjgQ== + dependencies: + caniuse-lite "^1.0.30001280" + electron-to-chromium "^1.3.896" + escalade "^3.1.1" + node-releases "^2.0.1" + picocolors "^1.0.0" + bs-logger@0.x: version "0.2.6" resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" @@ -3756,11 +3997,16 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001109, caniuse-lite@^1.0.30001181: +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001109: version "1.0.30001251" resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001251.tgz" integrity sha512-HOe1r+9VkU4TFmnU70z+r7OLmtR+/chB1rdcJUeQlAinjEeb0cKL20tlAtOagNZhbrtLnCvV19B4FmF1rgzl6A== +caniuse-lite@^1.0.30001181, caniuse-lite@^1.0.30001280: + version "1.0.30001285" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001285.tgz#fe1e52229187e11d6670590790d669b9e03315b7" + integrity sha512-KAOkuUtcQ901MtmvxfKD+ODHH9YVDYnBt+TGYSz2KIfnq22CiArbUxXPN9067gNbgMlnNYRSwho8OPXZPALB9Q== + capture-exit@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" @@ -3798,7 +4044,23 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0, chalk@^2.3.0, chalk@^2.4.1, chalk@^2.4 escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.0.0, chalk@^4.1.0: +chalk@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" + integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chalk@^4.0.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chalk@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== @@ -3882,6 +4144,11 @@ ci-info@^2.0.0: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== +ci-info@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.3.0.tgz#b4ed1fb6818dea4803a55c623041f9165d2066b2" + integrity sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw== + cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" @@ -4084,16 +4351,16 @@ color@^3.0.0: color-string "^1.5.4" colorette@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.1.tgz#4d0b921325c14faf92633086a536db6e89564b1b" - integrity sha512-puCDz0CzydiSYOrnXpz/PKd69zRrribezjtE9yd4zvytoRc8+RY/KJPvtPFKZS3E3wP6neGyMe0vOTlHO5L3Pw== + version "1.4.0" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40" + integrity sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g== colors@^1.1.2: version "1.4.0" resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== -combined-stream@^1.0.6, combined-stream@~1.0.6: +combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== @@ -4236,7 +4503,14 @@ content-type@~1.0.4: resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== -convert-source-map@^1.4.0, convert-source-map@^1.5.1, convert-source-map@^1.6.0, convert-source-map@^1.7.0: +convert-source-map@^1.4.0, convert-source-map@^1.7.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" + integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== + dependencies: + safe-buffer "~5.1.1" + +convert-source-map@^1.5.1, convert-source-map@^1.6.0: version "1.7.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== @@ -4953,6 +5227,13 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: dependencies: ms "2.0.0" +debug@4, debug@^4.1.0: + version "4.3.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" + integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== + dependencies: + ms "2.1.2" + debug@^3.1.0, debug@^3.1.1, debug@^3.2.6: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" @@ -4960,7 +5241,7 @@ debug@^3.1.0, debug@^3.1.1, debug@^3.2.6: dependencies: ms "^2.1.1" -debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: +debug@^4.0.1, debug@^4.1.1: version "4.3.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== @@ -5382,10 +5663,10 @@ ejs@^2.6.1: resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.7.4.tgz#48661287573dcc53e366c7a1ae52c3a120eec9ba" integrity sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA== -electron-to-chromium@^1.3.649: - version "1.3.673" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.673.tgz#b4f81c930b388f962b7eba20d0483299aaa40913" - integrity sha512-ms+QR2ckfrrpEAjXweLx6kNCbpAl66DcW//3BZD4BV5KhUgr0RZRce1ON/9J3QyA3JO28nzgb5Xv8DnPr05ILg== +electron-to-chromium@^1.3.649, electron-to-chromium@^1.3.896: + version "1.4.12" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.12.tgz#5f73d1278c6205fc41d7a0ebd75563046b77c5d8" + integrity sha512-zjfhG9Us/hIy8AlQ5OzfbR/C4aBv1Dg/ak4GX35CELYlJ4tDAtoEcQivXvyBdqdNQ+R6PhlgQqV8UNPJmhkJog== elliptic@^6.5.3: version "6.5.4" @@ -6052,9 +6333,9 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: safe-buffer "^5.1.1" exec-sh@^0.3.2: - version "0.3.5" - resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.5.tgz#1b46bd6bcbf54fdc1e926a4f3d90126d42cec3df" - integrity sha512-0hzpaUazv4mEccxdn3TXC+HWNeVXNKMCJRK6E7Xyg+LwGAYI3yFag6jTkd4injV+kChYDQS1ftqDhnDVWNhU8A== + version "0.3.6" + resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.6.tgz#ff264f9e325519a60cb5e273692943483cca63bc" + integrity sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w== execa@^0.8.0: version "0.8.0" @@ -6570,6 +6851,15 @@ forever-agent@~0.6.1: resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= +form-data@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" + integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + form-data@~2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" @@ -6652,7 +6942,7 @@ fsevents@^1.2.7: bindings "^1.5.0" nan "^2.12.1" -fsevents@^2.1.2, fsevents@~2.3.1: +fsevents@^2.1.2, fsevents@^2.3.2, fsevents@~2.3.1: version "2.3.2" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== @@ -6785,7 +7075,7 @@ glob-to-regexp@^0.3.0: resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= -glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@~7.1.1: +glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@~7.1.1: version "7.1.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== @@ -6797,6 +7087,18 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, gl once "^1.3.0" path-is-absolute "^1.0.0" +glob@^7.1.4: + version "7.2.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + globals@^11.0.1, globals@^11.1.0: version "11.12.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" @@ -6891,12 +7193,12 @@ google-maps@^3.2.1: resolved "https://registry.yarnpkg.com/google-maps/-/google-maps-3.3.0.tgz#4432b4715406bc15268ad35b1dd1b04d974956a6" integrity sha512-pj4En0cWKG+lcBvC7qrzu5ItiMsYNTgjG2capsPzAbAM/O8ftugGpUUftTTwdGL8KlNvB4CEZ6IBWwpWYzUEpw== -graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4: +graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0: version "4.2.6" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee" integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ== -graceful-fs@^4.2.3: +graceful-fs@^4.2.3, graceful-fs@^4.2.4: version "4.2.8" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== @@ -7240,6 +7542,15 @@ http-parser-js@>=0.5.1: resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.3.tgz#01d2709c79d41698bb01d4decc5e9da4e4a033d9" integrity sha512-t7hjvef/5HEK7RWTdUzVUhl8zkEu+LlaE0IYzdMuvbSDipxBRpOn4Uhw8ZyECEa808iVT8XCjzo6xmYt4CiLZg== +http-proxy-agent@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" + integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== + dependencies: + "@tootallnate/once" "1" + agent-base "6" + debug "4" + http-proxy-middleware@0.19.1: version "0.19.1" resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz#183c7dc4aa1479150306498c210cdaf96080a43a" @@ -7273,6 +7584,14 @@ https-browserify@^1.0.0: resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= +https-proxy-agent@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" + integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== + dependencies: + agent-base "6" + debug "4" + human-signals@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" @@ -7758,6 +8077,11 @@ is-potential-custom-element-name@^1.0.0: resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz#0c52e54bcca391bb2c494b21e8626d7336c6e397" integrity sha1-DFLlS8yjkbssSUsh6GJtczbG45c= +is-potential-custom-element-name@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" + integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== + is-regex@^1.0.4, is-regex@^1.1.1, is-regex@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.2.tgz#81c8ebde4db142f2cf1c53fc86d6a45788266251" @@ -7869,10 +8193,10 @@ istanbul-lib-coverage@^2.0.2, istanbul-lib-coverage@^2.0.5: resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz#675f0ab69503fad4b1d849f736baaca803344f49" integrity sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA== -istanbul-lib-coverage@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec" - integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg== +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" + integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== istanbul-lib-instrument@^3.0.1, istanbul-lib-instrument@^3.3.0: version "3.3.0" @@ -7887,7 +8211,7 @@ istanbul-lib-instrument@^3.0.1, istanbul-lib-instrument@^3.3.0: istanbul-lib-coverage "^2.0.5" semver "^6.0.0" -istanbul-lib-instrument@^4.0.0, istanbul-lib-instrument@^4.0.3: +istanbul-lib-instrument@^4.0.3: version "4.0.3" resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ== @@ -7897,6 +8221,17 @@ istanbul-lib-instrument@^4.0.0, istanbul-lib-instrument@^4.0.3: istanbul-lib-coverage "^3.0.0" semver "^6.3.0" +istanbul-lib-instrument@^5.0.4: + version "5.1.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz#7b49198b657b27a730b8e9cb601f1e1bff24c59a" + integrity sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" + istanbul-lib-report@^2.0.4: version "2.0.8" resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz#5a8113cd746d43c4889eba36ab10e7d50c9b4f33" @@ -8134,6 +8469,16 @@ jest-environment-jsdom-fifteen@^1.0.2: jest-util "^24.0.0" jsdom "^15.2.1" +jest-environment-jsdom-sixteen@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom-sixteen/-/jest-environment-jsdom-sixteen-2.0.0.tgz#0f8c12663ccd9836d248574decffc575bfb091e1" + integrity sha512-BF+8P67aEJcd78TQzwSb9P4a73cArOWb5KgqI8eU6cHRWDIJdDRE8XTeZAmOuDSDhKpuEXjKkXwWB3GOJvqHJQ== + dependencies: + "@jest/fake-timers" "^25.1.0" + jest-mock "^25.1.0" + jest-util "^25.1.0" + jsdom "^16.2.1" + jest-environment-jsdom@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-24.9.0.tgz#4b0806c7fc94f95edb369a69cc2778eec2b7375b" @@ -8232,6 +8577,26 @@ jest-haste-map@^26.6.2: optionalDependencies: fsevents "^2.1.2" +jest-haste-map@^27.4.2: + version "27.4.2" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.4.2.tgz#7fc7d5e568cca704284f4850885b74a0b8b87587" + integrity sha512-foiyAEePORUN2eeJnOtcM1y8qW0ShEd9kTjWVL4sVaMcuCJM6gtHegvYPBRT0mpI/bs4ueThM90+Eoj2ncoNsA== + dependencies: + "@jest/types" "^27.4.2" + "@types/graceful-fs" "^4.1.2" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.4" + jest-regex-util "^27.4.0" + jest-serializer "^27.4.0" + jest-util "^27.4.2" + jest-worker "^27.4.2" + micromatch "^4.0.4" + walker "^1.0.7" + optionalDependencies: + fsevents "^2.3.2" + jest-jasmine2@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-24.9.0.tgz#1f7b1bd3242c1774e62acabb3646d96afc3be6a0" @@ -8328,6 +8693,20 @@ jest-message-util@^24.9.0: slash "^2.0.0" stack-utils "^1.0.1" +jest-message-util@^25.5.0: + version "25.5.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-25.5.0.tgz#ea11d93204cc7ae97456e1d8716251185b8880ea" + integrity sha512-ezddz3YCT/LT0SKAmylVyWWIGYoKHOFOFXx3/nA4m794lfVUskMcwhip6vTgdVrOtYdjeQeis2ypzes9mZb4EA== + dependencies: + "@babel/code-frame" "^7.0.0" + "@jest/types" "^25.5.0" + "@types/stack-utils" "^1.0.1" + chalk "^3.0.0" + graceful-fs "^4.2.4" + micromatch "^4.0.2" + slash "^3.0.0" + stack-utils "^1.0.1" + jest-message-util@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-26.6.2.tgz#58173744ad6fc0506b5d21150b9be56ef001ca07" @@ -8350,6 +8729,13 @@ jest-mock@^24.0.0, jest-mock@^24.9.0: dependencies: "@jest/types" "^24.9.0" +jest-mock@^25.1.0, jest-mock@^25.5.0: + version "25.5.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-25.5.0.tgz#a91a54dabd14e37ecd61665d6b6e06360a55387a" + integrity sha512-eXWuTV8mKzp/ovHc5+3USJMYsTBhyQ+5A1Mak35dey/RG8GlM4YWVylZuGgVXinaW6tpvk/RSecmF37FKUlpXA== + dependencies: + "@jest/types" "^25.5.0" + jest-mock@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-26.6.2.tgz#d6cb712b041ed47fe0d9b6fc3474bc6543feb302" @@ -8373,6 +8759,11 @@ jest-regex-util@^26.0.0: resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28" integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A== +jest-regex-util@^27.4.0: + version "27.4.0" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.4.0.tgz#e4c45b52653128843d07ad94aec34393ea14fbca" + integrity sha512-WeCpMpNnqJYMQoOjm1nTtsgbR4XHAk1u00qDoNBQoykM280+/TmgA5Qh5giC1ecy6a5d4hbSsHzpBtu5yvlbEg== + jest-resolve-dependencies@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-24.9.0.tgz#ad055198959c4cfba8a4f066c673a3f0786507ab" @@ -8549,6 +8940,14 @@ jest-serializer@^26.6.2: "@types/node" "*" graceful-fs "^4.2.4" +jest-serializer@^27.4.0: + version "27.4.0" + resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-27.4.0.tgz#34866586e1cae2388b7d12ffa2c7819edef5958a" + integrity sha512-RDhpcn5f1JYTX2pvJAGDcnsNTnsV9bjYPU8xcV+xPwOXnUPOQwf4ZEuiU6G9H1UztH+OapMgu/ckEVwO87PwnQ== + dependencies: + "@types/node" "*" + graceful-fs "^4.2.4" + jest-snapshot@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-24.9.0.tgz#ec8e9ca4f2ec0c5c87ae8f925cf97497b0e951ba" @@ -8613,6 +9012,17 @@ jest-util@^24.0.0, jest-util@^24.9.0: slash "^2.0.0" source-map "^0.6.0" +jest-util@^25.1.0, jest-util@^25.5.0: + version "25.5.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-25.5.0.tgz#31c63b5d6e901274d264a4fec849230aa3fa35b0" + integrity sha512-KVlX+WWg1zUTB9ktvhsg2PXZVdkI1NBevOJSkTKYAyXyH4QSvh+Lay/e/v+bmaFfrkfx43xD8QTfgobzlEXdIA== + dependencies: + "@jest/types" "^25.5.0" + chalk "^3.0.0" + graceful-fs "^4.2.4" + is-ci "^2.0.0" + make-dir "^3.0.0" + jest-util@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.6.2.tgz#907535dbe4d5a6cb4c47ac9b926f6af29576cbc1" @@ -8625,6 +9035,18 @@ jest-util@^26.6.2: is-ci "^2.0.0" micromatch "^4.0.2" +jest-util@^27.4.2: + version "27.4.2" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.4.2.tgz#ed95b05b1adfd761e2cda47e0144c6a58e05a621" + integrity sha512-YuxxpXU6nlMan9qyLuxHaMMOzXAl5aGZWCSzben5DhLHemYQxCc4YK+4L3ZrCutT8GPQ+ui9k5D8rUJoDioMnA== + dependencies: + "@jest/types" "^27.4.2" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.4" + picomatch "^2.2.3" + jest-validate@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-24.9.0.tgz#0775c55360d173cd854e40180756d4ff52def8ab" @@ -8705,6 +9127,15 @@ jest-worker@^26.6.2: merge-stream "^2.0.0" supports-color "^7.0.0" +jest-worker@^27.4.2: + version "27.4.2" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.4.2.tgz#0fb123d50955af1a450267787f340a1bf7e12bc4" + integrity sha512-0QMy/zPovLfUPyHuOuuU4E+kGACXXE84nRnq6lBVI9GJg5DCBiA97SATi+ZP8CpiJwEQy1oCPjRBf8AnLjN+Ag== + dependencies: + "@types/node" "*" + merge-stream "^2.0.0" + supports-color "^8.0.0" + jest@^24.9.0: version "24.9.0" resolved "https://registry.yarnpkg.com/jest/-/jest-24.9.0.tgz#987d290c05a08b52c56188c1002e368edb007171" @@ -8842,6 +9273,39 @@ jsdom@^15.2.1: ws "^7.0.0" xml-name-validator "^3.0.0" +jsdom@^16.2.1: + version "16.7.0" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" + integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw== + dependencies: + abab "^2.0.5" + acorn "^8.2.4" + acorn-globals "^6.0.0" + cssom "^0.4.4" + cssstyle "^2.3.0" + data-urls "^2.0.0" + decimal.js "^10.2.1" + domexception "^2.0.1" + escodegen "^2.0.0" + form-data "^3.0.0" + html-encoding-sniffer "^2.0.1" + http-proxy-agent "^4.0.1" + https-proxy-agent "^5.0.0" + is-potential-custom-element-name "^1.0.1" + nwsapi "^2.2.0" + parse5 "6.0.1" + saxes "^5.0.1" + symbol-tree "^3.2.4" + tough-cookie "^4.0.0" + w3c-hr-time "^1.0.2" + w3c-xmlserializer "^2.0.0" + webidl-conversions "^6.1.0" + whatwg-encoding "^1.0.5" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.5.0" + ws "^7.4.6" + xml-name-validator "^3.0.0" + jsdom@^16.4.0: version "16.5.1" resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.5.1.tgz#4ced6bbd7b77d67fb980e64d9e3e6fb900f97dd6" @@ -9204,7 +9668,7 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash@^4.0.0, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0, lodash@~4.17.10: +lodash@^4.0.0, lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.7.0, lodash@~4.17.10: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -9221,6 +9685,13 @@ loglevel@^1.6.8: resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.1.tgz#005fde2f5e6e47068f935ff28573e125ef72f197" integrity sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw== +lolex@^5.0.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/lolex/-/lolex-5.1.2.tgz#953694d098ce7c07bc5ed6d0e42bc6c0c6d5a367" + integrity sha512-h4hmjAvHTmd+25JSwrtTIuwbKdwg5NzZVRMLn9saij4SZaepCrTCxPr35H/3bjwfMJtN+t3CX8672UIkglz28A== + dependencies: + "@sinonjs/commons" "^1.7.0" + loose-envify@^1.0.0, loose-envify@^1.2.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" @@ -9289,12 +9760,12 @@ make-error@1.x: resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== -makeerror@1.0.x: - version "1.0.11" - resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" - integrity sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw= +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== dependencies: - tmpl "1.0.x" + tmpl "1.0.5" map-cache@^0.2.2: version "0.2.2" @@ -9429,13 +9900,13 @@ micromatch@^3.1.10, micromatch@^3.1.4: snapdragon "^0.8.1" to-regex "^3.0.2" -micromatch@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" - integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== +micromatch@^4.0.2, micromatch@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" + integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== dependencies: braces "^3.0.1" - picomatch "^2.0.5" + picomatch "^2.2.3" miller-rabin@^4.0.0: version "4.0.1" @@ -9834,9 +10305,14 @@ node-notifier@^8.0.0: which "^2.0.2" node-releases@^1.1.70: - version "1.1.71" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.71.tgz#cb1334b179896b1c89ecfdd4b725fb7bbdfc7dbb" - integrity sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg== + version "1.1.77" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.77.tgz#50b0cfede855dd374e7585bf228ff34e57c1c32e" + integrity sha512-rB1DUFUNAN4Gn9keO2K1efO35IDK7yKHCdCaIMvFO7yUYmmZYeDjnGKle26G4rwj+LKRQpjyUUvMkPglwGCYNQ== + +node-releases@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.1.tgz#3d1d395f204f1f2f29a54358b9fb678765ad2fc5" + integrity sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA== node-sass@^6.0.1: version "6.0.1" @@ -10494,7 +10970,17 @@ performance-now@^2.1.0: resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= -picomatch@^2.0.4, picomatch@^2.0.5, picomatch@^2.2.1: +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picomatch@^2.0.4, picomatch@^2.2.3: + version "2.3.0" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" + integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== + +picomatch@^2.2.1: version "2.2.2" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== @@ -10526,13 +11012,20 @@ pinkie@^2.0.0: resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= -pirates@^4.0.0, pirates@^4.0.1: +pirates@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" integrity sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA== dependencies: node-modules-regexp "^1.0.0" +pirates@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.3.tgz#41a4acbc9bc78decd7f205ee828f34929b9d5749" + integrity sha512-e30YDq2NWgpyIpaKWgols6m/YfgyIyLEmVvrLH5mGrwUs6R6N2h5+DKluT502tex/BK+DO9DIRZ0qqm1/M3FrQ== + dependencies: + node-modules-regexp "^1.0.0" + pkg-dir@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" @@ -11478,9 +11971,9 @@ renderkid@^2.0.4: strip-ansi "^3.0.0" repeat-element@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" - integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== + version "1.1.4" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" + integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== repeat-string@^1.6.1: version "1.6.1" @@ -12043,9 +12536,9 @@ sigmund@^1.0.1: integrity sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA= signal-exit@^3.0.0, signal-exit@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" - integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== + version "3.0.6" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.6.tgz#24e630c4b0f03fea446a2bd299e62b4a6ca8d0af" + integrity sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ== simple-swizzle@^0.2.2: version "0.2.2" @@ -12630,6 +13123,13 @@ supports-color@^7.0.0, supports-color@^7.1.0: dependencies: has-flag "^4.0.0" +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + supports-hyperlinks@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz#f663df252af5f37c5d49bbd7eeefa9e0b9e59e47" @@ -12854,10 +13354,10 @@ tmp@^0.0.33: dependencies: os-tmpdir "~1.0.2" -tmpl@1.0.x: - version "1.0.4" - resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" - integrity sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE= +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== to-arraybuffer@^1.0.0: version "1.0.1" @@ -12973,6 +13473,13 @@ tr46@^2.0.2: dependencies: punycode "^2.1.1" +tr46@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" + integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw== + dependencies: + punycode "^2.1.1" + trim-newlines@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" @@ -13678,11 +14185,11 @@ w3c-xmlserializer@^2.0.0: xml-name-validator "^3.0.0" walker@^1.0.7, walker@~1.0.5: - version "1.0.7" - resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" - integrity sha1-L3+bj9ENZ3JisYqITijRlhjgKPs= + version "1.0.8" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== dependencies: - makeerror "1.0.x" + makeerror "1.0.12" watchpack-chokidar2@^2.0.1: version "2.0.1" @@ -13936,6 +14443,15 @@ whatwg-url@^8.0.0: tr46 "^2.0.2" webidl-conversions "^6.1.0" +whatwg-url@^8.5.0: + version "8.7.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" + integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg== + dependencies: + lodash "^4.7.0" + tr46 "^2.1.0" + webidl-conversions "^6.1.0" + which-boxed-primitive@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" @@ -14072,6 +14588,11 @@ ws@^7.3.1: resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.5.tgz#8b4bc4af518cfabd0473ae4f99144287b33eb881" integrity sha512-BAkMFcAzl8as1G/hArkxOxq3G7pjUqQ3gzYbLL0/5zNkph70e+lCoxBGnm6AW1+/aiNeV4fnKqZ8m4GZewmH2w== +ws@^7.4.6: + version "7.5.6" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.6.tgz#e59fc509fb15ddfb65487ee9765c5a51dec5fe7b" + integrity sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA== + xml-name-validator@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" From a0f8c6664d1b1fe84497d043265ddfb7ebaa9434 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 7 Dec 2021 18:04:10 +0100 Subject: [PATCH 65/74] fix window assign mock --- frontend/src/components/SidebarPlugin/SideBar.spec.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/SidebarPlugin/SideBar.spec.js b/frontend/src/components/SidebarPlugin/SideBar.spec.js index 7b12b6473..3f1a29034 100644 --- a/frontend/src/components/SidebarPlugin/SideBar.spec.js +++ b/frontend/src/components/SidebarPlugin/SideBar.spec.js @@ -167,7 +167,10 @@ describe('SideBar', () => { beforeEach(async () => { mocks.$store.state.isAdmin = true mocks.$store.state.token = 'valid-token' - window.location.assign = assignLocationSpy + delete window.location + window.location = { + assign: assignLocationSpy, + } wrapper = Wrapper() }) From c55c1f26cf31e27f41c143c793f81dd93941ce83 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 7 Dec 2021 18:41:49 +0100 Subject: [PATCH 66/74] test complete apollo provider --- frontend/src/plugins/apolloProvider.test.js | 90 +++++++++++++++++---- 1 file changed, 76 insertions(+), 14 deletions(-) diff --git a/frontend/src/plugins/apolloProvider.test.js b/frontend/src/plugins/apolloProvider.test.js index 75a7045ea..aeb02243c 100644 --- a/frontend/src/plugins/apolloProvider.test.js +++ b/frontend/src/plugins/apolloProvider.test.js @@ -1,4 +1,4 @@ -import { ApolloClient, ApolloLink, InMemoryCache, HttpLink } from 'apollo-boost' +import { ApolloClient, ApolloLink, HttpLink } from 'apollo-boost' import './apolloProvider' import CONFIG from '../config' @@ -44,10 +44,12 @@ describe('apolloProvider', () => { describe('ApolloLink', () => { // mock store const storeDispatchMock = jest.fn() + const storeCommitMock = jest.fn() store.state = { token: 'some-token', } store.dispatch = storeDispatchMock + store.commit = storeCommitMock // mock i18n.t i18n.t = jest.fn((t) => t) @@ -70,7 +72,7 @@ describe('apolloProvider', () => { return { response: { headers: { - get: jest.fn(), + get: jest.fn(() => 'another-token'), }, }, } @@ -89,27 +91,87 @@ describe('apolloProvider', () => { // get apollo link callback const middleware = ApolloLink.mock.calls[0][0] - beforeEach(() => { - jest.clearAllMocks() - // run the callback with mocked params - middleware(operationMock, forwardMock) + describe('with token in store', () => { + it('sets authorization header with token', () => { + // run the apollo link callback with mocked params + middleware(operationMock, forwardMock) + expect(setContextMock).toBeCalledWith({ + headers: { + Authorization: 'Bearer some-token', + }, + }) + }) }) - it('sets authorization header', () => { - expect(setContextMock).toBeCalledWith({ - headers: { - Authorization: 'Bearer some-token', - }, + describe('without token in store', () => { + beforeEach(() => { + store.state.token = null + }) + + it('sets authorization header empty', () => { + middleware(operationMock, forwardMock) + expect(setContextMock).toBeCalledWith({ + headers: { + Authorization: '', + }, + }) }) }) describe('apollo response is 403.13', () => { - it.skip('dispatches logout', () => { + beforeEach(() => { + // run the apollo link callback with mocked params + middleware(operationMock, forwardMock) + }) + + it('dispatches logout', () => { expect(storeDispatchMock).toBeCalledWith('logout', null) }) - it.skip('redirects to logout', () => { - expect(routerPushMock).toBeCalledWith('/logout') + describe('current route is not login', () => { + it('redirects to logout', () => { + expect(routerPushMock).toBeCalledWith('/login') + }) + }) + + describe('current route is login', () => { + beforeEach(() => { + jest.clearAllMocks() + router.currentRoute.path = '/login' + }) + + it('does not redirect to login', () => { + expect(routerPushMock).not.toBeCalled() + }) + }) + }) + + describe('apollo response is with new token', () => { + beforeEach(() => { + delete responseMock.errors + middleware(operationMock, forwardMock) + }) + + it('commits new token to store', () => { + expect(storeCommitMock).toBeCalledWith('token', 'another-token') + }) + }) + + describe('apollo response is without new token', () => { + beforeEach(() => { + jest.clearAllMocks() + getContextMock.mockReturnValue({ + response: { + headers: { + get: jest.fn(() => null), + }, + }, + }) + middleware(operationMock, forwardMock) + }) + + it('does not commit token to store', () => { + expect(storeCommitMock).not.toBeCalled() }) }) }) From 994253747281580b2887831118cd816fcf1cf839 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 7 Dec 2021 18:43:13 +0100 Subject: [PATCH 67/74] test coverage frontend to 90% --- .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 d5b02cc76..e2488d050 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -399,7 +399,7 @@ jobs: report_name: Coverage Frontend type: lcov result_path: ./coverage/lcov.info - min_coverage: 86 + min_coverage: 90 token: ${{ github.token }} ############################################################################## From ee248ec86a36887401864ebe516d2b803a09fadb Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 7 Dec 2021 19:11:31 +0100 Subject: [PATCH 68/74] test apollo provider, apollo provider as plugin --- admin/src/main.js | 35 +---- admin/src/main.test.js | 73 ---------- admin/src/plugins/apolloProvider.js | 37 +++++ admin/src/plugins/apolloProvider.test.js | 178 +++++++++++++++++++++++ 4 files changed, 216 insertions(+), 107 deletions(-) create mode 100644 admin/src/plugins/apolloProvider.js create mode 100644 admin/src/plugins/apolloProvider.test.js diff --git a/admin/src/main.js b/admin/src/main.js index 6a59f1cc7..2743e0f9a 100644 --- a/admin/src/main.js +++ b/admin/src/main.js @@ -11,11 +11,8 @@ import addNavigationGuards from './router/guards' import i18n from './i18n' -import { ApolloClient, ApolloLink, InMemoryCache, HttpLink } from 'apollo-boost' import VueApollo from 'vue-apollo' -import CONFIG from './config' - import { BootstrapVue, IconsPlugin } from 'bootstrap-vue' import 'bootstrap/dist/css/bootstrap.css' import 'bootstrap-vue/dist/bootstrap-vue.css' @@ -23,37 +20,7 @@ import 'bootstrap-vue/dist/bootstrap-vue.css' import moment from 'vue-moment' import Toasted from 'vue-toasted' -const httpLink = new HttpLink({ uri: CONFIG.GRAPHQL_URI }) - -const authLink = new ApolloLink((operation, forward) => { - const token = store.state.token - - operation.setContext({ - headers: { - Authorization: token && token.length > 0 ? `Bearer ${token}` : '', - }, - }) - return forward(operation).map((response) => { - if (response.errors && response.errors[0].message === '403.13 - Client certificate revoked') { - response.errors[0].message = i18n.t('error.session-expired') - store.dispatch('logout', null) - if (router.currentRoute.path !== '/logout') router.push('/logout') - return response - } - const newToken = operation.getContext().response.headers.get('token') - if (newToken) store.commit('token', newToken) - return response - }) -}) - -const apolloClient = new ApolloClient({ - link: authLink.concat(httpLink), - cache: new InMemoryCache(), -}) - -const apolloProvider = new VueApollo({ - defaultClient: apolloClient, -}) +import { apolloProvider } from './plugins/apolloProvider' Vue.use(BootstrapVue) diff --git a/admin/src/main.test.js b/admin/src/main.test.js index 747ef5d2a..06efa8b65 100644 --- a/admin/src/main.test.js +++ b/admin/src/main.test.js @@ -101,77 +101,4 @@ describe('main', () => { }), ) }) - - describe('ApolloLink', () => { - // mock store - const storeDispatchMock = jest.fn() - store.state = { - token: 'some-token', - } - store.dispatch = storeDispatchMock - - // mock i18n.t - i18n.t = jest.fn((t) => t) - - // mock apllo response - const responseMock = { - errors: [{ message: '403.13 - Client certificate revoked' }], - } - - // mock router - const routerPushMock = jest.fn() - router.push = routerPushMock - router.currentRoute = { - path: '/overview', - } - - // mock context - const setContextMock = jest.fn() - const getContextMock = jest.fn(() => { - return { - response: { - headers: { - get: jest.fn(), - }, - }, - } - }) - - // mock apollo link function params - const operationMock = { - setContext: setContextMock, - getContext: getContextMock, - } - - const forwardMock = jest.fn(() => { - return [responseMock] - }) - - // get apollo link callback - const middleware = ApolloLink.mock.calls[0][0] - - beforeEach(() => { - jest.clearAllMocks() - // run the callback with mocked params - middleware(operationMock, forwardMock) - }) - - it('sets authorization header', () => { - expect(setContextMock).toBeCalledWith({ - headers: { - Authorization: 'Bearer some-token', - }, - }) - }) - - describe('apollo response is 403.13', () => { - it.skip('dispatches logout', () => { - expect(storeDispatchMock).toBeCalledWith('logout', null) - }) - - it.skip('redirects to logout', () => { - expect(routerPushMock).toBeCalledWith('/logout') - }) - }) - }) }) diff --git a/admin/src/plugins/apolloProvider.js b/admin/src/plugins/apolloProvider.js new file mode 100644 index 000000000..ec7df38f1 --- /dev/null +++ b/admin/src/plugins/apolloProvider.js @@ -0,0 +1,37 @@ +import { ApolloClient, ApolloLink, InMemoryCache, HttpLink } from 'apollo-boost' +import VueApollo from 'vue-apollo' +import CONFIG from '../config' +import store from '../store/store' +import router from '../router/router' +import i18n from '../i18n' + +const httpLink = new HttpLink({ uri: CONFIG.GRAPHQL_URI }) + +const authLink = new ApolloLink((operation, forward) => { + const token = store.state.token + operation.setContext({ + headers: { + Authorization: token && token.length > 0 ? `Bearer ${token}` : '', + }, + }) + return forward(operation).map((response) => { + if (response.errors && response.errors[0].message === '403.13 - Client certificate revoked') { + response.errors[0].message = i18n.t('error.session-expired') + store.dispatch('logout', null) + if (router.currentRoute.path !== '/login') router.push('/login') + return response + } + const newToken = operation.getContext().response.headers.get('token') + if (newToken) store.commit('token', newToken) + return response + }) +}) + +const apolloClient = new ApolloClient({ + link: authLink.concat(httpLink), + cache: new InMemoryCache(), +}) + +export const apolloProvider = new VueApollo({ + defaultClient: apolloClient, +}) diff --git a/admin/src/plugins/apolloProvider.test.js b/admin/src/plugins/apolloProvider.test.js new file mode 100644 index 000000000..3610b5dae --- /dev/null +++ b/admin/src/plugins/apolloProvider.test.js @@ -0,0 +1,178 @@ +import { ApolloClient, ApolloLink, HttpLink } from 'apollo-boost' +import './apolloProvider' +import CONFIG from '../config' + +import VueApollo from 'vue-apollo' +import store from '../store/store' +import router from '../router/router' +import i18n from '../i18n' + +jest.mock('vue-apollo') +jest.mock('../store/store') +jest.mock('../router/router') +jest.mock('../i18n') + +jest.mock('apollo-boost', () => { + return { + __esModule: true, + ApolloClient: jest.fn(), + ApolloLink: jest.fn(() => { + return { concat: jest.fn() } + }), + InMemoryCache: jest.fn(), + HttpLink: jest.fn(), + } +}) + +describe('apolloProvider', () => { + it('calls the HttpLink', () => { + expect(HttpLink).toBeCalledWith({ uri: CONFIG.GRAPHQL_URI }) + }) + + it('calls the ApolloLink', () => { + expect(ApolloLink).toBeCalled() + }) + + it('calls the ApolloClient', () => { + expect(ApolloClient).toBeCalled() + }) + + it('calls the VueApollo', () => { + expect(VueApollo).toBeCalled() + }) + + describe('ApolloLink', () => { + // mock store + const storeDispatchMock = jest.fn() + const storeCommitMock = jest.fn() + store.state = { + token: 'some-token', + } + store.dispatch = storeDispatchMock + store.commit = storeCommitMock + + // mock i18n.t + i18n.t = jest.fn((t) => t) + + // mock apllo response + const responseMock = { + errors: [{ message: '403.13 - Client certificate revoked' }], + } + + // mock router + const routerPushMock = jest.fn() + router.push = routerPushMock + router.currentRoute = { + path: '/overview', + } + + // mock context + const setContextMock = jest.fn() + const getContextMock = jest.fn(() => { + return { + response: { + headers: { + get: jest.fn(() => 'another-token'), + }, + }, + } + }) + + // mock apollo link function params + const operationMock = { + setContext: setContextMock, + getContext: getContextMock, + } + + const forwardMock = jest.fn(() => { + return [responseMock] + }) + + // get apollo link callback + const middleware = ApolloLink.mock.calls[0][0] + + describe('with token in store', () => { + it('sets authorization header with token', () => { + // run the apollo link callback with mocked params + middleware(operationMock, forwardMock) + expect(setContextMock).toBeCalledWith({ + headers: { + Authorization: 'Bearer some-token', + }, + }) + }) + }) + + describe('without token in store', () => { + beforeEach(() => { + store.state.token = null + }) + + it('sets authorization header empty', () => { + middleware(operationMock, forwardMock) + expect(setContextMock).toBeCalledWith({ + headers: { + Authorization: '', + }, + }) + }) + }) + + describe('apollo response is 403.13', () => { + beforeEach(() => { + // run the apollo link callback with mocked params + middleware(operationMock, forwardMock) + }) + + it('dispatches logout', () => { + expect(storeDispatchMock).toBeCalledWith('logout', null) + }) + + describe('current route is not login', () => { + it('redirects to logout', () => { + expect(routerPushMock).toBeCalledWith('/login') + }) + }) + + describe('current route is login', () => { + beforeEach(() => { + jest.clearAllMocks() + router.currentRoute.path = '/login' + }) + + it('does not redirect to login', () => { + expect(routerPushMock).not.toBeCalled() + }) + }) + }) + + describe('apollo response is with new token', () => { + beforeEach(() => { + delete responseMock.errors + middleware(operationMock, forwardMock) + }) + + it('commits new token to store', () => { + expect(storeCommitMock).toBeCalledWith('token', 'another-token') + }) + }) + + describe('apollo response is without new token', () => { + beforeEach(() => { + jest.clearAllMocks() + getContextMock.mockReturnValue({ + response: { + headers: { + get: jest.fn(() => null), + }, + }, + }) + middleware(operationMock, forwardMock) + }) + + it('does not commit token to store', () => { + expect(storeCommitMock).not.toBeCalled() + }) + }) + }) +}) From 3fff3cce67deb23fbeaf396c8446a265549d894d Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 7 Dec 2021 19:12:01 +0100 Subject: [PATCH 69/74] unit test coverage to 69% in Admin Interface --- .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 e2488d050..0435d0c76 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -441,7 +441,7 @@ jobs: report_name: Coverage Admin Interface type: lcov result_path: ./coverage/lcov.info - min_coverage: 60 + min_coverage: 69 token: ${{ github.token }} ############################################################################## From 811c24067941c598e45ef2e76196dc67a1a9d00e Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 7 Dec 2021 19:14:54 +0100 Subject: [PATCH 70/74] redirect to logout --- admin/src/plugins/apolloProvider.js | 2 +- admin/src/plugins/apolloProvider.test.js | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/admin/src/plugins/apolloProvider.js b/admin/src/plugins/apolloProvider.js index ec7df38f1..0e342b8fc 100644 --- a/admin/src/plugins/apolloProvider.js +++ b/admin/src/plugins/apolloProvider.js @@ -18,7 +18,7 @@ const authLink = new ApolloLink((operation, forward) => { if (response.errors && response.errors[0].message === '403.13 - Client certificate revoked') { response.errors[0].message = i18n.t('error.session-expired') store.dispatch('logout', null) - if (router.currentRoute.path !== '/login') router.push('/login') + if (router.currentRoute.path !== '/logout') router.push('/logout') return response } const newToken = operation.getContext().response.headers.get('token') diff --git a/admin/src/plugins/apolloProvider.test.js b/admin/src/plugins/apolloProvider.test.js index 3610b5dae..e5f394e96 100644 --- a/admin/src/plugins/apolloProvider.test.js +++ b/admin/src/plugins/apolloProvider.test.js @@ -128,19 +128,19 @@ describe('apolloProvider', () => { expect(storeDispatchMock).toBeCalledWith('logout', null) }) - describe('current route is not login', () => { + describe('current route is not logout', () => { it('redirects to logout', () => { - expect(routerPushMock).toBeCalledWith('/login') + expect(routerPushMock).toBeCalledWith('/logout') }) }) - describe('current route is login', () => { + describe('current route is logout', () => { beforeEach(() => { jest.clearAllMocks() - router.currentRoute.path = '/login' + router.currentRoute.path = '/logout' }) - it('does not redirect to login', () => { + it('does not redirect to logout', () => { expect(routerPushMock).not.toBeCalled() }) }) From 8122f218a9cf34bbb38816b5c64c9a43e1464555 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Wed, 8 Dec 2021 11:14:34 +0100 Subject: [PATCH 71/74] render error message as it is --- frontend/src/views/Layout/DashboardLayout_gdd.vue | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/frontend/src/views/Layout/DashboardLayout_gdd.vue b/frontend/src/views/Layout/DashboardLayout_gdd.vue index 9487eadf7..8273685bd 100755 --- a/frontend/src/views/Layout/DashboardLayout_gdd.vue +++ b/frontend/src/views/Layout/DashboardLayout_gdd.vue @@ -133,9 +133,7 @@ export default { }) .catch((error) => { this.pending = true - if (error.message === 'GraphQL error: 403.13 - Client certificate revoked') { - this.$toasted.error(this.$t('error.session-expired')) - } + this.$toasted.error(error.message) // what to do when loading balance fails? }) }, From 88002a52097dcec2f60a24eb7d7451fdbc0e8128 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Wed, 8 Dec 2021 13:21:03 +0100 Subject: [PATCH 72/74] define custom error toast, use this custom toast for all error toasts --- frontend/src/main.js | 10 ++++++++++ frontend/src/mixins/getCommunityInfo.js | 2 +- frontend/src/plugins/dashboard-plugin.test.js | 20 +++++++++++++++++++ frontend/src/routes/router.test.js | 7 +++++++ .../views/Layout/DashboardLayout_gdd.spec.js | 6 ++++-- .../src/views/Layout/DashboardLayout_gdd.vue | 2 +- .../GdtTransactionList.spec.js | 4 +++- .../AccountOverview/GdtTransactionList.vue | 2 +- frontend/src/views/Pages/Login.spec.js | 4 +++- frontend/src/views/Pages/Login.vue | 2 +- frontend/src/views/Pages/Register.spec.js | 4 +++- .../src/views/Pages/RegisterCommunity.spec.js | 4 +++- .../Pages/RegisterSelectCommunity.spec.js | 4 +++- .../views/Pages/RegisterSelectCommunity.vue | 2 +- .../src/views/Pages/ResetPassword.spec.js | 4 +++- frontend/src/views/Pages/ResetPassword.vue | 4 ++-- .../UserCard_CoinAnimation.spec.js | 4 +++- .../UserProfile/UserCard_CoinAnimation.vue | 2 +- .../UserProfile/UserCard_FormUserData.spec.js | 4 +++- .../UserProfile/UserCard_FormUserData.vue | 2 +- .../UserCard_FormUserPasswort.spec.js | 4 +++- .../UserProfile/UserCard_FormUserPasswort.vue | 2 +- .../UserProfile/UserCard_FormUsername.spec.js | 4 +++- .../UserProfile/UserCard_FormUsername.vue | 2 +- .../UserProfile/UserCard_Language.spec.js | 4 +++- .../Pages/UserProfile/UserCard_Language.vue | 2 +- .../UserProfile/UserCard_Newsletter.spec.js | 4 +++- .../Pages/UserProfile/UserCard_Newsletter.vue | 2 +- 28 files changed, 90 insertions(+), 27 deletions(-) diff --git a/frontend/src/main.js b/frontend/src/main.js index 75dfdcedb..cbd7383aa 100755 --- a/frontend/src/main.js +++ b/frontend/src/main.js @@ -16,6 +16,16 @@ import { apolloProvider } from './plugins/apolloProvider' Vue.use(DashboardPlugin) Vue.config.productionTip = false +Vue.toasted.register( + 'error', + (payload) => { + return payload.replace(/^GraphQL error: /, '') + }, + { + type: 'error', + }, +) + loadAllRules(i18n) addNavigationGuards(router, store, apolloProvider.defaultClient) diff --git a/frontend/src/mixins/getCommunityInfo.js b/frontend/src/mixins/getCommunityInfo.js index f8fda6e45..3ca1c74cc 100644 --- a/frontend/src/mixins/getCommunityInfo.js +++ b/frontend/src/mixins/getCommunityInfo.js @@ -13,7 +13,7 @@ export const getCommunityInfoMixin = { return result.data.getCommunityInfo }) .catch((error) => { - this.$toasted.error(error.message) + this.$toasted.global.error(error.message) }) } }, diff --git a/frontend/src/plugins/dashboard-plugin.test.js b/frontend/src/plugins/dashboard-plugin.test.js index 3792ad2c4..25083c399 100644 --- a/frontend/src/plugins/dashboard-plugin.test.js +++ b/frontend/src/plugins/dashboard-plugin.test.js @@ -4,8 +4,11 @@ import Vue from 'vue' import GlobalComponents from './globalComponents' import GlobalDirectives from './globalDirectives' +import Toasted from 'vue-toasted' + jest.mock('./globalComponents') jest.mock('./globalDirectives') +jest.mock('vue-toasted') jest.mock('vue') @@ -22,4 +25,21 @@ describe('dashboard plugin', () => { it('installs the global directives', () => { expect(vueUseMock).toBeCalledWith(GlobalDirectives) }) + + describe('vue toasted', () => { + const toastedAction = vueUseMock.mock.calls[11][1].action.onClick + const goAwayMock = jest.fn() + const toastObject = { + goAway: goAwayMock, + } + + it('installs vue toasted', () => { + expect(vueUseMock).toBeCalledWith(Toasted, expect.anything()) + }) + + it('onClick calls goAway(0)', () => { + toastedAction({}, toastObject) + expect(goAwayMock).toBeCalledWith(0) + }) + }) }) diff --git a/frontend/src/routes/router.test.js b/frontend/src/routes/router.test.js index a85c7a291..bc2f3d340 100644 --- a/frontend/src/routes/router.test.js +++ b/frontend/src/routes/router.test.js @@ -143,6 +143,13 @@ describe('router', () => { }) }) + describe('password with param comingFrom', () => { + it('loads the "Password" component', async () => { + const component = await routes.find((r) => r.path === '/password/:comingFrom').component() + expect(component.default.name).toBe('password') + }) + }) + describe('register-community', () => { it('loads the "registerCommunity" component', async () => { const component = await routes.find((r) => r.path === '/register-community').component() diff --git a/frontend/src/views/Layout/DashboardLayout_gdd.spec.js b/frontend/src/views/Layout/DashboardLayout_gdd.spec.js index b25640e5c..231e36dcd 100644 --- a/frontend/src/views/Layout/DashboardLayout_gdd.spec.js +++ b/frontend/src/views/Layout/DashboardLayout_gdd.spec.js @@ -39,7 +39,9 @@ describe('DashboardLayoutGdd', () => { }, }, $toasted: { - error: toasterMock, + global: { + error: toasterMock, + }, }, $apollo: { query: apolloMock, @@ -266,7 +268,7 @@ describe('DashboardLayoutGdd', () => { expect(wrapper.vm.pending).toBeTruthy() }) - it('calls $toasted.error method', () => { + it('calls $toasted.global.error method', () => { expect(toasterMock).toBeCalledWith('Ouch!') }) }) diff --git a/frontend/src/views/Layout/DashboardLayout_gdd.vue b/frontend/src/views/Layout/DashboardLayout_gdd.vue index 8273685bd..a9859145b 100755 --- a/frontend/src/views/Layout/DashboardLayout_gdd.vue +++ b/frontend/src/views/Layout/DashboardLayout_gdd.vue @@ -133,7 +133,7 @@ export default { }) .catch((error) => { this.pending = true - this.$toasted.error(error.message) + this.$toasted.global.error(error.message) // what to do when loading balance fails? }) }, diff --git a/frontend/src/views/Pages/AccountOverview/GdtTransactionList.spec.js b/frontend/src/views/Pages/AccountOverview/GdtTransactionList.spec.js index 77507cb69..a03122527 100644 --- a/frontend/src/views/Pages/AccountOverview/GdtTransactionList.spec.js +++ b/frontend/src/views/Pages/AccountOverview/GdtTransactionList.spec.js @@ -37,7 +37,9 @@ describe('GdtTransactionList ', () => { $n: jest.fn((n) => n), $d: jest.fn((d) => d), $toasted: { - error: toastErrorMock, + global: { + error: toastErrorMock, + }, }, $apollo: { query: apolloMock, diff --git a/frontend/src/views/Pages/AccountOverview/GdtTransactionList.vue b/frontend/src/views/Pages/AccountOverview/GdtTransactionList.vue index 378aa3ece..9c8b51f5e 100644 --- a/frontend/src/views/Pages/AccountOverview/GdtTransactionList.vue +++ b/frontend/src/views/Pages/AccountOverview/GdtTransactionList.vue @@ -71,7 +71,7 @@ export default { window.scrollTo(0, 0) }) .catch((error) => { - this.$toasted.error(error.message) + this.$toasted.global.error(error.message) }) }, }, diff --git a/frontend/src/views/Pages/Login.spec.js b/frontend/src/views/Pages/Login.spec.js index a16a8ad54..34175d8b3 100644 --- a/frontend/src/views/Pages/Login.spec.js +++ b/frontend/src/views/Pages/Login.spec.js @@ -52,7 +52,9 @@ describe('Login', () => { push: mockRouterPush, }, $toasted: { - error: toastErrorMock, + global: { + error: toastErrorMock, + }, }, $apollo: { query: apolloQueryMock, diff --git a/frontend/src/views/Pages/Login.vue b/frontend/src/views/Pages/Login.vue index 0ce209551..d5d3e25a4 100755 --- a/frontend/src/views/Pages/Login.vue +++ b/frontend/src/views/Pages/Login.vue @@ -106,7 +106,7 @@ export default { }) .catch((error) => { if (error.message.includes('No user with this credentials')) { - this.$toasted.error(this.$t('error.no-account')) + this.$toasted.global.error(this.$t('error.no-account')) } else { // : this.$t('error.no-email-verify') this.$router.push('/reset/login') diff --git a/frontend/src/views/Pages/Register.spec.js b/frontend/src/views/Pages/Register.spec.js index b75c881c6..820229a4a 100644 --- a/frontend/src/views/Pages/Register.spec.js +++ b/frontend/src/views/Pages/Register.spec.js @@ -49,7 +49,9 @@ describe('Register', () => { }, }, $toasted: { - error: toastErrorMock, + global: { + error: toastErrorMock, + }, }, } diff --git a/frontend/src/views/Pages/RegisterCommunity.spec.js b/frontend/src/views/Pages/RegisterCommunity.spec.js index 63fd63276..477e5e08e 100644 --- a/frontend/src/views/Pages/RegisterCommunity.spec.js +++ b/frontend/src/views/Pages/RegisterCommunity.spec.js @@ -37,7 +37,9 @@ describe('RegisterCommunity', () => { }, }, $toasted: { - error: toastErrorMock, + global: { + error: toastErrorMock, + }, }, } diff --git a/frontend/src/views/Pages/RegisterSelectCommunity.spec.js b/frontend/src/views/Pages/RegisterSelectCommunity.spec.js index eba23cea4..ad80c7e38 100644 --- a/frontend/src/views/Pages/RegisterSelectCommunity.spec.js +++ b/frontend/src/views/Pages/RegisterSelectCommunity.spec.js @@ -79,7 +79,9 @@ describe('RegisterSelectCommunity', () => { show: spinnerMock, }, $toasted: { - error: toasterMock, + global: { + error: toasterMock, + }, }, } diff --git a/frontend/src/views/Pages/RegisterSelectCommunity.vue b/frontend/src/views/Pages/RegisterSelectCommunity.vue index f6914f1f2..ab46da03f 100644 --- a/frontend/src/views/Pages/RegisterSelectCommunity.vue +++ b/frontend/src/views/Pages/RegisterSelectCommunity.vue @@ -76,7 +76,7 @@ export default { ) }) .catch((error) => { - this.$toasted.error(error.message) + this.$toasted.global.error(error.message) }) loader.hide() this.pending = false diff --git a/frontend/src/views/Pages/ResetPassword.spec.js b/frontend/src/views/Pages/ResetPassword.spec.js index 36a2f169c..f3bbc7334 100644 --- a/frontend/src/views/Pages/ResetPassword.spec.js +++ b/frontend/src/views/Pages/ResetPassword.spec.js @@ -30,7 +30,9 @@ const createMockObject = (comingFrom) => { }, }, $toasted: { - error: toasterMock, + global: { + error: toasterMock, + }, }, $router: { push: routerPushMock, diff --git a/frontend/src/views/Pages/ResetPassword.vue b/frontend/src/views/Pages/ResetPassword.vue index 478a8db8c..3e6aef339 100644 --- a/frontend/src/views/Pages/ResetPassword.vue +++ b/frontend/src/views/Pages/ResetPassword.vue @@ -96,10 +96,10 @@ export default { }) .catch((error) => { if (error.message.includes('Code is older than 10 minutes')) { - this.$toasted.error(error.message) + this.$toasted.global.error(error.message) this.$router.push('/password/reset') } else { - this.$toasted.error(error.message) + this.$toasted.global.error(error.message) } }) }, diff --git a/frontend/src/views/Pages/UserProfile/UserCard_CoinAnimation.spec.js b/frontend/src/views/Pages/UserProfile/UserCard_CoinAnimation.spec.js index 59d1f72e5..64455a3e8 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_CoinAnimation.spec.js +++ b/frontend/src/views/Pages/UserProfile/UserCard_CoinAnimation.spec.js @@ -24,7 +24,9 @@ describe('UserCard_CoinAnimation', () => { }, $toasted: { success: toastSuccessMock, - error: toastErrorMock, + global: { + error: toastErrorMock, + }, }, $apollo: { mutate: mockAPIcall, diff --git a/frontend/src/views/Pages/UserProfile/UserCard_CoinAnimation.vue b/frontend/src/views/Pages/UserProfile/UserCard_CoinAnimation.vue index 21192af93..99d46ae9b 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_CoinAnimation.vue +++ b/frontend/src/views/Pages/UserProfile/UserCard_CoinAnimation.vue @@ -58,7 +58,7 @@ export default { }) .catch((error) => { this.CoinAnimationStatus = this.$store.state.coinanimation - this.$toasted.error(error.message) + this.$toasted.global.error(error.message) }) }, }, diff --git a/frontend/src/views/Pages/UserProfile/UserCard_FormUserData.spec.js b/frontend/src/views/Pages/UserProfile/UserCard_FormUserData.spec.js index b4cdc0fb7..23c9e2840 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_FormUserData.spec.js +++ b/frontend/src/views/Pages/UserProfile/UserCard_FormUserData.spec.js @@ -25,7 +25,9 @@ describe('UserCard_FormUserData', () => { }, $toasted: { success: toastSuccessMock, - error: toastErrorMock, + global: { + error: toastErrorMock, + }, }, $apollo: { mutate: mockAPIcall, diff --git a/frontend/src/views/Pages/UserProfile/UserCard_FormUserData.vue b/frontend/src/views/Pages/UserProfile/UserCard_FormUserData.vue index f22a48ccd..9f23c864d 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_FormUserData.vue +++ b/frontend/src/views/Pages/UserProfile/UserCard_FormUserData.vue @@ -124,7 +124,7 @@ export default { this.$toasted.success(this.$t('settings.name.change-success')) }) .catch((error) => { - this.$toasted.error(error.message) + this.$toasted.global.error(error.message) }) }, }, diff --git a/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js b/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js index 3997bb71e..1057f71f1 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js +++ b/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.spec.js @@ -17,7 +17,9 @@ describe('UserCard_FormUserPasswort', () => { $t: jest.fn((t) => t), $toasted: { success: toastSuccessMock, - error: toastErrorMock, + global: { + error: toastErrorMock, + }, }, $apollo: { mutate: changePasswordProfileMock, diff --git a/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.vue b/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.vue index 5235c4554..54ad39431 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.vue +++ b/frontend/src/views/Pages/UserProfile/UserCard_FormUserPasswort.vue @@ -85,7 +85,7 @@ export default { this.cancelEdit() }) .catch((error) => { - this.$toasted.error(error.message) + this.$toasted.global.error(error.message) }) }, }, diff --git a/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.spec.js b/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.spec.js index be3abbbee..5a3ee8cd6 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.spec.js +++ b/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.spec.js @@ -31,7 +31,9 @@ describe('UserCard_FormUsername', () => { }, $toasted: { success: toastSuccessMock, - error: toastErrorMock, + global: { + error: toastErrorMock, + }, }, $apollo: { mutate: mockAPIcall, diff --git a/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.vue b/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.vue index 90ac23884..6bae1abb4 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.vue +++ b/frontend/src/views/Pages/UserProfile/UserCard_FormUsername.vue @@ -100,7 +100,7 @@ export default { this.$toasted.success(this.$t('settings.name.change-success')) }) .catch((error) => { - this.$toasted.error(error.message) + this.$toasted.global.error(error.message) this.showUsername = true this.username = this.$store.state.username this.form.username = this.$store.state.username diff --git a/frontend/src/views/Pages/UserProfile/UserCard_Language.spec.js b/frontend/src/views/Pages/UserProfile/UserCard_Language.spec.js index f2acacd5b..e13d4a1d1 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_Language.spec.js +++ b/frontend/src/views/Pages/UserProfile/UserCard_Language.spec.js @@ -28,7 +28,9 @@ describe('UserCard_Language', () => { }, $toasted: { success: toastSuccessMock, - error: toastErrorMock, + global: { + error: toastErrorMock, + }, }, $apollo: { mutate: mockAPIcall, diff --git a/frontend/src/views/Pages/UserProfile/UserCard_Language.vue b/frontend/src/views/Pages/UserProfile/UserCard_Language.vue index 9315c747e..b53d08189 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_Language.vue +++ b/frontend/src/views/Pages/UserProfile/UserCard_Language.vue @@ -101,7 +101,7 @@ export default { }) .catch((error) => { this.language = this.$store.state.language - this.$toasted.error(error.message) + this.$toasted.global.error(error.message) }) }, buildTagFromLanguageString() { diff --git a/frontend/src/views/Pages/UserProfile/UserCard_Newsletter.spec.js b/frontend/src/views/Pages/UserProfile/UserCard_Newsletter.spec.js index facde1f36..766e13ce5 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_Newsletter.spec.js +++ b/frontend/src/views/Pages/UserProfile/UserCard_Newsletter.spec.js @@ -25,7 +25,9 @@ describe('UserCard_Newsletter', () => { }, $toasted: { success: toastSuccessMock, - error: toastErrorMock, + global: { + error: toastErrorMock, + }, }, $apollo: { mutate: mockAPIcall, diff --git a/frontend/src/views/Pages/UserProfile/UserCard_Newsletter.vue b/frontend/src/views/Pages/UserProfile/UserCard_Newsletter.vue index 31fd745b2..2499671cf 100644 --- a/frontend/src/views/Pages/UserProfile/UserCard_Newsletter.vue +++ b/frontend/src/views/Pages/UserProfile/UserCard_Newsletter.vue @@ -56,7 +56,7 @@ export default { }) .catch((error) => { this.newsletterState = this.$store.state.newsletterState - this.$toasted.error(error.message) + this.$toasted.global.error(error.message) }) }, }, From 9eb4e8603a7adc81ea7a5a3afa00608b7f8bce43 Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 10 Dec 2021 09:08:54 +0100 Subject: [PATCH 73/74] Withdrew * 10000 and / 10000 since we need to store the full value. --- backend/src/graphql/resolver/AdminResolver.ts | 4 ++-- backend/src/graphql/resolver/TransactionResolver.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index 3c03227d5..5be947cde 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -176,7 +176,7 @@ export class AdminResolver { } else { newBalance = lastUserTransaction.balance } - newBalance = Number(newBalance) + Number(parseInt(pendingCreation.amount.toString()) / 10000) + newBalance = Number(newBalance) + Number(parseInt(pendingCreation.amount.toString())) const newUserTransaction = new UserTransaction() newUserTransaction.userId = pendingCreation.userId @@ -194,7 +194,7 @@ export class AdminResolver { if (!userBalance) userBalance = balanceRepository.create() userBalance.userId = pendingCreation.userId - userBalance.amount = Number(newBalance * 10000) + userBalance.amount = Number(newBalance) userBalance.modified = new Date() userBalance.recordDate = userBalance.recordDate ? userBalance.recordDate : new Date() await balanceRepository.save(userBalance) diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index 58eb695ea..b2f4b4db5 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -428,7 +428,7 @@ async function addUserTransaction( if (lastUserTransaction) { newBalance += Number( await calculateDecay( - Number(lastUserTransaction.balance * 10000), + Number(lastUserTransaction.balance), lastUserTransaction.balanceDate, transaction.received, ).catch(() => { From 56dd218ee28daecbb10d51179a51ff737feeb2ce Mon Sep 17 00:00:00 2001 From: elweyn Date: Fri, 10 Dec 2021 09:14:22 +0100 Subject: [PATCH 74/74] Fix updatePendingCreation amount that is send back. --- 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 5be947cde..749f2f591 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -83,7 +83,7 @@ export class AdminResolver { await pendingCreationRepository.save(updatedCreation) const result = new UpdatePendingCreation() - result.amount = parseInt(updatedCreation.amount.toString()) + result.amount = parseInt(amount.toString()) result.memo = updatedCreation.memo result.date = updatedCreation.date result.moderator = updatedCreation.moderator