diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7e07cc8d3..0435d0c76 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: 87 + min_coverage: 90 token: ${{ github.token }} ############################################################################## @@ -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 }} ############################################################################## @@ -491,7 +491,7 @@ jobs: report_name: Coverage Backend type: lcov result_path: ./backend/coverage/lcov.info - min_coverage: 39 + min_coverage: 37 token: ${{ github.token }} ############################################################################## 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/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) diff --git a/admin/src/plugins/apolloProvider.js b/admin/src/plugins/apolloProvider.js new file mode 100644 index 000000000..0e342b8fc --- /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 !== '/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(), +}) + +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..e5f394e96 --- /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 logout', () => { + it('redirects to logout', () => { + expect(routerPushMock).toBeCalledWith('/logout') + }) + }) + + describe('current route is logout', () => { + beforeEach(() => { + jest.clearAllMocks() + router.currentRoute.path = '/logout' + }) + + it('does not redirect to logout', () => { + 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() + }) + }) + }) +}) diff --git a/backend/.env.dist b/backend/.env.dist index 1b485b8e4..ed9b26102 100644 --- a/backend/.env.dist +++ b/backend/.env.dist @@ -2,8 +2,6 @@ PORT=4000 JWT_SECRET=secret123 JWT_EXPIRES_IN=10m GRAPHIQL=false -LOGIN_API_URL=http://login-server:1201/ -COMMUNITY_API_URL=http://nginx/api/ GDT_API_URL=https://gdt.gradido.net DB_HOST=localhost DB_PORT=3306 diff --git a/backend/src/auth/INALIENABLE_RIGHTS.ts b/backend/src/auth/INALIENABLE_RIGHTS.ts index eb367d643..58a81ce52 100644 --- a/backend/src/auth/INALIENABLE_RIGHTS.ts +++ b/backend/src/auth/INALIENABLE_RIGHTS.ts @@ -4,10 +4,8 @@ export const INALIENABLE_RIGHTS = [ RIGHTS.LOGIN, RIGHTS.GET_COMMUNITY_INFO, RIGHTS.COMMUNITIES, - RIGHTS.LOGIN_VIA_EMAIL_VERIFICATION_CODE, RIGHTS.CREATE_USER, RIGHTS.SEND_RESET_PASSWORD_EMAIL, - RIGHTS.RESET_PASSWORD, + RIGHTS.SET_PASSWORD, RIGHTS.CHECK_USERNAME, - RIGHTS.CHECK_EMAIL, ] diff --git a/backend/src/auth/RIGHTS.ts b/backend/src/auth/RIGHTS.ts index fa750239e..6a2c05025 100644 --- a/backend/src/auth/RIGHTS.ts +++ b/backend/src/auth/RIGHTS.ts @@ -12,14 +12,12 @@ export enum RIGHTS { SUBSCRIBE_NEWSLETTER = 'SUBSCRIBE_NEWSLETTER', TRANSACTION_LIST = 'TRANSACTION_LIST', SEND_COINS = 'SEND_COINS', - LOGIN_VIA_EMAIL_VERIFICATION_CODE = 'LOGIN_VIA_EMAIL_VERIFICATION_CODE', LOGOUT = 'LOGOUT', CREATE_USER = 'CREATE_USER', SEND_RESET_PASSWORD_EMAIL = 'SEND_RESET_PASSWORD_EMAIL', - RESET_PASSWORD = 'RESET_PASSWORD', + SET_PASSWORD = 'SET_PASSWORD', UPDATE_USER_INFOS = 'UPDATE_USER_INFOS', CHECK_USERNAME = 'CHECK_USERNAME', - CHECK_EMAIL = 'CHECK_EMAIL', HAS_ELOPAGE = 'HAS_ELOPAGE', // Admin SEARCH_USERS = 'SEARCH_USERS', diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index eab1b4608..a12524a78 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -8,8 +8,6 @@ const server = { JWT_SECRET: process.env.JWT_SECRET || 'secret123', JWT_EXPIRES_IN: process.env.JWT_EXPIRES_IN || '10m', GRAPHIQL: process.env.GRAPHIQL === 'true' || false, - LOGIN_API_URL: process.env.LOGIN_API_URL || 'http://login-server:1201/', - COMMUNITY_API_URL: process.env.COMMUNITY_API_URL || 'http://nginx/api/', GDT_API_URL: process.env.GDT_API_URL || 'https://gdt.gradido.net', PRODUCTION: process.env.NODE_ENV === 'production' || false, } @@ -53,6 +51,7 @@ 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/reset/$1', } const webhook = { diff --git a/backend/src/graphql/arg/ChangePasswordArgs.ts b/backend/src/graphql/arg/ChangePasswordArgs.ts deleted file mode 100644 index 4c2efae60..000000000 --- a/backend/src/graphql/arg/ChangePasswordArgs.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { ArgsType, Field } from 'type-graphql' - -@ArgsType() -export default class ChangePasswordArgs { - @Field(() => Number) - sessionId: number - - @Field(() => String) - email: string - - @Field(() => String) - password: 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/model/LoginViaVerificationCode.ts b/backend/src/graphql/model/LoginViaVerificationCode.ts deleted file mode 100644 index 61286ca0e..000000000 --- a/backend/src/graphql/model/LoginViaVerificationCode.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 LoginViaVerificationCode { - constructor(json: any) { - this.sessionId = json.session_id - this.email = json.user.email - } - - @Field(() => Number) - sessionId: number - - @Field(() => String) - email: string -} 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/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index 3c03227d5..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 @@ -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(() => { diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index ce403ac0e..bebc32e1e 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -3,24 +3,16 @@ import fs from 'fs' import { Resolver, Query, Args, Arg, Authorized, Ctx, UseMiddleware, Mutation } from 'type-graphql' -import { getConnection, getCustomRepository } from 'typeorm' +import { getConnection, getCustomRepository, getRepository } 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 '../../auth/JWT' -import ChangePasswordArgs from '../arg/ChangePasswordArgs' import CheckUsernameArgs from '../arg/CheckUsernameArgs' import CreateUserArgs from '../arg/CreateUserArgs' import UnsecureLoginArgs from '../arg/UnsecureLoginArgs' import UpdateUserInfosArgs from '../arg/UpdateUserInfosArgs' -import { apiPost, apiGet } from '../../apis/HttpRequest' -import { - klicktippRegistrationMiddleware, - klicktippNewsletterStateMiddleware, -} from '../../middleware/klicktippMiddleware' -import { CheckEmailResponse } from '../model/CheckEmailResponse' +import { klicktippNewsletterStateMiddleware } from '../../middleware/klicktippMiddleware' import { UserSettingRepository } from '../../typeorm/repository/UserSettingRepository' import { LoginUserRepository } from '../../typeorm/repository/LoginUser' import { Setting } from '../enum/Setting' @@ -30,10 +22,14 @@ import { LoginUserBackup } from '@entity/LoginUserBackup' import { LoginEmailOptIn } from '@entity/LoginEmailOptIn' import { sendEMail } from '../../util/sendEMail' import { LoginElopageBuysRepository } from '../../typeorm/repository/LoginElopageBuys' +import { signIn } from '../../apis/KlicktippController' import { RIGHTS } from '../../auth/RIGHTS' import { ServerUserRepository } from '../../typeorm/repository/ServerUser' import { ROLE_ADMIN } from '../../auth/ROLES' +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 @@ -58,50 +54,8 @@ const PassphraseGenerate = (): string[] => { result.push(WORDS[sodium.randombytes_random() % 2048]) } return result - /* - return [ - 'behind', - 'salmon', - 'fluid', - 'orphan', - 'frost', - 'elder', - 'amateur', - 'always', - 'panel', - 'palm', - 'leopard', - 'essay', - 'punch', - 'title', - 'fun', - 'annual', - 'page', - 'hundred', - 'journey', - 'select', - 'figure', - 'tunnel', - 'casual', - 'bar', - ] - */ } -/* -Test results: -INSERT INTO `login_users` (`id`, `email`, `first_name`, `last_name`, `username`, `description`, `password`, `pubkey`, `privkey`, `email_hash`, `created`, `email_checked`, `passphrase_shown`, `language`, `disabled`, `group_id`, `publisher_id`) VALUES -// old -(1, 'peter@lustig.de', 'peter', 'lustig', '', '', 4747956395458240931, 0x8c75edd507f470e5378f927489374694d68f3d155523f1c4402c36affd35a7ed, 0xb0e310655726b088631ccfd31ad6470ee50115c161dde8559572fa90657270ff13dc1200b2d3ea90dfbe92f3a4475ee4d9cee4989e39736a0870c33284bc73a8ae690e6da89f241a121eb3b500c22885, 0x9f700e6f6ec351a140b674c0edd4479509697b023bd8bee8826915ef6c2af036, '2021-11-03 20:05:04', 0, 0, 'de', 0, 1, 0); -// new -(2, 'peter@lustig.de', 'peter', 'lustig', '', '', 4747956395458240931, 0x8c75edd507f470e5378f927489374694d68f3d155523f1c4402c36affd35a7ed, 0xb0e310655726b088631ccfd31ad6470ee50115c161dde8559572fa90657270ff13dc1200b2d3ea90dfbe92f3a4475ee4d9cee4989e39736a0870c33284bc73a8ae690e6da89f241a121eb3b500c22885, 0x9f700e6f6ec351a140b674c0edd4479509697b023bd8bee8826915ef6c2af036, '2021-11-03 20:22:15', 0, 0, 'de', 0, 1, 0); -INSERT INTO `login_user_backups` (`id`, `user_id`, `passphrase`, `mnemonic_type`) VALUES -// old -(1, 1, 'behind salmon fluid orphan frost elder amateur always panel palm leopard essay punch title fun annual page hundred journey select figure tunnel casual bar ', 2); -// new -(2, 2, 'behind salmon fluid orphan frost elder amateur always panel palm leopard essay punch title fun annual page hundred journey select figure tunnel casual bar ', 2); -*/ - const KeyPairEd25519Create = (passphrase: string[]): Buffer[] => { if (!passphrase.length || passphrase.length < PHRASE_WORD_COUNT) { throw new Error('passphrase empty or to short') @@ -240,13 +194,21 @@ 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') }) - if (!loginUser.emailChecked) throw new Error('user email not validated') + if (!loginUser.emailChecked) { + throw new Error('User email not validated') + } + if (loginUser.password === BigInt(0)) { + // TODO we want to catch this on the frontend and ask the user to check his emails or resend code + throw new Error('User has no password set yet') + } + if (!loginUser.pubKey || !loginUser.privKey) { + // TODO we want to catch this on the frontend and ask the user to check his emails or resend code + throw new Error('User has no private or publicKey') + } const passwordHash = SecretKeyCryptographyCreateKey(email, password) // return short and long hash const loginUserPassword = BigInt(loginUser.password.toString()) if (loginUserPassword !== passwordHash[0].readBigUInt64LE()) { @@ -320,22 +282,6 @@ export class UserResolver { return user } - @Authorized([RIGHTS.LOGIN_VIA_EMAIL_VERIFICATION_CODE]) - @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([RIGHTS.LOGOUT]) @Query(() => String) async logout(): Promise { @@ -350,7 +296,7 @@ export class UserResolver { @Authorized([RIGHTS.CREATE_USER]) @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; @@ -360,13 +306,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 = '' @@ -384,10 +323,10 @@ 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 keyPair = KeyPairEd25519Create(passphrase) // return pub, priv Key + // const passwordHash = SecretKeyCryptographyCreateKey(email, password) // return short and long hash + // const encryptedPrivkey = SecretKeyCryptographyEncrypt(keyPair[1], passwordHash[1]) const emailHash = getEmailHash(email) - const encryptedPrivkey = SecretKeyCryptographyEncrypt(keyPair[1], passwordHash[1]) // Table: login_users const loginUser = new LoginUser() @@ -396,13 +335,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() @@ -428,11 +367,13 @@ export class UserResolver { // Table: state_users const dbUser = new DbUser() - dbUser.pubkey = keyPair[0] dbUser.email = email dbUser.firstName = firstName dbUser.lastName = lastName dbUser.username = username + // TODO this field has no null allowed unlike the loginServer table + dbUser.pubkey = Buffer.alloc(32, 0) // default to 0000... + // dbUser.pubkey = keyPair[0] await queryRunner.manager.save(dbUser).catch((er) => { // eslint-disable-next-line no-console @@ -441,10 +382,11 @@ export class UserResolver { }) // Store EmailOptIn in DB + // TODO: this has duplicate code with sendResetPasswordEmail const emailOptIn = new LoginEmailOptIn() emailOptIn.userId = loginUserId emailOptIn.verificationCode = random(64) - emailOptIn.emailOptInTypeId = 2 + emailOptIn.emailOptInTypeId = EMAIL_OPT_IN_REGISTER await queryRunner.manager.save(emailOptIn).catch((error) => { // eslint-disable-next-line no-console @@ -489,38 +431,172 @@ export class UserResolver { } @Authorized([RIGHTS.SEND_RESET_PASSWORD_EMAIL]) - @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 { + // TODO: this has duplicate code with createUser + // TODO: Moriz: I think we do not need this variable. + let emailAlreadySend = false + + const loginUserRepository = await getCustomRepository(LoginUserRepository) + const loginUser = await loginUserRepository.findOneOrFail({ email }) + + const loginEmailOptInRepository = await getRepository(LoginEmailOptIn) + let optInCode = await loginEmailOptInRepository.findOne({ + userId: loginUser.id, + emailOptInTypeId: EMAIL_OPT_IN_RESET_PASSWORD, + }) + if (optInCode) { + emailAlreadySend = true + } else { + optInCode = new LoginEmailOptIn() + optInCode.verificationCode = random(64) + optInCode.userId = loginUser.id + optInCode.emailOptInTypeId = EMAIL_OPT_IN_RESET_PASSWORD + await loginEmailOptInRepository.save(optInCode) } - 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 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 } - @Authorized([RIGHTS.RESET_PASSWORD]) - @Mutation(() => String) - async resetPassword( - @Args() - { sessionId, email, password }: ChangePasswordArgs, - ): Promise { - const payload = { - session_id: sessionId, - email, - password, + @Authorized([RIGHTS.SET_PASSWORD]) + @Mutation(() => Boolean) + async setPassword( + @Arg('code') code: string, + @Arg('password') password: string, + ): Promise { + // 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!', + ) } - const result = await apiPost(CONFIG.LOGIN_API_URL + 'resetPassword', payload) - if (!result.success) { - throw new Error(result.data) + + // Load code + const loginEmailOptInRepository = await getRepository(LoginEmailOptIn) + const optInCode = await loginEmailOptInRepository + .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') } - return 'success' + + // load loginUser + const loginUserRepository = await getCustomRepository(LoginUserRepository) + const loginUser = await loginUserRepository + .findOneOrFail({ id: optInCode.userId }) + .catch(() => { + throw new Error('Could not find corresponding Login User') + }) + + // load user + const dbUserRepository = await getCustomRepository(UserRepository) + const dbUser = await dbUserRepository.findOneOrFail({ email: loginUser.email }).catch(() => { + throw new Error('Could not find corresponding User') + }) + + const loginUserBackupRepository = await getRepository(LoginUserBackup) + const loginUserBackup = await loginUserBackupRepository + .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 + + // 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 + dbUser.pubkey = keyPair[0] + + const queryRunner = getConnection().createQueryRunner() + await queryRunner.connect() + await queryRunner.startTransaction('READ UNCOMMITTED') + + try { + // Save loginUser + await queryRunner.manager.save(loginUser).catch((error) => { + throw new Error('error saving loginUser: ' + error) + }) + + // Save user + await queryRunner.manager.save(dbUser).catch((error) => { + throw new Error('error saving user: ' + error) + }) + + // Delete Code + await queryRunner.manager.remove(optInCode).catch((error) => { + throw new Error('error deleting code: ' + error) + }) + + await queryRunner.commitTransaction() + } catch (e) { + await queryRunner.rollbackTransaction() + throw e + } finally { + await queryRunner.release() + } + + // Sign into Klicktipp + // TODO do we always signUp the user? How to handle things with old users? + if (optInCode.emailOptInTypeId === EMAIL_OPT_IN_REGISTER) { + try { + await signIn(loginUser.email, loginUser.language, loginUser.firstName, loginUser.lastName) + } catch { + // TODO is this a problem? + // eslint-disable-next-line no-console + console.log('Could not subscribe to klicktipp') + } + } + + return true } @Authorized([RIGHTS.UPDATE_USER_INFOS]) @@ -656,19 +732,6 @@ export class UserResolver { return true } - @Authorized([RIGHTS.CHECK_EMAIL]) - @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([RIGHTS.HAS_ELOPAGE]) @Query(() => Boolean) async hasElopage(@Ctx() context: any): Promise { diff --git a/backend/src/middleware/klicktippMiddleware.ts b/backend/src/middleware/klicktippMiddleware.ts index e81087097..69a74480d 100644 --- a/backend/src/middleware/klicktippMiddleware.ts +++ b/backend/src/middleware/klicktippMiddleware.ts @@ -1,20 +1,20 @@ import { MiddlewareFn } from 'type-graphql' -import { signIn, getKlickTippUser } from '../apis/KlicktippController' +import { /* signIn, */ getKlickTippUser } from '../apis/KlicktippController' import { KlickTipp } from '../graphql/model/KlickTipp' import CONFIG from '../config/index' -export const klicktippRegistrationMiddleware: MiddlewareFn = async ( - // Only for demo - /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ - { root, args, context, info }, - next, -) => { - // Do Something here before resolver is called - const result = await next() - // Do Something here after resolver is completed - await signIn(result.email, result.language, result.firstName, result.lastName) - return result -} +// export const klicktippRegistrationMiddleware: MiddlewareFn = async ( +// // Only for demo +// /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ +// { root, args, context, info }, +// next, +// ) => { +// // Do Something here before resolver is called +// const result = await next() +// // Do Something here after resolver is completed +// await signIn(result.email, result.language, result.firstName, result.lastName) +// return result +// } export const klicktippNewsletterStateMiddleware: MiddlewareFn = async ( /* eslint-disable-next-line @typescript-eslint/no-unused-vars */ diff --git a/database/README.md b/database/README.md index f78eca113..8d490496b 100644 --- a/database/README.md +++ b/database/README.md @@ -39,6 +39,7 @@ yarn seed ## Seeded Users | email | password | admin | +|------------------------|------------|---------| | peter@lustig.de | `Aa12345_` | `true` | | bibi@bloxberg.de | `Aa12345_` | `false` | | raeuber@hotzenplotz.de | `Aa12345_` | `false` | diff --git a/database/entity/0001-init_db/Balance.ts b/database/entity/0001-init_db/Balance.ts index c1ca359f1..1a7050daf 100644 --- a/database/entity/0001-init_db/Balance.ts +++ b/database/entity/0001-init_db/Balance.ts @@ -1,4 +1,5 @@ -import { BaseEntity, Entity, PrimaryGeneratedColumn, Column } from 'typeorm' +import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, JoinColumn, OneToOne } from 'typeorm' +import { User } from '../User' @Entity('state_balances') export class Balance extends BaseEntity { @@ -16,4 +17,8 @@ export class Balance extends BaseEntity { @Column({ type: 'bigint' }) amount: number + + @OneToOne(() => User, { nullable: false }) + @JoinColumn({ name: 'state_user_id' }) + user: User } diff --git a/database/entity/0001-init_db/TransactionSignature.ts b/database/entity/0001-init_db/TransactionSignature.ts new file mode 100644 index 000000000..df3e02ba6 --- /dev/null +++ b/database/entity/0001-init_db/TransactionSignature.ts @@ -0,0 +1,21 @@ +import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm' +import { Transaction } from './Transaction' + +@Entity('transaction_signatures') +export class TransactionSignature extends BaseEntity { + @PrimaryGeneratedColumn() + id: number + + @Column({ name: 'transaction_id' }) + transactionId: number + + @Column({ type: 'binary', length: 64 }) + signature: Buffer + + @Column({ type: 'binary', length: 32 }) + pubkey: Buffer + + @ManyToOne(() => Transaction) + @JoinColumn({ name: 'transaction_id' }) + transaction: Transaction +} diff --git a/database/entity/0001-init_db/User.ts b/database/entity/0001-init_db/User.ts index 7280dca40..545d4f5c5 100644 --- a/database/entity/0001-init_db/User.ts +++ b/database/entity/0001-init_db/User.ts @@ -1,4 +1,5 @@ -import { BaseEntity, Entity, PrimaryGeneratedColumn, Column } from 'typeorm' +import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, OneToOne } from 'typeorm' +import { Balance } from '../Balance' // Moriz: I do not like the idea of having two user tables @Entity('state_users') @@ -29,4 +30,7 @@ export class User extends BaseEntity { @Column() disabled: boolean + + @OneToOne(() => Balance, (balance) => balance.user) + balance: Balance } diff --git a/database/entity/TransactionSignature.ts b/database/entity/TransactionSignature.ts new file mode 100644 index 000000000..e3c9cbe1c --- /dev/null +++ b/database/entity/TransactionSignature.ts @@ -0,0 +1 @@ +export { TransactionSignature } from './0001-init_db/TransactionSignature' diff --git a/database/entity/index.ts b/database/entity/index.ts index 92b3875f8..9d3b10ea7 100644 --- a/database/entity/index.ts +++ b/database/entity/index.ts @@ -8,6 +8,7 @@ import { Migration } from './Migration' import { ServerUser } from './ServerUser' import { Transaction } from './Transaction' import { TransactionCreation } from './TransactionCreation' +import { TransactionSignature } from './TransactionSignature' import { TransactionSendCoin } from './TransactionSendCoin' import { User } from './User' import { UserSetting } from './UserSetting' @@ -25,6 +26,7 @@ export const entities = [ ServerUser, Transaction, TransactionCreation, + TransactionSignature, TransactionSendCoin, User, UserSetting, diff --git a/database/migrations/0004-login_server_data.ts b/database/migrations/0004-login_server_data.ts index 554125eed..6d67dcdcb 100644 --- a/database/migrations/0004-login_server_data.ts +++ b/database/migrations/0004-login_server_data.ts @@ -25,34 +25,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? diff --git a/database/src/factories/balance.factory.ts b/database/src/factories/balance.factory.ts new file mode 100644 index 000000000..2c344be99 --- /dev/null +++ b/database/src/factories/balance.factory.ts @@ -0,0 +1,18 @@ +import Faker from 'faker' +import { define } from 'typeorm-seeding' +import { Balance } from '../../entity/Balance' +import { BalanceContext } from '../interface/TransactionContext' + +define(Balance, (faker: typeof Faker, context?: BalanceContext) => { + if (!context || !context.user) { + throw new Error('Balance: No user present!') + } + + const balance = new Balance() + balance.modified = context.modified ? context.modified : faker.date.recent() + balance.recordDate = context.recordDate ? context.recordDate : faker.date.recent() + balance.amount = context.amount ? context.amount : 10000000 + balance.user = context.user + + return balance +}) diff --git a/database/src/factories/transaction-creation.factory.ts b/database/src/factories/transaction-creation.factory.ts new file mode 100644 index 000000000..ec0b9e8a6 --- /dev/null +++ b/database/src/factories/transaction-creation.factory.ts @@ -0,0 +1,18 @@ +import Faker from 'faker' +import { define } from 'typeorm-seeding' +import { TransactionCreation } from '../../entity/TransactionCreation' +import { TransactionCreationContext } from '../interface/TransactionContext' + +define(TransactionCreation, (faker: typeof Faker, context?: TransactionCreationContext) => { + if (!context || !context.userId || !context.transaction) { + throw new Error('TransactionCreation: No userId and/or transaction present!') + } + + const transactionCreation = new TransactionCreation() + transactionCreation.userId = context.userId + transactionCreation.amount = context.amount ? context.amount : 100000 + transactionCreation.targetDate = context.targetDate ? context.targetDate : new Date() + transactionCreation.transaction = context.transaction + + return transactionCreation +}) diff --git a/database/src/factories/transaction-signature.factory.ts b/database/src/factories/transaction-signature.factory.ts new file mode 100644 index 000000000..b79e15052 --- /dev/null +++ b/database/src/factories/transaction-signature.factory.ts @@ -0,0 +1,18 @@ +import Faker from 'faker' +import { define } from 'typeorm-seeding' +import { TransactionSignature } from '../../entity/TransactionSignature' +import { TransactionSignatureContext } from '../interface/TransactionContext' +import { randomBytes } from 'crypto' + +define(TransactionSignature, (faker: typeof Faker, context?: TransactionSignatureContext) => { + if (!context || !context.transaction) { + throw new Error('TransactionSignature: No transaction present!') + } + + const transactionSignature = new TransactionSignature() + transactionSignature.signature = context.signature ? context.signature : randomBytes(64) + transactionSignature.pubkey = context.pubkey ? context.pubkey : randomBytes(32) + transactionSignature.transaction = context.transaction + + return transactionSignature +}) diff --git a/database/src/factories/transaction.factory.ts b/database/src/factories/transaction.factory.ts new file mode 100644 index 000000000..4880ace5b --- /dev/null +++ b/database/src/factories/transaction.factory.ts @@ -0,0 +1,20 @@ +import Faker from 'faker' +import { define } from 'typeorm-seeding' +import { Transaction } from '../../entity/Transaction' +import { TransactionContext } from '../interface/TransactionContext' +import { randomBytes } from 'crypto' + +define(Transaction, (faker: typeof Faker, context?: TransactionContext) => { + if (!context) context = {} + + const transaction = new Transaction() + transaction.transactionTypeId = context.transactionTypeId ? context.transactionTypeId : 2 + transaction.txHash = context.txHash ? context.txHash : randomBytes(48) + transaction.memo = context.memo || context.memo === '' ? context.memo : faker.lorem.sentence() + transaction.received = context.received ? context.received : new Date() + transaction.blockchainTypeId = context.blockchainTypeId ? context.blockchainTypeId : 1 + if (context.transactionSendCoin) transaction.transactionSendCoin = context.transactionSendCoin + if (context.transactionCreation) transaction.transactionCreation = context.transactionCreation + + return transaction +}) diff --git a/database/src/factories/user-transaction.factory.ts b/database/src/factories/user-transaction.factory.ts new file mode 100644 index 000000000..7ea79235b --- /dev/null +++ b/database/src/factories/user-transaction.factory.ts @@ -0,0 +1,19 @@ +import Faker from 'faker' +import { define } from 'typeorm-seeding' +import { UserTransaction } from '../../entity/UserTransaction' +import { UserTransactionContext } from '../interface/TransactionContext' + +define(UserTransaction, (faker: typeof Faker, context?: UserTransactionContext) => { + if (!context || !context.userId || !context.transactionId) { + throw new Error('UserTransaction: No userId and/or transactionId present!') + } + + const userTransaction = new UserTransaction() + userTransaction.userId = context.userId + userTransaction.transactionId = context.transactionId + userTransaction.transactionTypeId = context.transactionTypeId ? context.transactionTypeId : 1 + userTransaction.balance = context.balance ? context.balance : 100000 + userTransaction.balanceDate = context.balanceDate ? context.balanceDate : new Date() + + return userTransaction +}) diff --git a/database/src/index.ts b/database/src/index.ts index ec5328a9a..94566c9f5 100644 --- a/database/src/index.ts +++ b/database/src/index.ts @@ -9,6 +9,7 @@ import { CreatePeterLustigSeed } from './seeds/users/peter-lustig.admin.seed' import { CreateBibiBloxbergSeed } from './seeds/users/bibi-bloxberg.seed' import { CreateRaeuberHotzenplotzSeed } from './seeds/users/raeuber-hotzenplotz.seed' import { CreateBobBaumeisterSeed } from './seeds/users/bob-baumeister.seed' +import { DecayStartBlockSeed } from './seeds/decay-start-block.seed' const run = async (command: string) => { // Database actions not supported by our migration library @@ -59,6 +60,7 @@ const run = async (command: string) => { root: process.cwd(), configName: 'ormconfig.js', }) + await runSeeder(DecayStartBlockSeed) await runSeeder(CreatePeterLustigSeed) await runSeeder(CreateBibiBloxbergSeed) await runSeeder(CreateRaeuberHotzenplotzSeed) diff --git a/database/src/interface/TransactionContext.ts b/database/src/interface/TransactionContext.ts new file mode 100644 index 000000000..481959c5f --- /dev/null +++ b/database/src/interface/TransactionContext.ts @@ -0,0 +1,52 @@ +import { Transaction } from '../../entity/Transaction' +import { TransactionSendCoin } from '../../entity/TransactionSendCoin' +import { TransactionCreation } from '../../entity/TransactionCreation' +import { User } from '../../entity/User' + +export interface TransactionContext { + transactionTypeId?: number + txHash?: Buffer + memo?: string + received?: Date + blockchainTypeId?: number + transactionSendCoin?: TransactionSendCoin + transactionCreation?: TransactionCreation +} + +export interface BalanceContext { + modified?: Date + recordDate?: Date + amount?: number + user?: User +} + +export interface TransactionSendCoinContext { + senderPublic?: Buffer + userId?: number + recipiantPublic?: Buffer + recipiantUserId?: number + amount?: number + senderFinalBalance?: number + transaction?: Transaction +} + +export interface TransactionCreationContext { + userId?: number + amount?: number + targetDate?: Date + transaction?: Transaction +} + +export interface UserTransactionContext { + userId?: number + transactionId?: number + transactionTypeId?: number + balance?: number + balanceDate?: Date +} + +export interface TransactionSignatureContext { + signature?: Buffer + pubkey?: Buffer + transaction?: Transaction +} diff --git a/database/src/interface/UserInterface.ts b/database/src/interface/UserInterface.ts index 942158593..70be6cff4 100644 --- a/database/src/interface/UserInterface.ts +++ b/database/src/interface/UserInterface.ts @@ -27,4 +27,14 @@ export interface UserInterface { modified?: Date // flag for admin isAdmin?: boolean + // flag for balance (creation of 1000 GDD) + addBalance?: boolean + // balance + balanceModified?: Date + recordDate?: Date + targetDate?: Date + amount?: number + creationTxHash?: Buffer + signature?: Buffer + signaturePubkey?: Buffer } diff --git a/database/src/seeds/decay-start-block.seed.ts b/database/src/seeds/decay-start-block.seed.ts new file mode 100644 index 000000000..fd62ee333 --- /dev/null +++ b/database/src/seeds/decay-start-block.seed.ts @@ -0,0 +1,17 @@ +import { Factory, Seeder } from 'typeorm-seeding' +import { Transaction } from '../../entity/Transaction' + +export class DecayStartBlockSeed implements Seeder { + public async run(factory: Factory): Promise { + await factory(Transaction)({ + transactionTypeId: 9, + txHash: Buffer.from( + '9c9c4152b8a4cfbac287eee18d2d262e9de756fae726fc0ca36b788564973fff00000000000000000000000000000000', + 'hex', + ), + memo: '', + received: new Date('2021-11-30T09:13:26'), + blockchainTypeId: 1, + }).create() + } +} diff --git a/database/src/seeds/helpers/user-helpers.ts b/database/src/seeds/helpers/user-helpers.ts index 805104519..bd46ecdee 100644 --- a/database/src/seeds/helpers/user-helpers.ts +++ b/database/src/seeds/helpers/user-helpers.ts @@ -5,16 +5,28 @@ import { ServerUserContext, LoginUserRolesContext, } from '../../interface/UserContext' +import { + BalanceContext, + TransactionContext, + TransactionCreationContext, + UserTransactionContext, + TransactionSignatureContext, +} from '../../interface/TransactionContext' import { UserInterface } from '../../interface/UserInterface' import { User } from '../../../entity/User' import { LoginUser } from '../../../entity/LoginUser' import { LoginUserBackup } from '../../../entity/LoginUserBackup' import { ServerUser } from '../../../entity/ServerUser' import { LoginUserRoles } from '../../../entity/LoginUserRoles' +import { Balance } from '../../../entity/Balance' +import { Transaction } from '../../../entity/Transaction' +import { TransactionSignature } from '../../../entity/TransactionSignature' +import { UserTransaction } from '../../../entity/UserTransaction' +import { TransactionCreation } from '../../../entity/TransactionCreation' import { Factory } from 'typeorm-seeding' export const userSeeder = async (factory: Factory, userData: UserInterface): Promise => { - await factory(User)(createUserContext(userData)).create() + const user = await factory(User)(createUserContext(userData)).create() const loginUser = await factory(LoginUser)(createLoginUserContext(userData)).create() await factory(LoginUserBackup)(createLoginUserBackupContext(userData, loginUser)).create() @@ -25,9 +37,26 @@ export const userSeeder = async (factory: Factory, userData: UserInterface): Pro // It works with LoginRoles empty!! await factory(LoginUserRoles)(createLoginUserRolesContext(loginUser)).create() } + + if (userData.addBalance) { + // create some GDD for the user + await factory(Balance)(createBalanceContext(userData, user)).create() + const transaction = await factory(Transaction)( + createTransactionContext(userData, 1, 'Herzlich Willkommen bei Gradido!'), + ).create() + await factory(TransactionCreation)( + createTransactionCreationContext(userData, user, transaction), + ).create() + await factory(UserTransaction)( + createUserTransactionContext(userData, user, transaction), + ).create() + await factory(TransactionSignature)( + createTransactionSignatureContext(userData, transaction), + ).create() + } } -export const createUserContext = (context: UserInterface): UserContext => { +const createUserContext = (context: UserInterface): UserContext => { return { pubkey: context.pubKey, email: context.email, @@ -38,7 +67,7 @@ export const createUserContext = (context: UserInterface): UserContext => { } } -export const createLoginUserContext = (context: UserInterface): LoginUserContext => { +const createLoginUserContext = (context: UserInterface): LoginUserContext => { return { email: context.email, firstName: context.firstName, @@ -59,7 +88,7 @@ export const createLoginUserContext = (context: UserInterface): LoginUserContext } } -export const createLoginUserBackupContext = ( +const createLoginUserBackupContext = ( context: UserInterface, loginUser: LoginUser, ): LoginUserBackupContext => { @@ -70,7 +99,7 @@ export const createLoginUserBackupContext = ( } } -export const createServerUserContext = (context: UserInterface): ServerUserContext => { +const createServerUserContext = (context: UserInterface): ServerUserContext => { return { role: context.role, username: context.username, @@ -83,9 +112,69 @@ export const createServerUserContext = (context: UserInterface): ServerUserConte } } -export const createLoginUserRolesContext = (loginUser: LoginUser): LoginUserRolesContext => { +const createLoginUserRolesContext = (loginUser: LoginUser): LoginUserRolesContext => { return { userId: loginUser.id, roleId: 1, } } + +const createBalanceContext = (context: UserInterface, user: User): BalanceContext => { + return { + modified: context.balanceModified, + recordDate: context.recordDate, + amount: context.amount, + user, + } +} + +const createTransactionContext = ( + context: UserInterface, + type: number, + memo: string, +): TransactionContext => { + return { + transactionTypeId: type, + txHash: context.creationTxHash, + memo, + received: context.recordDate, + } +} + +const createTransactionCreationContext = ( + context: UserInterface, + user: User, + transaction: Transaction, +): TransactionCreationContext => { + return { + userId: user.id, + amount: context.amount, + targetDate: context.targetDate, + transaction, + } +} + +const createUserTransactionContext = ( + context: UserInterface, + user: User, + transaction: Transaction, +): UserTransactionContext => { + return { + userId: user.id, + transactionId: transaction.id, + transactionTypeId: transaction.transactionTypeId, + balance: context.amount, + balanceDate: context.recordDate, + } +} + +const createTransactionSignatureContext = ( + context: UserInterface, + transaction: Transaction, +): TransactionSignatureContext => { + return { + signature: context.signature, + pubkey: context.signaturePubkey, + transaction, + } +} diff --git a/database/src/seeds/users/bibi-bloxberg.ts b/database/src/seeds/users/bibi-bloxberg.ts index d87e3eb4a..30ad4eb4c 100644 --- a/database/src/seeds/users/bibi-bloxberg.ts +++ b/database/src/seeds/users/bibi-bloxberg.ts @@ -22,4 +22,21 @@ export const bibiBloxberg = { 'knife normal level all hurdle crucial color avoid warrior stadium road bachelor affair topple hawk pottery right afford immune two ceiling budget glance hour ', mnemonicType: 2, isAdmin: false, + addBalance: true, + balanceModified: new Date('2021-11-30T10:37:11'), + recordDate: new Date('2021-11-30T10:37:11'), + targetDate: new Date('2021-08-01 00:00:00'), + amount: 10000000, + creationTxHash: Buffer.from( + '51103dc0fc2ca5d5d75a9557a1e899304e5406cfdb1328d8df6414d527b0118100000000000000000000000000000000', + 'hex', + ), + signature: Buffer.from( + '2a2c71f3e41adc060bbc3086577e2d57d24eeeb0a7727339c3f85aad813808f601d7e1df56a26e0929d2e67fc054fca429ccfa283ed2782185c7f009fe008f0c', + 'hex', + ), + signaturePubkey: Buffer.from( + '7281e0ee3258b08801f3ec73e431b4519677f65c03b0382c63a913b5784ee770', + 'hex', + ), } diff --git a/database/src/seeds/users/bob-baumeister.ts b/database/src/seeds/users/bob-baumeister.ts index 33ce35656..a6933d7c1 100644 --- a/database/src/seeds/users/bob-baumeister.ts +++ b/database/src/seeds/users/bob-baumeister.ts @@ -22,4 +22,21 @@ export const bobBaumeister = { 'detail master source effort unable waste tilt flush domain orchard art truck hint barrel response gate impose peanut secret merry three uncle wink resource ', mnemonicType: 2, isAdmin: false, + addBalance: true, + balanceModified: new Date('2021-11-30T10:37:14'), + recordDate: new Date('2021-11-30T10:37:14'), + targetDate: new Date('2021-08-01 00:00:00'), + amount: 10000000, + creationTxHash: Buffer.from( + 'be095dc87acb94987e71168fee8ecbf50ecb43a180b1006e75d573b35725c69c00000000000000000000000000000000', + 'hex', + ), + signature: Buffer.from( + '1fbd6b9a3d359923b2501557f3bc79fa7e428127c8090fb16bc490b4d87870ab142b3817ddd902d22f0b26472a483233784a0e460c0622661752a13978903905', + 'hex', + ), + signaturePubkey: Buffer.from( + '7281e0ee3258b08801f3ec73e431b4519677f65c03b0382c63a913b5784ee770', + 'hex', + ), } diff --git a/database/src/seeds/users/raeuber-hotzenplotz.ts b/database/src/seeds/users/raeuber-hotzenplotz.ts index 10fcf8af1..eb2118af5 100644 --- a/database/src/seeds/users/raeuber-hotzenplotz.ts +++ b/database/src/seeds/users/raeuber-hotzenplotz.ts @@ -22,4 +22,21 @@ export const raeuberHotzenplotz = { 'gospel trip tenant mouse spider skill auto curious man video chief response same little over expire drum display fancy clinic keen throw urge basket ', mnemonicType: 2, isAdmin: false, + addBalance: true, + balanceModified: new Date('2021-11-30T10:37:13'), + recordDate: new Date('2021-11-30T10:37:13'), + targetDate: new Date('2021-08-01 00:00:00'), + amount: 10000000, + creationTxHash: Buffer.from( + '23ba44fd84deb59b9f32969ad0cb18bfa4588be1bdb99c396888506474c16c1900000000000000000000000000000000', + 'hex', + ), + signature: Buffer.from( + '756d3da061687c575d1dbc5073908f646aa5f498b0927b217c83b48af471450e571dfe8421fb8e1f1ebd1104526b7e7c6fa78684e2da59c8f7f5a8dc3d9e5b0b', + 'hex', + ), + signaturePubkey: Buffer.from( + '7281e0ee3258b08801f3ec73e431b4519677f65c03b0382c63a913b5784ee770', + 'hex', + ), } 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/components/Inputs/InputPassword.vue b/frontend/src/components/Inputs/InputPassword.vue index 15ce116c9..b457e7673 100644 --- a/frontend/src/components/Inputs/InputPassword.vue +++ b/frontend/src/components/Inputs/InputPassword.vue @@ -23,6 +23,7 @@ variant="outline-light" @click="toggleShowPassword" class="border-left-0 rounded-right" + tabindex="-1" > diff --git a/frontend/src/components/SidebarPlugin/SideBar.spec.js b/frontend/src/components/SidebarPlugin/SideBar.spec.js new file mode 100644 index 000000000..3f1a29034 --- /dev/null +++ b/frontend/src/components/SidebarPlugin/SideBar.spec.js @@ -0,0 +1,200 @@ +import { mount, RouterLinkStub } from '@vue/test-utils' +import SideBar from './SideBar' + +const localVue = global.localVue + +const storeDispatchMock = jest.fn() + +describe('SideBar', () => { + let wrapper + + const stubs = { + RouterLink: RouterLinkStub, + } + + const propsData = { + balance: 1234.56, + } + + const mocks = { + $store: { + state: { + email: 'test@example.org', + publisherId: 123, + firstName: 'test', + lastName: 'example', + hasElopage: false, + }, + dispatch: storeDispatchMock, + }, + $i18n: { + locale: 'en', + }, + $t: jest.fn((t) => t), + $n: jest.fn((n) => n), + } + + const Wrapper = () => { + return mount(SideBar, { localVue, mocks, stubs, propsData }) + } + + describe('mount', () => { + beforeEach(() => { + wrapper = Wrapper() + }) + + it('renders the component', () => { + expect(wrapper.find('#sidenav-main').exists()).toBeTruthy() + }) + + describe('navbar button', () => { + it('has a navbar button', () => { + expect(wrapper.find('button.navbar-toggler').exists()).toBeTruthy() + }) + + it('calls showSidebar when clicked', async () => { + const spy = jest.spyOn(wrapper.vm.$sidebar, 'displaySidebar') + wrapper.find('button.navbar-toggler').trigger('click') + await wrapper.vm.$nextTick() + expect(spy).toHaveBeenCalledWith(true) + }) + }) + + describe('balance', () => { + it('shows em-dash as balance while loading', () => { + expect(wrapper.find('div.row.text-center').text()).toBe('— GDD') + }) + + it('shows the when loaded', async () => { + wrapper.setProps({ + pending: false, + }) + await wrapper.vm.$nextTick() + expect(wrapper.find('div.row.text-center').text()).toBe('1234.56 GDD') + }) + }) + + describe('close siedbar', () => { + it('calls closeSidebar when clicked', async () => { + const spy = jest.spyOn(wrapper.vm.$sidebar, 'displaySidebar') + wrapper.find('#sidenav-collapse-main').find('button.navbar-toggler').trigger('click') + await wrapper.vm.$nextTick() + expect(spy).toHaveBeenCalledWith(false) + }) + }) + + describe('static menu items', () => { + describe("member's area without publisher ID", () => { + it('has a link to the elopage', () => { + expect(wrapper.findAll('li').at(0).text()).toContain('members_area') + }) + + it('has a badge', () => { + expect(wrapper.findAll('li').at(0).text()).toContain('!') + }) + + it('links to the elopage registration', () => { + expect(wrapper.findAll('li').at(0).find('a').attributes('href')).toBe( + 'https://elopage.com/s/gradido/basic-de/payment?locale=en&prid=111&pid=123&firstName=test&lastName=example&email=test@example.org', + ) + }) + + describe('with locale="de"', () => { + beforeEach(() => { + mocks.$i18n.locale = 'de' + }) + + it('links to the German elopage registration when locale is set to de', () => { + expect(wrapper.findAll('li').at(0).find('a').attributes('href')).toBe( + 'https://elopage.com/s/gradido/basic-de/payment?locale=de&prid=111&pid=123&firstName=test&lastName=example&email=test@example.org', + ) + }) + }) + + describe("member's area with publisher ID", () => { + beforeEach(() => { + mocks.$store.state.hasElopage = true + }) + + it('links to the elopage member area', () => { + expect(wrapper.findAll('li').at(0).find('a').attributes('href')).toBe( + 'https://elopage.com/s/gradido/sign_in?locale=de', + ) + }) + + it('has no badge', () => { + expect(wrapper.findAll('li').at(0).text()).not.toContain('!') + }) + }) + + describe("member's area with default publisher ID and no elopage", () => { + beforeEach(() => { + mocks.$store.state.publisherId = null + mocks.$store.state.hasElopage = false + }) + + it('links to the elopage member area with default publisher ID', () => { + expect(wrapper.findAll('li').at(0).find('a').attributes('href')).toBe( + 'https://elopage.com/s/gradido/basic-de/payment?locale=de&prid=111&pid=2896&firstName=test&lastName=example&email=test@example.org', + ) + }) + + it('has a badge', () => { + expect(wrapper.findAll('li').at(0).text()).toContain('!') + }) + }) + }) + + describe('logout', () => { + it('has a logout button', () => { + expect(wrapper.findAll('li').at(1).text()).toBe('logout') + }) + + it('emits logout when logout is clicked', async () => { + wrapper.findAll('li').at(1).find('a').trigger('click') + await wrapper.vm.$nextTick() + expect(wrapper.emitted('logout')).toEqual([[]]) + }) + }) + + describe('admin-area', () => { + it('is not visible when not an admin', () => { + expect(wrapper.findAll('li').at(1).text()).not.toBe('admin_area') + }) + + describe('logged in as admin', () => { + const assignLocationSpy = jest.fn() + beforeEach(async () => { + mocks.$store.state.isAdmin = true + mocks.$store.state.token = 'valid-token' + delete window.location + window.location = { + assign: assignLocationSpy, + } + wrapper = Wrapper() + }) + + it('is visible', () => { + expect(wrapper.findAll('li').at(1).text()).toBe('admin_area') + }) + + describe('click on admin area', () => { + beforeEach(async () => { + await wrapper.findAll('li').at(1).find('a').trigger('click') + }) + + it('opens a new window when clicked', () => { + expect(assignLocationSpy).toHaveBeenCalledWith( + 'http://localhost/admin/authenticate?token=valid-token', + ) + }) + + it('dispatches logout to store', () => { + expect(storeDispatchMock).toHaveBeenCalledWith('logout') + }) + }) + }) + }) + }) + }) +}) diff --git a/frontend/src/graphql/mutations.js b/frontend/src/graphql/mutations.js index d1d3d583c..0c6ea51aa 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) } ` @@ -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/graphql/queries.js b/frontend/src/graphql/queries.js index 8b55f4098..d867e14ad 100644 --- a/frontend/src/graphql/queries.js +++ b/frontend/src/graphql/queries.js @@ -46,15 +46,6 @@ export const logout = gql` } ` -export const loginViaEmailVerificationCode = gql` - query($optin: String!) { - loginViaEmailVerificationCode(optin: $optin) { - sessionId - email - } - } -` - export const transactionsQuery = gql` query($currentPage: Int = 1, $pageSize: Int = 25, $order: Order = DESC) { transactionList(currentPage: $currentPage, pageSize: $pageSize, order: $order) { @@ -88,9 +79,7 @@ export const transactionsQuery = gql` export const sendResetPasswordEmail = gql` query($email: String!) { - sendResetPasswordEmail(email: $email) { - state - } + sendResetPasswordEmail(email: $email) } ` @@ -118,15 +107,6 @@ export const listGDTEntriesQuery = gql` } ` -export const checkEmailQuery = gql` - query($optin: String!) { - checkEmail(optin: $optin) { - email - sessionId - } - } -` - export const communityInfo = gql` query { getCommunityInfo { diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index 1e8bfb621..59cd60f00 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -48,7 +48,7 @@ "error": "Fehler", "no-account": "Leider konnten wir keinen Account finden mit diesen Daten!", "no-email-verify": "Die Email wurde noch nicht bestätigt, bitte überprüfe deine Emails und klicke auf den Aktivierungslink!", - "session-expired": "Sitzung abgelaufen!" + "session-expired": "Die Sitzung wurde aus Sicherheitsgründen beendet." }, "form": { "amount": "Betrag", @@ -145,12 +145,17 @@ "password": { "change-password": "Passwort ändern", "forgot_pwd": "Passwort vergessen?", + "not-authenticated": "Leider konnten wir dich nicht authentifizieren. Bitte wende dich an den Support.", + "resend_subtitle": "Dein Aktivierungslink ist abgelaufen, Du kannst hier ein neuen anfordern.", "reset": "Passwort zurücksetzen", "reset-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." }, "send_now": "Jetzt senden", + "set": "Passwort festlegen", + "set-password": { + "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 f473ff798..21a4f4ef9 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -48,7 +48,7 @@ "error": "Error", "no-account": "Unfortunately we could not find an account to the given data!", "no-email-verify": "Your email is not activated yet, please check your emails and click the activation link!", - "session-expired": "The session expired" + "session-expired": "The session was closed for security reasons." }, "form": { "amount": "Amount", @@ -145,12 +145,17 @@ "password": { "change-password": "Change password", "forgot_pwd": "Forgot password?", + "not-authenticated": "Unfortunately we could not authenticate you. Please contact the support.", + "resend_subtitle": "Your activation link is expired, here you can order a new one.", "reset": "Reset password", "reset-password": { - "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", + "set": "Set password", + "set-password": { + "text": "Now you can save a new password to login to the Gradido-App in the future." + }, "subtitle": "If you have forgotten your password, you can reset it here." } }, diff --git a/frontend/src/main.js b/frontend/src/main.js index 1aa945608..cbd7383aa 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,42 +10,22 @@ 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) 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/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..aeb02243c --- /dev/null +++ b/frontend/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.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() + 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() + }) + }) + }) +}) 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 cd26b6f6b..bc2f3d340 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', () => { @@ -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() @@ -167,7 +174,7 @@ describe('router', () => { describe('checkEmail', () => { it('loads the "CheckEmail" component', async () => { const component = await routes.find((r) => r.path === '/checkEmail/:optin').component() - expect(component.default.name).toBe('CheckEmail') + expect(component.default.name).toBe('ResetPassword') }) }) diff --git a/frontend/src/routes/routes.js b/frontend/src/routes/routes.js index f6975d09d..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 { @@ -62,6 +62,10 @@ const routes = [ path: '/password', component: () => import('../views/Pages/ForgotPassword.vue'), }, + { + path: '/password/:comingFrom', + component: () => import('../views/Pages/ForgotPassword.vue'), + }, { path: '/register-community', component: () => import('../views/Pages/RegisterCommunity.vue'), @@ -76,7 +80,7 @@ const routes = [ }, { path: '/checkEmail/:optin', - component: () => import('../views/Pages/CheckEmail.vue'), + component: () => import('../views/Pages/ResetPassword.vue'), }, { path: '*', component: NotFound }, ] diff --git a/frontend/src/views/Layout/DashboardLayout_gdd.spec.js b/frontend/src/views/Layout/DashboardLayout_gdd.spec.js index c17c66647..3e03bec2e 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, @@ -216,7 +218,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 e56629275..1932711ef 100755 --- a/frontend/src/views/Layout/DashboardLayout_gdd.vue +++ b/frontend/src/views/Layout/DashboardLayout_gdd.vue @@ -101,7 +101,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/CheckEmail.spec.js b/frontend/src/views/Pages/CheckEmail.spec.js deleted file mode 100644 index 2513d4b3f..000000000 --- a/frontend/src/views/Pages/CheckEmail.spec.js +++ /dev/null @@ -1,105 +0,0 @@ -import { mount, RouterLinkStub } from '@vue/test-utils' -import CheckEmail from './CheckEmail' - -const localVue = global.localVue - -const apolloQueryMock = jest.fn().mockRejectedValue({ message: 'error' }) - -const toasterMock = jest.fn() -const routerPushMock = jest.fn() - -describe('CheckEmail', () => { - 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: { - query: apolloQueryMock, - }, - } - - const stubs = { - RouterLink: RouterLinkStub, - } - - const Wrapper = () => { - return mount(CheckEmail, { localVue, mocks, stubs }) - } - - describe('mount', () => { - beforeEach(() => { - wrapper = Wrapper() - }) - - it('calls the checkEmail when created', async () => { - expect(apolloQueryMock).toBeCalledWith( - expect.objectContaining({ variables: { optin: '123' } }), - ) - }) - - describe('No valid optin', () => { - it('toasts an error when no valid optin is given', () => { - expect(toasterMock).toHaveBeenCalledWith('error') - }) - - it('has a message suggesting to contact the support', () => { - expect(wrapper.find('div.header').text()).toContain('checkEmail.title') - expect(wrapper.find('div.header').text()).toContain('checkEmail.errorText') - }) - }) - - describe('is authenticated', () => { - beforeEach(() => { - apolloQueryMock.mockResolvedValue({ - data: { - checkEmail: { - sessionId: 1, - email: 'user@example.org', - language: 'de', - }, - }, - }) - }) - - it.skip('Has sessionId from API call', async () => { - await wrapper.vm.$nextTick() - expect(wrapper.vm.sessionId).toBe(1) - }) - - describe('Register header', () => { - it('has a welcome message', async () => { - expect(wrapper.find('div.header').text()).toContain('checkEmail.title') - }) - }) - - describe('links', () => { - it('has a link "Back"', async () => { - expect(wrapper.findAllComponents(RouterLinkStub).at(0).text()).toEqual('back') - }) - - it('links to /login when clicking "Back"', async () => { - expect(wrapper.findAllComponents(RouterLinkStub).at(0).props().to).toBe('/Login') - }) - }) - }) - }) -}) diff --git a/frontend/src/views/Pages/CheckEmail.vue b/frontend/src/views/Pages/CheckEmail.vue deleted file mode 100644 index 1a23f6b09..000000000 --- a/frontend/src/views/Pages/CheckEmail.vue +++ /dev/null @@ -1,72 +0,0 @@ - - - diff --git a/frontend/src/views/Pages/ForgotPassword.spec.js b/frontend/src/views/Pages/ForgotPassword.spec.js index 91247d8a6..47c9fad56 100644 --- a/frontend/src/views/Pages/ForgotPassword.spec.js +++ b/frontend/src/views/Pages/ForgotPassword.spec.js @@ -8,30 +8,41 @@ const localVue = global.localVue const mockRouterPush = jest.fn() +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', () => { @@ -144,5 +155,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') + }) + }) }) }) diff --git a/frontend/src/views/Pages/ForgotPassword.vue b/frontend/src/views/Pages/ForgotPassword.vue index 444e94495..c8b31246f 100644 --- a/frontend/src/views/Pages/ForgotPassword.vue +++ b/frontend/src/views/Pages/ForgotPassword.vue @@ -5,8 +5,8 @@
-

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

-

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

+

{{ $t(displaySetup.headline) }}

+

{{ $t(displaySetup.subtitle) }}

@@ -22,7 +22,7 @@
- {{ $t('settings.password.send_now') }} + {{ $t(displaySetup.button) }}
@@ -41,6 +41,21 @@ import { sendResetPasswordEmail } from '../../graphql/queries' import InputEmail from '../../components/Inputs/InputEmail' +const textFields = { + reset: { + headline: 'settings.password.reset', + subtitle: 'settings.password.resend_subtitle', + button: 'settings.password.send_now', + cancel: 'back', + }, + login: { + headline: 'settings.password.reset', + subtitle: 'settings.password.subtitle', + button: 'settings.password.send_now', + cancel: 'back', + }, +} + export default { name: 'password', components: { @@ -52,6 +67,7 @@ export default { form: { email: '', }, + displaySetup: {}, } }, methods: { @@ -71,6 +87,13 @@ export default { }) }, }, + created() { + if (this.$route.params.comingFrom) { + this.displaySetup = textFields[this.$route.params.comingFrom] + } else { + this.displaySetup = textFields.login + } + }, } diff --git a/frontend/src/views/Pages/Login.spec.js b/frontend/src/views/Pages/Login.spec.js index 53bb9446f..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, @@ -238,7 +240,7 @@ describe('Login', () => { describe('login fails', () => { beforeEach(() => { apolloQueryMock.mockRejectedValue({ - message: 'Ouch!', + message: '..No user with this credentials', }) }) diff --git a/frontend/src/views/Pages/Login.vue b/frontend/src/views/Pages/Login.vue index 45e700099..d5d3e25a4 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')) { - this.$toasted.error(this.$t('error.no-account')) + if (error.message.includes('No user with this credentials')) { + this.$toasted.global.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() }) diff --git a/frontend/src/views/Pages/Register.spec.js b/frontend/src/views/Pages/Register.spec.js index d6814bd49..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, + }, }, } @@ -151,16 +153,10 @@ describe('Register', () => { expect(wrapper.find('#Email-input-field').exists()).toBeTruthy() }) - it('has password input fields', () => { - expect(wrapper.find('input[name="form.password"]').exists()).toBeTruthy() - }) - - it('has password repeat input fields', () => { - expect(wrapper.find('input[name="form.passwordRepeat"]').exists()).toBeTruthy() - }) it('has Language selected field', () => { expect(wrapper.find('.selectedLanguage').exists()).toBeTruthy() }) + it('selects Language value en', async () => { wrapper.find('.selectedLanguage').findAll('option').at(1).setSelected() expect(wrapper.find('.selectedLanguage').element.value).toBe('en') @@ -223,8 +219,6 @@ describe('Register', () => { wrapper.find('#registerFirstname').setValue('Max') wrapper.find('#registerLastname').setValue('Mustermann') wrapper.find('#Email-input-field').setValue('max.mustermann@gradido.net') - wrapper.find('input[name="form.password"]').setValue('Aa123456_') - wrapper.find('input[name="form.passwordRepeat"]').setValue('Aa123456_') wrapper.find('.language-switch-select').findAll('option').at(1).setSelected() wrapper.find('#publisherid').setValue('12345') }) @@ -280,7 +274,6 @@ describe('Register', () => { email: 'max.mustermann@gradido.net', firstName: 'Max', lastName: 'Mustermann', - password: 'Aa123456_', language: 'en', publisherId: 12345, }, diff --git a/frontend/src/views/Pages/Register.vue b/frontend/src/views/Pages/Register.vue index 8669781a4..070d80bb9 100755 --- a/frontend/src/views/Pages/Register.vue +++ b/frontend/src/views/Pages/Register.vue @@ -85,10 +85,6 @@
- @@ -194,14 +190,13 @@ 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) }) }, }, 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" 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"); diff --git a/login_server/src/cpp/model/gradido/TransactionCreation.cpp b/login_server/src/cpp/model/gradido/TransactionCreation.cpp index 7461b9bce..97fec92ee 100644 --- a/login_server/src/cpp/model/gradido/TransactionCreation.cpp +++ b/login_server/src/cpp/model/gradido/TransactionCreation.cpp @@ -74,8 +74,8 @@ namespace model { auto now = Poco::DateTime(); if (target_date.year() == now.year()) { - if (target_date.month() + 3 < now.month()) { - addError(new Error(function_name, "year is the same, target date month is more than 3 month in past")); + if (target_date.month() + 2 < now.month()) { + addError(new Error(function_name, "year is the same, target date month is more than 2 month in past")); return TRANSACTION_VALID_INVALID_TARGET_DATE; } if (target_date.month() > now.month()) { @@ -96,8 +96,8 @@ namespace model { else { // target_date.year +1 == now.year - if (target_date.month() + 3 < now.month() + 12) { - addError(new Error(function_name, "target date is more than 3 month in past")); + if (target_date.month() + 2 < now.month() + 12) { + addError(new Error(function_name, "target date is more than 2 month in past")); return TRANSACTION_VALID_INVALID_TARGET_DATE; } }