mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
Merge branch 'master' into ADMINBEREICH-first-step
This commit is contained in:
commit
d2bfb213a2
@ -35,6 +35,7 @@
|
|||||||
"identity-obj-proxy": "^3.0.0",
|
"identity-obj-proxy": "^3.0.0",
|
||||||
"jest": "26.6.3",
|
"jest": "26.6.3",
|
||||||
"moment": "^2.29.1",
|
"moment": "^2.29.1",
|
||||||
|
"regenerator-runtime": "^0.13.9",
|
||||||
"stats-webpack-plugin": "^0.7.0",
|
"stats-webpack-plugin": "^0.7.0",
|
||||||
"vue": "^2.6.11",
|
"vue": "^2.6.11",
|
||||||
"vue-apollo": "^3.0.8",
|
"vue-apollo": "^3.0.8",
|
||||||
|
|||||||
68
admin/src/App.spec.js
Normal file
68
admin/src/App.spec.js
Normal file
@ -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)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@ -1,19 +1,9 @@
|
|||||||
<template>
|
<template>
|
||||||
<div id="app">
|
<div id="app"></div>
|
||||||
<nav-bar class="wrapper-nav" />
|
|
||||||
<router-view class="wrapper p-3"></router-view>
|
|
||||||
<foo-ter />
|
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import NavBar from '@/components/NavBar.vue'
|
|
||||||
import FooTer from '@/components/Footer.vue'
|
|
||||||
export default {
|
export default {
|
||||||
name: 'App',
|
name: 'App',
|
||||||
components: {
|
|
||||||
NavBar,
|
|
||||||
FooTer,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import App from './App.vue'
|
import App from './App.vue'
|
||||||
|
|
||||||
|
// without this async calls are not working
|
||||||
|
import 'regenerator-runtime'
|
||||||
|
|
||||||
import store from './store/store'
|
import store from './store/store'
|
||||||
|
|
||||||
import router from './router/router'
|
import router from './router/router'
|
||||||
@ -22,7 +25,9 @@ import moment from 'vue-moment'
|
|||||||
const httpLink = new HttpLink({ uri: CONFIG.GRAPHQL_URI })
|
const httpLink = new HttpLink({ uri: CONFIG.GRAPHQL_URI })
|
||||||
|
|
||||||
const authLink = new ApolloLink((operation, forward) => {
|
const authLink = new ApolloLink((operation, forward) => {
|
||||||
const token = '' // store.state.token
|
|
||||||
|
const token = store.state.token
|
||||||
|
|
||||||
operation.setContext({
|
operation.setContext({
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: token && token.length > 0 ? `Bearer ${token}` : '',
|
Authorization: token && token.length > 0 ? `Bearer ${token}` : '',
|
||||||
@ -52,6 +57,7 @@ const apolloProvider = new VueApollo({
|
|||||||
})
|
})
|
||||||
|
|
||||||
Vue.use(BootstrapVue)
|
Vue.use(BootstrapVue)
|
||||||
|
|
||||||
Vue.use(IconsPlugin)
|
Vue.use(IconsPlugin)
|
||||||
|
|
||||||
Vue.use(moment)
|
Vue.use(moment)
|
||||||
|
|||||||
@ -14,6 +14,9 @@ export const mutations = {
|
|||||||
resetOpenCreations: (state) => {
|
resetOpenCreations: (state) => {
|
||||||
state.openCreations = 0
|
state.openCreations = 0
|
||||||
},
|
},
|
||||||
|
token: (state, token) => {
|
||||||
|
state.token = token
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
const store = new Vuex.Store({
|
const store = new Vuex.Store({
|
||||||
|
|||||||
15
admin/src/store/store.test.js
Normal file
15
admin/src/store/store.test.js
Normal file
@ -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')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@ -2,6 +2,9 @@ import { createLocalVue } from '@vue/test-utils'
|
|||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import { BootstrapVue } from 'bootstrap-vue'
|
import { BootstrapVue } from 'bootstrap-vue'
|
||||||
|
|
||||||
|
// without this async calls are not working
|
||||||
|
import 'regenerator-runtime'
|
||||||
|
|
||||||
global.localVue = createLocalVue()
|
global.localVue = createLocalVue()
|
||||||
|
|
||||||
global.localVue.use(BootstrapVue)
|
global.localVue.use(BootstrapVue)
|
||||||
|
|||||||
@ -10623,7 +10623,7 @@ regenerator-runtime@^0.11.0:
|
|||||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
|
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
|
||||||
integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
|
integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
|
||||||
|
|
||||||
regenerator-runtime@^0.13.4:
|
regenerator-runtime@^0.13.4, regenerator-runtime@^0.13.9:
|
||||||
version "0.13.9"
|
version "0.13.9"
|
||||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52"
|
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52"
|
||||||
integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==
|
integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==
|
||||||
|
|||||||
@ -51,7 +51,6 @@ const email = {
|
|||||||
EMAIL_PASSWORD: process.env.EMAIL_PASSWORD || 'xxx',
|
EMAIL_PASSWORD: process.env.EMAIL_PASSWORD || 'xxx',
|
||||||
EMAIL_SMTP_URL: process.env.EMAIL_SMTP_URL || 'gmail.com',
|
EMAIL_SMTP_URL: process.env.EMAIL_SMTP_URL || 'gmail.com',
|
||||||
EMAIL_SMTP_PORT: process.env.EMAIL_SMTP_PORT || '587',
|
EMAIL_SMTP_PORT: process.env.EMAIL_SMTP_PORT || '587',
|
||||||
|
|
||||||
EMAIL_LINK_VERIFICATION:
|
EMAIL_LINK_VERIFICATION:
|
||||||
process.env.EMAIL_LINK_VERIFICATION || 'http://localhost/vue/checkEmail/$1',
|
process.env.EMAIL_LINK_VERIFICATION || 'http://localhost/vue/checkEmail/$1',
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,9 +2,6 @@
|
|||||||
|
|
||||||
import { AuthChecker } from 'type-graphql'
|
import { AuthChecker } from 'type-graphql'
|
||||||
|
|
||||||
import CONFIG from '../../config'
|
|
||||||
import { apiGet } from '../../apis/HttpRequest'
|
|
||||||
|
|
||||||
import decode from '../../jwt/decode'
|
import decode from '../../jwt/decode'
|
||||||
import encode from '../../jwt/encode'
|
import encode from '../../jwt/encode'
|
||||||
|
|
||||||
@ -13,7 +10,7 @@ const isAuthorized: AuthChecker<any> = async (
|
|||||||
) => {
|
) => {
|
||||||
if (context.token) {
|
if (context.token) {
|
||||||
const decoded = decode(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) })
|
context.setHeaders.push({ key: 'token', value: encode(decoded.pubKey) })
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,15 +10,17 @@ export class User {
|
|||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
id: number
|
id: number
|
||||||
*/
|
*/
|
||||||
constructor(json: any) {
|
constructor(json?: any) {
|
||||||
this.email = json.email
|
if (json) {
|
||||||
this.firstName = json.first_name
|
this.email = json.email
|
||||||
this.lastName = json.last_name
|
this.firstName = json.first_name
|
||||||
this.username = json.username
|
this.lastName = json.last_name
|
||||||
this.description = json.description
|
this.username = json.username
|
||||||
this.pubkey = json.public_hex
|
this.description = json.description
|
||||||
this.language = json.language
|
this.pubkey = json.public_hex
|
||||||
this.publisherId = json.publisher_id
|
this.language = json.language
|
||||||
|
this.publisherId = json.publisher_id
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Field(() => String)
|
@Field(() => String)
|
||||||
|
|||||||
@ -613,9 +613,6 @@ export class TransactionResolver {
|
|||||||
await queryRunner.commitTransaction()
|
await queryRunner.commitTransaction()
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
await queryRunner.rollbackTransaction()
|
await queryRunner.rollbackTransaction()
|
||||||
throw e
|
|
||||||
} finally {
|
|
||||||
await queryRunner.release()
|
|
||||||
// TODO: This is broken code - we should never correct an autoincrement index in production
|
// 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
|
// 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
|
// index for the transaction which requires a chain without gaps
|
||||||
@ -627,6 +624,9 @@ export class TransactionResolver {
|
|||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log('problems with reset auto increment: %o', error)
|
console.log('problems with reset auto increment: %o', error)
|
||||||
})
|
})
|
||||||
|
throw e
|
||||||
|
} finally {
|
||||||
|
await queryRunner.release()
|
||||||
}
|
}
|
||||||
// send notification email
|
// send notification email
|
||||||
// TODO: translate
|
// TODO: translate
|
||||||
|
|||||||
@ -22,14 +22,14 @@ import {
|
|||||||
} from '../../middleware/klicktippMiddleware'
|
} from '../../middleware/klicktippMiddleware'
|
||||||
import { CheckEmailResponse } from '../model/CheckEmailResponse'
|
import { CheckEmailResponse } from '../model/CheckEmailResponse'
|
||||||
import { UserSettingRepository } from '../../typeorm/repository/UserSettingRepository'
|
import { UserSettingRepository } from '../../typeorm/repository/UserSettingRepository'
|
||||||
|
import { LoginUserRepository } from '../../typeorm/repository/LoginUser'
|
||||||
import { Setting } from '../enum/Setting'
|
import { Setting } from '../enum/Setting'
|
||||||
import { UserRepository } from '../../typeorm/repository/User'
|
import { UserRepository } from '../../typeorm/repository/User'
|
||||||
import { LoginUser } from '@entity/LoginUser'
|
import { LoginUser } from '@entity/LoginUser'
|
||||||
import { LoginElopageBuys } from '@entity/LoginElopageBuys'
|
|
||||||
import { LoginUserBackup } from '@entity/LoginUserBackup'
|
import { LoginUserBackup } from '@entity/LoginUserBackup'
|
||||||
import { LoginEmailOptIn } from '@entity/LoginEmailOptIn'
|
import { LoginEmailOptIn } from '@entity/LoginEmailOptIn'
|
||||||
import { sendEMail } from '../../util/sendEMail'
|
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
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
const sodium = require('sodium-native')
|
const sodium = require('sodium-native')
|
||||||
@ -201,33 +201,32 @@ export class UserResolver {
|
|||||||
@Ctx() context: any,
|
@Ctx() context: any,
|
||||||
): Promise<User> {
|
): Promise<User> {
|
||||||
email = email.trim().toLowerCase()
|
email = email.trim().toLowerCase()
|
||||||
const result = await apiPost(CONFIG.LOGIN_API_URL + 'unsecureLogin', { email, password })
|
// const result = await apiPost(CONFIG.LOGIN_API_URL + 'unsecureLogin', { email, password })
|
||||||
|
// UnsecureLogin
|
||||||
// if there is no user, throw an authentication error
|
const loginUserRepository = getCustomRepository(LoginUserRepository)
|
||||||
if (!result.success) {
|
const loginUser = await loginUserRepository.findByEmail(email).catch(() => {
|
||||||
throw new Error(result.data)
|
throw new Error('No user with this credentials')
|
||||||
}
|
|
||||||
|
|
||||||
context.setHeaders.push({
|
|
||||||
key: 'token',
|
|
||||||
value: encode(result.data.user.public_hex),
|
|
||||||
})
|
})
|
||||||
const user = new User(result.data.user)
|
const passwordHash = SecretKeyCryptographyCreateKey(email, password) // return short and long hash
|
||||||
// Hack: Database Field is not validated properly and not nullable
|
const loginUserPassword = BigInt(loginUser.password.toString())
|
||||||
if (user.publisherId === 0) {
|
if (loginUserPassword !== passwordHash[0].readBigUInt64LE()) {
|
||||||
user.publisherId = undefined
|
throw new Error('No user with this credentials')
|
||||||
}
|
}
|
||||||
user.hasElopage = result.data.hasElopage
|
// TODO: If user has no pubKey Create it again and update user.
|
||||||
// read additional settings from settings table
|
|
||||||
const userRepository = getCustomRepository(UserRepository)
|
const userRepository = getCustomRepository(UserRepository)
|
||||||
let userEntity: void | DbUser
|
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 = new DbUser()
|
||||||
userEntity.firstName = user.firstName
|
userEntity.firstName = loginUser.firstName
|
||||||
userEntity.lastName = user.lastName
|
userEntity.lastName = loginUser.lastName
|
||||||
userEntity.username = user.username
|
userEntity.username = loginUser.username
|
||||||
userEntity.email = user.email
|
userEntity.email = loginUser.email
|
||||||
userEntity.pubkey = Buffer.from(user.pubkey, 'hex')
|
userEntity.pubkey = loginUser.pubKey
|
||||||
|
|
||||||
userRepository.save(userEntity).catch(() => {
|
userRepository.save(userEntity).catch(() => {
|
||||||
throw new Error('error by save userEntity')
|
throw new Error('error by save userEntity')
|
||||||
@ -237,16 +236,28 @@ export class UserResolver {
|
|||||||
throw new Error('error with cannot happen')
|
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) {
|
if (!user.hasElopage && publisherId) {
|
||||||
user.publisherId = publisherId
|
user.publisherId = publisherId
|
||||||
|
// TODO: Check if we can use updateUserInfos
|
||||||
|
// await this.updateUserInfos({ publisherId }, { pubKey: loginUser.pubKey })
|
||||||
const loginUserRepository = getCustomRepository(LoginUserRepository)
|
const loginUserRepository = getCustomRepository(LoginUserRepository)
|
||||||
const loginUser = await loginUserRepository.findOneOrFail({ email: userEntity.email })
|
const loginUser = await loginUserRepository.findOneOrFail({ email: userEntity.email })
|
||||||
loginUser.publisherId = publisherId
|
loginUser.publisherId = publisherId
|
||||||
loginUserRepository.save(loginUser)
|
loginUserRepository.save(loginUser)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// coinAnimation
|
||||||
const userSettingRepository = getCustomRepository(UserSettingRepository)
|
const userSettingRepository = getCustomRepository(UserSettingRepository)
|
||||||
const coinanimation = await userSettingRepository
|
const coinanimation = await userSettingRepository
|
||||||
.readBoolean(userEntity.id, Setting.COIN_ANIMATION)
|
.readBoolean(userEntity.id, Setting.COIN_ANIMATION)
|
||||||
@ -254,6 +265,12 @@ export class UserResolver {
|
|||||||
throw new Error(error)
|
throw new Error(error)
|
||||||
})
|
})
|
||||||
user.coinanimation = coinanimation
|
user.coinanimation = coinanimation
|
||||||
|
|
||||||
|
context.setHeaders.push({
|
||||||
|
key: 'token',
|
||||||
|
value: encode(loginUser.pubKey),
|
||||||
|
})
|
||||||
|
|
||||||
return user
|
return user
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -537,7 +554,7 @@ export class UserResolver {
|
|||||||
await queryRunner.startTransaction('READ UNCOMMITTED')
|
await queryRunner.startTransaction('READ UNCOMMITTED')
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (coinanimation) {
|
if (coinanimation !== null && coinanimation !== undefined) {
|
||||||
queryRunner.manager
|
queryRunner.manager
|
||||||
.getCustomRepository(UserSettingRepository)
|
.getCustomRepository(UserSettingRepository)
|
||||||
.setOrUpdate(userEntity.id, Setting.COIN_ANIMATION, coinanimation.toString())
|
.setOrUpdate(userEntity.id, Setting.COIN_ANIMATION, coinanimation.toString())
|
||||||
@ -609,7 +626,8 @@ export class UserResolver {
|
|||||||
return false
|
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
|
return elopageBuyCount > 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
5
backend/src/typeorm/repository/LoginElopageBuys.ts
Normal file
5
backend/src/typeorm/repository/LoginElopageBuys.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { EntityRepository, Repository } from 'typeorm'
|
||||||
|
import { LoginElopageBuys } from '@entity/LoginElopageBuys'
|
||||||
|
|
||||||
|
@EntityRepository(LoginElopageBuys)
|
||||||
|
export class LoginElopageBuysRepository extends Repository<LoginElopageBuys> {}
|
||||||
@ -2,4 +2,10 @@ import { EntityRepository, Repository } from 'typeorm'
|
|||||||
import { LoginUser } from '@entity/LoginUser'
|
import { LoginUser } from '@entity/LoginUser'
|
||||||
|
|
||||||
@EntityRepository(LoginUser)
|
@EntityRepository(LoginUser)
|
||||||
export class LoginUserRepository extends Repository<LoginUser> {}
|
export class LoginUserRepository extends Repository<LoginUser> {
|
||||||
|
async findByEmail(email: string): Promise<LoginUser> {
|
||||||
|
return this.createQueryBuilder('loginUser')
|
||||||
|
.where('loginUser.email = :email', { email })
|
||||||
|
.getOneOrFail()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -9,6 +9,15 @@ export class UserRepository extends Repository<User> {
|
|||||||
.getOneOrFail()
|
.getOneOrFail()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async findByPubkeyHexBuffer(pubkeyHexBuffer: Buffer): Promise<User> {
|
||||||
|
const pubKeyString = pubkeyHexBuffer.toString('hex')
|
||||||
|
return await this.findByPubkeyHex(pubKeyString)
|
||||||
|
}
|
||||||
|
|
||||||
|
async findByEmail(email: string): Promise<User> {
|
||||||
|
return this.createQueryBuilder('user').where('user.email = :email', { email }).getOneOrFail()
|
||||||
|
}
|
||||||
|
|
||||||
async getUsersIndiced(userIds: number[]): Promise<User[]> {
|
async getUsersIndiced(userIds: number[]): Promise<User[]> {
|
||||||
if (!userIds.length) return []
|
if (!userIds.length) return []
|
||||||
const users = await this.createQueryBuilder('user')
|
const users = await this.createQueryBuilder('user')
|
||||||
|
|||||||
@ -1,170 +1,166 @@
|
|||||||
version: "3.4"
|
version: "3.4"
|
||||||
|
|
||||||
services:
|
services:
|
||||||
########################################################
|
########################################################
|
||||||
# FRONTEND #############################################
|
# FRONTEND #############################################
|
||||||
########################################################
|
########################################################
|
||||||
frontend:
|
frontend:
|
||||||
image: gradido/frontend:development
|
image: gradido/frontend:development
|
||||||
build:
|
build:
|
||||||
target: development
|
target: development
|
||||||
networks:
|
environment:
|
||||||
- external-net
|
- NODE_ENV="development"
|
||||||
environment:
|
# - DEBUG=true
|
||||||
- NODE_ENV="development"
|
volumes:
|
||||||
# - DEBUG=true
|
# This makes sure the docker container has its own node modules.
|
||||||
volumes:
|
# Therefore it is possible to have a different node version on the host machine
|
||||||
# This makes sure the docker container has its own node modules.
|
- frontend_node_modules:/app/node_modules
|
||||||
# Therefore it is possible to have a different node version on the host machine
|
# bind the local folder to the docker to allow live reload
|
||||||
- frontend_node_modules:/app/node_modules
|
- ./frontend:/app
|
||||||
# bind the local folder to the docker to allow live reload
|
|
||||||
- ./frontend:/app
|
########################################################
|
||||||
|
# ADMIN INTERFACE ######################################
|
||||||
########################################################
|
########################################################
|
||||||
# ADMIN INTERFACE ######################################
|
admin:
|
||||||
########################################################
|
image: gradido/admin:development
|
||||||
admin:
|
build:
|
||||||
image: gradido/admin:development
|
target: development
|
||||||
build:
|
environment:
|
||||||
target: development
|
- NODE_ENV="development"
|
||||||
networks:
|
# - DEBUG=true
|
||||||
- external-net
|
volumes:
|
||||||
environment:
|
# This makes sure the docker container has its own node modules.
|
||||||
- NODE_ENV="development"
|
# Therefore it is possible to have a different node version on the host machine
|
||||||
# - DEBUG=true
|
- admin_node_modules:/app/node_modules
|
||||||
volumes:
|
# bind the local folder to the docker to allow live reload
|
||||||
# This makes sure the docker container has its own node modules.
|
- ./admin:/app
|
||||||
# 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
|
# BACKEND ##############################################
|
||||||
- ./admin:/app
|
########################################################
|
||||||
|
backend:
|
||||||
########################################################
|
image: gradido/backend:development
|
||||||
# BACKEND ##############################################
|
build:
|
||||||
########################################################
|
target: development
|
||||||
backend:
|
networks:
|
||||||
image: gradido/backend:development
|
- external-net
|
||||||
build:
|
- internal-net
|
||||||
target: development
|
environment:
|
||||||
networks:
|
- NODE_ENV="development"
|
||||||
- external-net
|
volumes:
|
||||||
- internal-net
|
# This makes sure the docker container has its own node modules.
|
||||||
environment:
|
# Therefore it is possible to have a different node version on the host machine
|
||||||
- NODE_ENV="development"
|
- backend_node_modules:/app/node_modules
|
||||||
volumes:
|
- backend_database_node_modules:/database/node_modules
|
||||||
# This makes sure the docker container has its own node modules.
|
- backend_database_build:/database/build
|
||||||
# Therefore it is possible to have a different node version on the host machine
|
# bind the local folder to the docker to allow live reload
|
||||||
- backend_node_modules:/app/node_modules
|
- ./backend:/app
|
||||||
- backend_database_node_modules:/database/node_modules
|
- ./database:/database
|
||||||
- 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
|
||||||
# DATABASE ##############################################
|
# feel free to change this behaviour if it seems useful
|
||||||
########################################################
|
# Due to problems with the volume caching the built files
|
||||||
database:
|
# we changed this to test build. This keeps the service running.
|
||||||
# we always run on production here since else the service lingers
|
image: gradido/database:test_up
|
||||||
# feel free to change this behaviour if it seems useful
|
build:
|
||||||
# Due to problems with the volume caching the built files
|
target: test_up
|
||||||
# we changed this to test build. This keeps the service running.
|
#networks:
|
||||||
image: gradido/database:test_up
|
# - external-net
|
||||||
build:
|
# - internal-net
|
||||||
target: test_up
|
environment:
|
||||||
#networks:
|
- NODE_ENV="development"
|
||||||
# - external-net
|
volumes:
|
||||||
# - internal-net
|
# This makes sure the docker container has its own node modules.
|
||||||
environment:
|
# Therefore it is possible to have a different node version on the host machine
|
||||||
- NODE_ENV="development"
|
- database_node_modules:/app/node_modules
|
||||||
volumes:
|
- database_build:/app/build
|
||||||
# This makes sure the docker container has its own node modules.
|
# bind the local folder to the docker to allow live reload
|
||||||
# Therefore it is possible to have a different node version on the host machine
|
- ./database:/app
|
||||||
- database_node_modules:/app/node_modules
|
|
||||||
- database_build:/app/build
|
#########################################################
|
||||||
# bind the local folder to the docker to allow live reload
|
## LOGIN SERVER #########################################
|
||||||
- ./database:/app
|
#########################################################
|
||||||
|
login-server:
|
||||||
#########################################################
|
build:
|
||||||
## LOGIN SERVER #########################################
|
dockerfile: Dockerfiles/ubuntu/Dockerfile.debug
|
||||||
#########################################################
|
networks:
|
||||||
login-server:
|
- external-net
|
||||||
build:
|
- internal-net
|
||||||
dockerfile: Dockerfiles/ubuntu/Dockerfile.debug
|
security_opt:
|
||||||
networks:
|
- seccomp:unconfined
|
||||||
- external-net
|
cap_add:
|
||||||
- internal-net
|
- SYS_PTRACE
|
||||||
security_opt:
|
volumes:
|
||||||
- seccomp:unconfined
|
- ./logs:/var/log/grd_login
|
||||||
cap_add:
|
- ./login_server/src:/code/src
|
||||||
- SYS_PTRACE
|
- ./login_server/dependencies:/code/dependencies
|
||||||
volumes:
|
- ./login_server/scripts:/code/scripts
|
||||||
- ./logs:/var/log/grd_login
|
- ./configs/login_server:/etc/grd_login
|
||||||
- ./login_server/src:/code/src
|
- login_build_ubuntu_3.1:/code/build
|
||||||
- ./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:
|
||||||
## COMMUNITY SERVER (cakephp with php-fpm) ##############
|
context: .
|
||||||
#########################################################
|
target: community_server
|
||||||
community-server:
|
dockerfile: ./community_server/Dockerfile
|
||||||
build:
|
depends_on:
|
||||||
context: .
|
- mariadb
|
||||||
target: community_server
|
networks:
|
||||||
dockerfile: ./community_server/Dockerfile
|
- internal-net
|
||||||
depends_on:
|
- external-net
|
||||||
- mariadb
|
volumes:
|
||||||
networks:
|
- ./community_server/config/php-fpm/php-ini-overrides.ini:/etc/php/7.4/fpm/conf.d/99-overrides.ini
|
||||||
- internal-net
|
- ./community_server/src:/var/www/cakephp/src
|
||||||
- external-net
|
|
||||||
volumes:
|
#########################################################
|
||||||
- ./community_server/config/php-fpm/php-ini-overrides.ini:/etc/php/7.4/fpm/conf.d/99-overrides.ini
|
## MARIADB ##############################################
|
||||||
- ./community_server/src:/var/www/cakephp/src
|
#########################################################
|
||||||
|
mariadb:
|
||||||
#########################################################
|
networks:
|
||||||
## MARIADB ##############################################
|
- internal-net
|
||||||
#########################################################
|
- external-net
|
||||||
mariadb:
|
|
||||||
networks:
|
#########################################################
|
||||||
- internal-net
|
## NGINX ################################################
|
||||||
- external-net
|
#########################################################
|
||||||
|
nginx:
|
||||||
#########################################################
|
depends_on:
|
||||||
## NGINX ################################################
|
- frontend
|
||||||
#########################################################
|
- community-server
|
||||||
nginx:
|
- login-server
|
||||||
depends_on:
|
volumes:
|
||||||
- frontend
|
- ./logs/nginx:/var/log/nginx
|
||||||
- community-server
|
|
||||||
- login-server
|
#########################################################
|
||||||
volumes:
|
## PHPMYADMIN ###########################################
|
||||||
- ./logs/nginx:/var/log/nginx
|
#########################################################
|
||||||
|
phpmyadmin:
|
||||||
#########################################################
|
image: phpmyadmin
|
||||||
## PHPMYADMIN ###########################################
|
environment:
|
||||||
#########################################################
|
- PMA_ARBITRARY=1
|
||||||
phpmyadmin:
|
#restart: always
|
||||||
image: phpmyadmin
|
ports:
|
||||||
environment:
|
- 8074:80
|
||||||
- PMA_ARBITRARY=1
|
networks:
|
||||||
#restart: always
|
- internal-net
|
||||||
ports:
|
- external-net
|
||||||
- 8074:80
|
volumes:
|
||||||
networks:
|
- /sessions
|
||||||
- internal-net
|
|
||||||
- external-net
|
volumes:
|
||||||
volumes:
|
frontend_node_modules:
|
||||||
- /sessions
|
admin_node_modules:
|
||||||
|
backend_node_modules:
|
||||||
volumes:
|
backend_database_node_modules:
|
||||||
frontend_node_modules:
|
backend_database_build:
|
||||||
admin_node_modules:
|
database_node_modules:
|
||||||
backend_node_modules:
|
database_build:
|
||||||
backend_database_node_modules:
|
|
||||||
backend_database_build:
|
|
||||||
database_node_modules:
|
|
||||||
database_build:
|
|
||||||
login_build_ubuntu_3.1:
|
login_build_ubuntu_3.1:
|
||||||
@ -15,6 +15,7 @@ services:
|
|||||||
context: ./frontend
|
context: ./frontend
|
||||||
target: production
|
target: production
|
||||||
networks:
|
networks:
|
||||||
|
- external-net
|
||||||
- internal-net
|
- internal-net
|
||||||
ports:
|
ports:
|
||||||
- 3000:3000
|
- 3000:3000
|
||||||
@ -39,6 +40,7 @@ services:
|
|||||||
context: ./admin
|
context: ./admin
|
||||||
target: production
|
target: production
|
||||||
networks:
|
networks:
|
||||||
|
- external-net
|
||||||
- internal-net
|
- internal-net
|
||||||
ports:
|
ports:
|
||||||
- 8080:8080
|
- 8080:8080
|
||||||
|
|||||||
@ -46,6 +46,7 @@
|
|||||||
"change-password": "Fehler beim Ändern des Passworts",
|
"change-password": "Fehler beim Ändern des Passworts",
|
||||||
"error": "Fehler",
|
"error": "Fehler",
|
||||||
"no-account": "Leider konnten wir keinen Account finden mit diesen Daten!",
|
"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": "Sitzung abgelaufen!"
|
||||||
},
|
},
|
||||||
"form": {
|
"form": {
|
||||||
@ -180,9 +181,12 @@
|
|||||||
"uppercase": "Ein Großbuchstabe erforderlich."
|
"uppercase": "Ein Großbuchstabe erforderlich."
|
||||||
},
|
},
|
||||||
"thx": {
|
"thx": {
|
||||||
|
"activateEmail": "Deine Email wurde noch nicht aktiviert, bitte überprüfe deine Email und Klicke den Aktivierungslink!",
|
||||||
"checkEmail": "Deine Email würde erfolgreich verifiziert.",
|
"checkEmail": "Deine Email würde erfolgreich verifiziert.",
|
||||||
"email": "Wir haben dir eine eMail gesendet.",
|
"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.",
|
"reset": "Dein Passwort wurde geändert.",
|
||||||
"title": "Danke!"
|
"title": "Danke!"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -46,6 +46,7 @@
|
|||||||
"change-password": "Error while changing password",
|
"change-password": "Error while changing password",
|
||||||
"error": "Error",
|
"error": "Error",
|
||||||
"no-account": "Unfortunately we could not find an account to the given data!",
|
"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 expired"
|
||||||
},
|
},
|
||||||
"form": {
|
"form": {
|
||||||
@ -180,9 +181,12 @@
|
|||||||
"uppercase": "One uppercase letter required."
|
"uppercase": "One uppercase letter required."
|
||||||
},
|
},
|
||||||
"thx": {
|
"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.",
|
"checkEmail": "Your email has been successfully verified.",
|
||||||
"email": "We have sent you an email.",
|
"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.",
|
"reset": "Your password has been changed.",
|
||||||
"title": "Thank you!"
|
"title": "Thank you!"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,7 +47,7 @@ const routes = [
|
|||||||
path: '/thx/:comingFrom',
|
path: '/thx/:comingFrom',
|
||||||
component: () => import('../views/Pages/thx.vue'),
|
component: () => import('../views/Pages/thx.vue'),
|
||||||
beforeEnter: (to, from, next) => {
|
beforeEnter: (to, from, next) => {
|
||||||
const validFrom = ['password', 'reset', 'register']
|
const validFrom = ['password', 'reset', 'register', 'login']
|
||||||
if (!validFrom.includes(from.path.split('/')[1])) {
|
if (!validFrom.includes(from.path.split('/')[1])) {
|
||||||
next({ path: '/login' })
|
next({ path: '/login' })
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -104,9 +104,14 @@ export default {
|
|||||||
this.$router.push('/overview')
|
this.$router.push('/overview')
|
||||||
loader.hide()
|
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()
|
loader.hide()
|
||||||
this.$toasted.error(this.$t('error.no-account'))
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@ -161,6 +161,7 @@ import InputEmail from '../../components/Inputs/InputEmail.vue'
|
|||||||
import InputPasswordConfirmation from '../../components/Inputs/InputPasswordConfirmation.vue'
|
import InputPasswordConfirmation from '../../components/Inputs/InputPasswordConfirmation.vue'
|
||||||
import LanguageSwitchSelect from '../../components/LanguageSwitchSelect.vue'
|
import LanguageSwitchSelect from '../../components/LanguageSwitchSelect.vue'
|
||||||
import { registerUser } from '../../graphql/mutations'
|
import { registerUser } from '../../graphql/mutations'
|
||||||
|
import { localeChanged } from 'vee-validate'
|
||||||
import { getCommunityInfoMixin } from '../../mixins/getCommunityInfo'
|
import { getCommunityInfoMixin } from '../../mixins/getCommunityInfo'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@ -189,6 +190,9 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
updateLanguage(e) {
|
updateLanguage(e) {
|
||||||
this.language = e
|
this.language = e
|
||||||
|
this.$store.commit('language', this.language)
|
||||||
|
this.$i18n.locale = this.language
|
||||||
|
localeChanged(this.language)
|
||||||
},
|
},
|
||||||
getValidationState({ dirty, validated, valid = null }) {
|
getValidationState({ dirty, validated, valid = null }) {
|
||||||
return dirty || validated ? valid : null
|
return dirty || validated ? valid : null
|
||||||
|
|||||||
@ -4,10 +4,12 @@
|
|||||||
<div class="header py-7 py-lg-8 pt-lg-9">
|
<div class="header py-7 py-lg-8 pt-lg-9">
|
||||||
<b-container>
|
<b-container>
|
||||||
<div class="header-body text-center mb-7">
|
<div class="header-body text-center mb-7">
|
||||||
<p class="h1">{{ $t('site.thx.title') }}</p>
|
<p class="h1">{{ $t(displaySetup.headline) }}</p>
|
||||||
<p class="h4">{{ $t(displaySetup.subtitle) }}</p>
|
<p class="h4">{{ $t(displaySetup.subtitle) }}</p>
|
||||||
<hr />
|
<hr />
|
||||||
<b-button :to="displaySetup.linkTo">{{ $t(displaySetup.button) }}</b-button>
|
<b-button v-if="displaySetup.linkTo" :to="displaySetup.linkTo">
|
||||||
|
{{ $t(displaySetup.button) }}
|
||||||
|
</b-button>
|
||||||
</div>
|
</div>
|
||||||
</b-container>
|
</b-container>
|
||||||
</div>
|
</div>
|
||||||
@ -17,25 +19,33 @@
|
|||||||
<script>
|
<script>
|
||||||
const textFields = {
|
const textFields = {
|
||||||
password: {
|
password: {
|
||||||
|
headline: 'site.thx.title',
|
||||||
subtitle: 'site.thx.email',
|
subtitle: 'site.thx.email',
|
||||||
button: 'login',
|
button: 'login',
|
||||||
linkTo: '/login',
|
linkTo: '/login',
|
||||||
},
|
},
|
||||||
reset: {
|
reset: {
|
||||||
|
headline: 'site.thx.title',
|
||||||
subtitle: 'site.thx.reset',
|
subtitle: 'site.thx.reset',
|
||||||
button: 'login',
|
button: 'login',
|
||||||
linkTo: '/login',
|
linkTo: '/login',
|
||||||
},
|
},
|
||||||
register: {
|
register: {
|
||||||
|
headline: 'site.thx.title',
|
||||||
subtitle: 'site.thx.register',
|
subtitle: 'site.thx.register',
|
||||||
button: 'site.login.signin',
|
button: 'site.login.signin',
|
||||||
linkTo: '/overview',
|
linkTo: '/overview',
|
||||||
},
|
},
|
||||||
checkEmail: {
|
checkEmail: {
|
||||||
|
headline: 'site.thx.title',
|
||||||
subtitle: 'site.thx.checkEmail',
|
subtitle: 'site.thx.checkEmail',
|
||||||
button: 'login',
|
button: 'login',
|
||||||
linkTo: '/login',
|
linkTo: '/login',
|
||||||
},
|
},
|
||||||
|
login: {
|
||||||
|
headline: 'site.thx.errorTitle',
|
||||||
|
subtitle: 'site.thx.activateEmail',
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
|||||||
@ -147,7 +147,6 @@ Poco::JSON::Object* JsonUnsecureLogin::handle(Poco::Dynamic::Var params)
|
|||||||
infos.add("set user.group_id to default group_id = 1");
|
infos.add("set user.group_id to default group_id = 1");
|
||||||
case USER_NO_PRIVATE_KEY:
|
case USER_NO_PRIVATE_KEY:
|
||||||
case USER_COMPLETE:
|
case USER_COMPLETE:
|
||||||
case USER_EMAIL_NOT_ACTIVATED:
|
|
||||||
result->set("state", "success");
|
result->set("state", "success");
|
||||||
result->set("user", session->getNewUser()->getJson());
|
result->set("user", session->getNewUser()->getJson());
|
||||||
result->set("session_id", session->getHandle());
|
result->set("session_id", session->getHandle());
|
||||||
@ -158,6 +157,10 @@ Poco::JSON::Object* JsonUnsecureLogin::handle(Poco::Dynamic::Var params)
|
|||||||
AWAIT(hasElopageTask)
|
AWAIT(hasElopageTask)
|
||||||
result->set("hasElopage", hasElopageTask->hasElopage());
|
result->set("hasElopage", hasElopageTask->hasElopage());
|
||||||
return result;
|
return result;
|
||||||
|
case USER_EMAIL_NOT_ACTIVATED:
|
||||||
|
result->set("state", "processing");
|
||||||
|
result->set("msg", "user email not validated");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
result->set("state", "error");
|
result->set("state", "error");
|
||||||
result->set("msg", "unknown user state");
|
result->set("msg", "unknown user state");
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user