diff --git a/admin/package.json b/admin/package.json index 3e1522f91..e3c94f5d8 100644 --- a/admin/package.json +++ b/admin/package.json @@ -35,6 +35,7 @@ "identity-obj-proxy": "^3.0.0", "jest": "26.6.3", "moment": "^2.29.1", + "regenerator-runtime": "^0.13.9", "stats-webpack-plugin": "^0.7.0", "vue": "^2.6.11", "vue-apollo": "^3.0.8", diff --git a/admin/src/App.spec.js b/admin/src/App.spec.js new file mode 100644 index 000000000..b47141972 --- /dev/null +++ b/admin/src/App.spec.js @@ -0,0 +1,68 @@ +import { mount } from '@vue/test-utils' +import App from './App' + +const localVue = global.localVue + +const storeCommitMock = jest.fn() + +const mocks = { + $store: { + commit: storeCommitMock, + }, +} + +const localStorageMock = (() => { + let store = {} + + return { + getItem: (key) => { + return store[key] || null + }, + setItem: (key, value) => { + store[key] = value.toString() + }, + removeItem: (key) => { + delete store[key] + }, + clear: () => { + store = {} + }, + } +})() + +describe('App', () => { + let wrapper + + const Wrapper = () => { + return mount(App, { localVue, mocks }) + } + + describe('mount', () => { + beforeEach(() => { + wrapper = Wrapper() + }) + + it('has a div with id "app"', () => { + expect(wrapper.find('div#app').exists()).toBeTruthy() + }) + }) + + describe('window localStorage is undefined', () => { + it('does not commit a token to the store', () => { + expect(storeCommitMock).not.toBeCalled() + }) + }) + + describe('with token in local storage', () => { + beforeEach(() => { + Object.defineProperty(window, 'localStorage', { + value: localStorageMock, + }) + window.localStorage.setItem('vuex', JSON.stringify({ token: 1234 })) + }) + + it.skip('commits the token to the store', () => { + expect(storeCommitMock).toBeCalledWith('token', 1234) + }) + }) +}) diff --git a/admin/src/App.vue b/admin/src/App.vue index 70bc2978a..9267cc82b 100644 --- a/admin/src/App.vue +++ b/admin/src/App.vue @@ -1,19 +1,9 @@ diff --git a/admin/src/main.js b/admin/src/main.js index b3925c9fe..aa4cc3e03 100644 --- a/admin/src/main.js +++ b/admin/src/main.js @@ -1,6 +1,9 @@ import Vue from 'vue' import App from './App.vue' +// without this async calls are not working +import 'regenerator-runtime' + import store from './store/store' import router from './router/router' @@ -22,7 +25,9 @@ import moment from 'vue-moment' const httpLink = new HttpLink({ uri: CONFIG.GRAPHQL_URI }) const authLink = new ApolloLink((operation, forward) => { - const token = '' // store.state.token + + const token = store.state.token + operation.setContext({ headers: { Authorization: token && token.length > 0 ? `Bearer ${token}` : '', @@ -52,6 +57,7 @@ const apolloProvider = new VueApollo({ }) Vue.use(BootstrapVue) + Vue.use(IconsPlugin) Vue.use(moment) diff --git a/admin/src/store/store.js b/admin/src/store/store.js index 1dba6b9e3..38a210fe1 100644 --- a/admin/src/store/store.js +++ b/admin/src/store/store.js @@ -14,6 +14,9 @@ export const mutations = { resetOpenCreations: (state) => { state.openCreations = 0 }, + token: (state, token) => { + state.token = token + }, } const store = new Vuex.Store({ diff --git a/admin/src/store/store.test.js b/admin/src/store/store.test.js new file mode 100644 index 000000000..9ab9d980b --- /dev/null +++ b/admin/src/store/store.test.js @@ -0,0 +1,15 @@ +import { mutations } from './store' + +const { token } = mutations + +describe('Vuex store', () => { + describe('mutations', () => { + describe('token', () => { + it('sets the state of token', () => { + const state = { token: null } + token(state, '1234') + expect(state.token).toEqual('1234') + }) + }) + }) +}) diff --git a/admin/test/testSetup.js b/admin/test/testSetup.js index 118c0b1ce..3b6b50218 100644 --- a/admin/test/testSetup.js +++ b/admin/test/testSetup.js @@ -2,6 +2,9 @@ import { createLocalVue } from '@vue/test-utils' import Vue from 'vue' import { BootstrapVue } from 'bootstrap-vue' +// without this async calls are not working +import 'regenerator-runtime' + global.localVue = createLocalVue() global.localVue.use(BootstrapVue) diff --git a/admin/yarn.lock b/admin/yarn.lock index 0c8f9965e..d7960320b 100644 --- a/admin/yarn.lock +++ b/admin/yarn.lock @@ -10623,7 +10623,7 @@ regenerator-runtime@^0.11.0: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== -regenerator-runtime@^0.13.4: +regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.9: version "0.13.9" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index f21082d1d..7a55de8e8 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -51,7 +51,6 @@ const email = { EMAIL_PASSWORD: process.env.EMAIL_PASSWORD || 'xxx', EMAIL_SMTP_URL: process.env.EMAIL_SMTP_URL || 'gmail.com', EMAIL_SMTP_PORT: process.env.EMAIL_SMTP_PORT || '587', - EMAIL_LINK_VERIFICATION: process.env.EMAIL_LINK_VERIFICATION || 'http://localhost/vue/checkEmail/$1', } diff --git a/backend/src/graphql/directive/isAuthorized.ts b/backend/src/graphql/directive/isAuthorized.ts index d72f19456..6245ef8ba 100644 --- a/backend/src/graphql/directive/isAuthorized.ts +++ b/backend/src/graphql/directive/isAuthorized.ts @@ -2,9 +2,6 @@ import { AuthChecker } from 'type-graphql' -import CONFIG from '../../config' -import { apiGet } from '../../apis/HttpRequest' - import decode from '../../jwt/decode' import encode from '../../jwt/encode' @@ -13,7 +10,7 @@ const isAuthorized: AuthChecker = async ( ) => { if (context.token) { const decoded = decode(context.token) - context.pubKey = decoded.pubKey + context.pubKey = Buffer.from(decoded.pubKey).toString('hex') context.setHeaders.push({ key: 'token', value: encode(decoded.pubKey) }) return true } diff --git a/backend/src/graphql/model/User.ts b/backend/src/graphql/model/User.ts index 08651ae17..5b7682e01 100644 --- a/backend/src/graphql/model/User.ts +++ b/backend/src/graphql/model/User.ts @@ -10,15 +10,17 @@ export class User { @PrimaryGeneratedColumn() id: number */ - constructor(json: any) { - this.email = json.email - this.firstName = json.first_name - this.lastName = json.last_name - this.username = json.username - this.description = json.description - this.pubkey = json.public_hex - this.language = json.language - this.publisherId = json.publisher_id + constructor(json?: any) { + if (json) { + this.email = json.email + this.firstName = json.first_name + this.lastName = json.last_name + this.username = json.username + this.description = json.description + this.pubkey = json.public_hex + this.language = json.language + this.publisherId = json.publisher_id + } } @Field(() => String) diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index 968ce9d4c..ae9e318ae 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -613,9 +613,6 @@ export class TransactionResolver { await queryRunner.commitTransaction() } catch (e) { await queryRunner.rollbackTransaction() - throw e - } finally { - await queryRunner.release() // TODO: This is broken code - we should never correct an autoincrement index in production // according to dario it is required tho to properly work. The index of the table is used as // index for the transaction which requires a chain without gaps @@ -627,6 +624,9 @@ export class TransactionResolver { // eslint-disable-next-line no-console console.log('problems with reset auto increment: %o', error) }) + throw e + } finally { + await queryRunner.release() } // send notification email // TODO: translate diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index 5c4625938..25f83bb09 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -22,14 +22,14 @@ import { } from '../../middleware/klicktippMiddleware' import { CheckEmailResponse } from '../model/CheckEmailResponse' import { UserSettingRepository } from '../../typeorm/repository/UserSettingRepository' +import { LoginUserRepository } from '../../typeorm/repository/LoginUser' import { Setting } from '../enum/Setting' import { UserRepository } from '../../typeorm/repository/User' import { LoginUser } from '@entity/LoginUser' -import { LoginElopageBuys } from '@entity/LoginElopageBuys' import { LoginUserBackup } from '@entity/LoginUserBackup' import { LoginEmailOptIn } from '@entity/LoginEmailOptIn' import { sendEMail } from '../../util/sendEMail' -import { LoginUserRepository } from '../../typeorm/repository/LoginUser' +import { LoginElopageBuysRepository } from '../../typeorm/repository/LoginElopageBuys' // eslint-disable-next-line @typescript-eslint/no-var-requires const sodium = require('sodium-native') @@ -201,33 +201,32 @@ export class UserResolver { @Ctx() context: any, ): Promise { email = email.trim().toLowerCase() - const result = await apiPost(CONFIG.LOGIN_API_URL + 'unsecureLogin', { email, password }) - - // if there is no user, throw an authentication error - if (!result.success) { - throw new Error(result.data) - } - - context.setHeaders.push({ - key: 'token', - value: encode(result.data.user.public_hex), + // 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') }) - const user = new User(result.data.user) - // Hack: Database Field is not validated properly and not nullable - if (user.publisherId === 0) { - user.publisherId = undefined + const passwordHash = SecretKeyCryptographyCreateKey(email, password) // return short and long hash + const loginUserPassword = BigInt(loginUser.password.toString()) + if (loginUserPassword !== passwordHash[0].readBigUInt64LE()) { + throw new Error('No user with this credentials') } - user.hasElopage = result.data.hasElopage - // read additional settings from settings table + // TODO: If user has no pubKey Create it again and update user. + const userRepository = getCustomRepository(UserRepository) let userEntity: void | DbUser - userEntity = await userRepository.findByPubkeyHex(user.pubkey).catch(() => { + const loginUserPubKey = loginUser.pubKey + const loginUserPubKeyString = loginUserPubKey.toString('hex') + userEntity = await userRepository.findByPubkeyHex(loginUserPubKeyString).catch(() => { + // User not stored in state_users + // TODO: Check with production data - email is unique which can cause problems userEntity = new DbUser() - userEntity.firstName = user.firstName - userEntity.lastName = user.lastName - userEntity.username = user.username - userEntity.email = user.email - userEntity.pubkey = Buffer.from(user.pubkey, 'hex') + userEntity.firstName = loginUser.firstName + userEntity.lastName = loginUser.lastName + userEntity.username = loginUser.username + userEntity.email = loginUser.email + userEntity.pubkey = loginUser.pubKey userRepository.save(userEntity).catch(() => { throw new Error('error by save userEntity') @@ -237,16 +236,28 @@ export class UserResolver { throw new Error('error with cannot happen') } - // Save publisherId if Elopage is not yet registered + const user = new User() + user.email = email + user.firstName = loginUser.firstName + user.lastName = loginUser.lastName + user.username = loginUser.username + user.description = loginUser.description + user.pubkey = loginUserPubKeyString + user.language = loginUser.language + + // Elopage Status & Stored PublisherId + user.hasElopage = await this.hasElopage({ pubKey: loginUserPubKeyString }) if (!user.hasElopage && publisherId) { user.publisherId = publisherId - + // TODO: Check if we can use updateUserInfos + // await this.updateUserInfos({ publisherId }, { pubKey: loginUser.pubKey }) const loginUserRepository = getCustomRepository(LoginUserRepository) const loginUser = await loginUserRepository.findOneOrFail({ email: userEntity.email }) loginUser.publisherId = publisherId loginUserRepository.save(loginUser) } + // coinAnimation const userSettingRepository = getCustomRepository(UserSettingRepository) const coinanimation = await userSettingRepository .readBoolean(userEntity.id, Setting.COIN_ANIMATION) @@ -254,6 +265,12 @@ export class UserResolver { throw new Error(error) }) user.coinanimation = coinanimation + + context.setHeaders.push({ + key: 'token', + value: encode(loginUser.pubKey), + }) + return user } @@ -537,7 +554,7 @@ export class UserResolver { await queryRunner.startTransaction('READ UNCOMMITTED') try { - if (coinanimation) { + if (coinanimation !== null && coinanimation !== undefined) { queryRunner.manager .getCustomRepository(UserSettingRepository) .setOrUpdate(userEntity.id, Setting.COIN_ANIMATION, coinanimation.toString()) @@ -609,7 +626,8 @@ export class UserResolver { return false } - const elopageBuyCount = await LoginElopageBuys.count({ payerEmail: userEntity.email }) + const loginElopageBuysRepository = getCustomRepository(LoginElopageBuysRepository) + const elopageBuyCount = await loginElopageBuysRepository.count({ payerEmail: userEntity.email }) return elopageBuyCount > 0 } } diff --git a/backend/src/typeorm/repository/LoginElopageBuys.ts b/backend/src/typeorm/repository/LoginElopageBuys.ts new file mode 100644 index 000000000..15f2a8492 --- /dev/null +++ b/backend/src/typeorm/repository/LoginElopageBuys.ts @@ -0,0 +1,5 @@ +import { EntityRepository, Repository } from 'typeorm' +import { LoginElopageBuys } from '@entity/LoginElopageBuys' + +@EntityRepository(LoginElopageBuys) +export class LoginElopageBuysRepository extends Repository {} diff --git a/backend/src/typeorm/repository/LoginUser.ts b/backend/src/typeorm/repository/LoginUser.ts index d0db007d0..65ac6f67b 100644 --- a/backend/src/typeorm/repository/LoginUser.ts +++ b/backend/src/typeorm/repository/LoginUser.ts @@ -2,4 +2,10 @@ import { EntityRepository, Repository } from 'typeorm' import { LoginUser } from '@entity/LoginUser' @EntityRepository(LoginUser) -export class LoginUserRepository extends Repository {} +export class LoginUserRepository extends Repository { + async findByEmail(email: string): Promise { + return this.createQueryBuilder('loginUser') + .where('loginUser.email = :email', { email }) + .getOneOrFail() + } +} diff --git a/backend/src/typeorm/repository/User.ts b/backend/src/typeorm/repository/User.ts index 441c1b2c8..e127c179c 100644 --- a/backend/src/typeorm/repository/User.ts +++ b/backend/src/typeorm/repository/User.ts @@ -9,6 +9,15 @@ export class UserRepository extends Repository { .getOneOrFail() } + async findByPubkeyHexBuffer(pubkeyHexBuffer: Buffer): Promise { + const pubKeyString = pubkeyHexBuffer.toString('hex') + return await this.findByPubkeyHex(pubKeyString) + } + + async findByEmail(email: string): Promise { + return this.createQueryBuilder('user').where('user.email = :email', { email }).getOneOrFail() + } + async getUsersIndiced(userIds: number[]): Promise { if (!userIds.length) return [] const users = await this.createQueryBuilder('user') diff --git a/docker-compose.override.yml b/docker-compose.override.yml index bd23b43b3..9f3d3d618 100644 --- a/docker-compose.override.yml +++ b/docker-compose.override.yml @@ -1,170 +1,166 @@ -version: "3.4" - -services: - ######################################################## - # FRONTEND ############################################# - ######################################################## - frontend: - image: gradido/frontend:development - build: - target: development - networks: - - external-net - environment: - - NODE_ENV="development" - # - DEBUG=true - volumes: - # This makes sure the docker container has its own node modules. - # Therefore it is possible to have a different node version on the host machine - - frontend_node_modules:/app/node_modules - # bind the local folder to the docker to allow live reload - - ./frontend:/app - - ######################################################## - # ADMIN INTERFACE ###################################### - ######################################################## - admin: - image: gradido/admin:development - build: - target: development - networks: - - external-net - environment: - - NODE_ENV="development" - # - DEBUG=true - volumes: - # This makes sure the docker container has its own node modules. - # Therefore it is possible to have a different node version on the host machine - - admin_node_modules:/app/node_modules - # bind the local folder to the docker to allow live reload - - ./admin:/app - - ######################################################## - # BACKEND ############################################## - ######################################################## - backend: - image: gradido/backend:development - build: - target: development - networks: - - external-net - - internal-net - environment: - - NODE_ENV="development" - volumes: - # This makes sure the docker container has its own node modules. - # Therefore it is possible to have a different node version on the host machine - - backend_node_modules:/app/node_modules - - backend_database_node_modules:/database/node_modules - - backend_database_build:/database/build - # bind the local folder to the docker to allow live reload - - ./backend:/app - - ./database:/database - - ######################################################## - # DATABASE ############################################## - ######################################################## - database: - # we always run on production here since else the service lingers - # feel free to change this behaviour if it seems useful - # Due to problems with the volume caching the built files - # we changed this to test build. This keeps the service running. - image: gradido/database:test_up - build: - target: test_up - #networks: - # - external-net - # - internal-net - environment: - - NODE_ENV="development" - volumes: - # This makes sure the docker container has its own node modules. - # Therefore it is possible to have a different node version on the host machine - - database_node_modules:/app/node_modules - - database_build:/app/build - # bind the local folder to the docker to allow live reload - - ./database:/app - - ######################################################### - ## LOGIN SERVER ######################################### - ######################################################### - login-server: - build: - dockerfile: Dockerfiles/ubuntu/Dockerfile.debug - networks: - - external-net - - internal-net - security_opt: - - seccomp:unconfined - cap_add: - - SYS_PTRACE - volumes: - - ./logs:/var/log/grd_login - - ./login_server/src:/code/src - - ./login_server/dependencies:/code/dependencies - - ./login_server/scripts:/code/scripts - - ./configs/login_server:/etc/grd_login - - login_build_ubuntu_3.1:/code/build - - - ######################################################### - ## COMMUNITY SERVER (cakephp with php-fpm) ############## - ######################################################### - community-server: - build: - context: . - target: community_server - dockerfile: ./community_server/Dockerfile - depends_on: - - mariadb - networks: - - internal-net - - external-net - volumes: - - ./community_server/config/php-fpm/php-ini-overrides.ini:/etc/php/7.4/fpm/conf.d/99-overrides.ini - - ./community_server/src:/var/www/cakephp/src - - ######################################################### - ## MARIADB ############################################## - ######################################################### - mariadb: - networks: - - internal-net - - external-net - - ######################################################### - ## NGINX ################################################ - ######################################################### - nginx: - depends_on: - - frontend - - community-server - - login-server - volumes: - - ./logs/nginx:/var/log/nginx - - ######################################################### - ## PHPMYADMIN ########################################### - ######################################################### - phpmyadmin: - image: phpmyadmin - environment: - - PMA_ARBITRARY=1 - #restart: always - ports: - - 8074:80 - networks: - - internal-net - - external-net - volumes: - - /sessions - -volumes: - frontend_node_modules: - admin_node_modules: - backend_node_modules: - backend_database_node_modules: - backend_database_build: - database_node_modules: - database_build: +version: "3.4" + +services: + ######################################################## + # FRONTEND ############################################# + ######################################################## + frontend: + image: gradido/frontend:development + build: + target: development + environment: + - NODE_ENV="development" + # - DEBUG=true + volumes: + # This makes sure the docker container has its own node modules. + # Therefore it is possible to have a different node version on the host machine + - frontend_node_modules:/app/node_modules + # bind the local folder to the docker to allow live reload + - ./frontend:/app + + ######################################################## + # ADMIN INTERFACE ###################################### + ######################################################## + admin: + image: gradido/admin:development + build: + target: development + environment: + - NODE_ENV="development" + # - DEBUG=true + volumes: + # This makes sure the docker container has its own node modules. + # Therefore it is possible to have a different node version on the host machine + - admin_node_modules:/app/node_modules + # bind the local folder to the docker to allow live reload + - ./admin:/app + + ######################################################## + # BACKEND ############################################## + ######################################################## + backend: + image: gradido/backend:development + build: + target: development + networks: + - external-net + - internal-net + environment: + - NODE_ENV="development" + volumes: + # This makes sure the docker container has its own node modules. + # Therefore it is possible to have a different node version on the host machine + - backend_node_modules:/app/node_modules + - backend_database_node_modules:/database/node_modules + - backend_database_build:/database/build + # bind the local folder to the docker to allow live reload + - ./backend:/app + - ./database:/database + + ######################################################## + # DATABASE ############################################## + ######################################################## + database: + # we always run on production here since else the service lingers + # feel free to change this behaviour if it seems useful + # Due to problems with the volume caching the built files + # we changed this to test build. This keeps the service running. + image: gradido/database:test_up + build: + target: test_up + #networks: + # - external-net + # - internal-net + environment: + - NODE_ENV="development" + volumes: + # This makes sure the docker container has its own node modules. + # Therefore it is possible to have a different node version on the host machine + - database_node_modules:/app/node_modules + - database_build:/app/build + # bind the local folder to the docker to allow live reload + - ./database:/app + + ######################################################### + ## LOGIN SERVER ######################################### + ######################################################### + login-server: + build: + dockerfile: Dockerfiles/ubuntu/Dockerfile.debug + networks: + - external-net + - internal-net + security_opt: + - seccomp:unconfined + cap_add: + - SYS_PTRACE + volumes: + - ./logs:/var/log/grd_login + - ./login_server/src:/code/src + - ./login_server/dependencies:/code/dependencies + - ./login_server/scripts:/code/scripts + - ./configs/login_server:/etc/grd_login + - login_build_ubuntu_3.1:/code/build + + + ######################################################### + ## COMMUNITY SERVER (cakephp with php-fpm) ############## + ######################################################### + community-server: + build: + context: . + target: community_server + dockerfile: ./community_server/Dockerfile + depends_on: + - mariadb + networks: + - internal-net + - external-net + volumes: + - ./community_server/config/php-fpm/php-ini-overrides.ini:/etc/php/7.4/fpm/conf.d/99-overrides.ini + - ./community_server/src:/var/www/cakephp/src + + ######################################################### + ## MARIADB ############################################## + ######################################################### + mariadb: + networks: + - internal-net + - external-net + + ######################################################### + ## NGINX ################################################ + ######################################################### + nginx: + depends_on: + - frontend + - community-server + - login-server + volumes: + - ./logs/nginx:/var/log/nginx + + ######################################################### + ## PHPMYADMIN ########################################### + ######################################################### + phpmyadmin: + image: phpmyadmin + environment: + - PMA_ARBITRARY=1 + #restart: always + ports: + - 8074:80 + networks: + - internal-net + - external-net + volumes: + - /sessions + +volumes: + frontend_node_modules: + admin_node_modules: + backend_node_modules: + backend_database_node_modules: + backend_database_build: + database_node_modules: + database_build: login_build_ubuntu_3.1: \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index b212c6f21..9352fd162 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -15,6 +15,7 @@ services: context: ./frontend target: production networks: + - external-net - internal-net ports: - 3000:3000 @@ -39,6 +40,7 @@ services: context: ./admin target: production networks: + - external-net - internal-net ports: - 8080:8080 diff --git a/frontend/src/locales/de.json b/frontend/src/locales/de.json index 0dd3ba926..faa61886d 100644 --- a/frontend/src/locales/de.json +++ b/frontend/src/locales/de.json @@ -46,6 +46,7 @@ "change-password": "Fehler beim Ändern des Passworts", "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!" }, "form": { @@ -180,9 +181,12 @@ "uppercase": "Ein Großbuchstabe erforderlich." }, "thx": { + "activateEmail": "Deine Email wurde noch nicht aktiviert, bitte überprüfe deine Email und Klicke den Aktivierungslink!", "checkEmail": "Deine Email würde erfolgreich verifiziert.", "email": "Wir haben dir eine eMail gesendet.", - "register": "Du bist jetzt registriert.", + "emailActivated": "Danke dass Du deine Email bestätigt hast.", + "errorTitle": "Achtung!", + "register": "Du bist jetzt registriert, bitte überprüfe deine Emails und klicke auf den Aktivierungslink.", "reset": "Dein Passwort wurde geändert.", "title": "Danke!" } diff --git a/frontend/src/locales/en.json b/frontend/src/locales/en.json index 99fcd46a7..91e25f61d 100644 --- a/frontend/src/locales/en.json +++ b/frontend/src/locales/en.json @@ -46,6 +46,7 @@ "change-password": "Error while changing password", "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" }, "form": { @@ -180,9 +181,12 @@ "uppercase": "One uppercase letter required." }, "thx": { + "activateEmail": "Your email has not been activated yet, please check your emails and click the activation link!", "checkEmail": "Your email has been successfully verified.", "email": "We have sent you an email.", - "register": "You are registred now.", + "emailActivated": "Thank you your email has been activated.", + "errorTitle": "Attention!", + "register": "You are registered now, please check your emails and click the activation link.", "reset": "Your password has been changed.", "title": "Thank you!" } diff --git a/frontend/src/routes/routes.js b/frontend/src/routes/routes.js index f4f0dfe04..a3c1389ce 100755 --- a/frontend/src/routes/routes.js +++ b/frontend/src/routes/routes.js @@ -47,7 +47,7 @@ const routes = [ path: '/thx/:comingFrom', component: () => import('../views/Pages/thx.vue'), beforeEnter: (to, from, next) => { - const validFrom = ['password', 'reset', 'register'] + const validFrom = ['password', 'reset', 'register', 'login'] if (!validFrom.includes(from.path.split('/')[1])) { next({ path: '/login' }) } else { diff --git a/frontend/src/views/Pages/Login.vue b/frontend/src/views/Pages/Login.vue index de1ae993a..45e700099 100755 --- a/frontend/src/views/Pages/Login.vue +++ b/frontend/src/views/Pages/Login.vue @@ -104,9 +104,14 @@ export default { this.$router.push('/overview') loader.hide() }) - .catch(() => { + .catch((error) => { + if (!error.message.includes('user email not validated')) { + this.$toasted.error(this.$t('error.no-account')) + } else { + // : this.$t('error.no-email-verify') + this.$router.push('/thx/login') + } loader.hide() - this.$toasted.error(this.$t('error.no-account')) }) }, }, diff --git a/frontend/src/views/Pages/Register.vue b/frontend/src/views/Pages/Register.vue index 00114eb04..ea4000cff 100755 --- a/frontend/src/views/Pages/Register.vue +++ b/frontend/src/views/Pages/Register.vue @@ -161,6 +161,7 @@ import InputEmail from '../../components/Inputs/InputEmail.vue' import InputPasswordConfirmation from '../../components/Inputs/InputPasswordConfirmation.vue' import LanguageSwitchSelect from '../../components/LanguageSwitchSelect.vue' import { registerUser } from '../../graphql/mutations' +import { localeChanged } from 'vee-validate' import { getCommunityInfoMixin } from '../../mixins/getCommunityInfo' export default { @@ -189,6 +190,9 @@ export default { methods: { updateLanguage(e) { this.language = e + this.$store.commit('language', this.language) + this.$i18n.locale = this.language + localeChanged(this.language) }, getValidationState({ dirty, validated, valid = null }) { return dirty || validated ? valid : null diff --git a/frontend/src/views/Pages/thx.vue b/frontend/src/views/Pages/thx.vue index 9d9143456..5884cc61c 100644 --- a/frontend/src/views/Pages/thx.vue +++ b/frontend/src/views/Pages/thx.vue @@ -4,10 +4,12 @@
-

{{ $t('site.thx.title') }}

+

{{ $t(displaySetup.headline) }}

{{ $t(displaySetup.subtitle) }}


- {{ $t(displaySetup.button) }} + + {{ $t(displaySetup.button) }} +
@@ -17,25 +19,33 @@