Merge branch 'master' into 557-Switch-language-only-in-user-profile

This commit is contained in:
Moriz Wahl 2021-09-14 14:03:31 +02:00
commit 0427a31790
23 changed files with 489 additions and 246 deletions

View File

@ -18,6 +18,7 @@
"apollo-server-express": "^2.25.2",
"axios": "^0.21.1",
"class-validator": "^0.13.1",
"cors": "^2.8.5",
"dotenv": "^10.0.0",
"express": "^4.17.1",
"graphql": "^15.5.1",

View File

@ -4,6 +4,7 @@ import { AuthChecker } from 'type-graphql'
import decode from '../jwt/decode'
import { apiGet } from '../apis/loginAPI'
import CONFIG from '../config'
import encode from '../jwt/encode'
/* eslint-disable-next-line @typescript-eslint/no-unused-vars */
export const isAuthorized: AuthChecker<any> = async ({ root, args, context, info }, roles) => {
@ -14,6 +15,7 @@ export const isAuthorized: AuthChecker<any> = async ({ root, args, context, info
`${CONFIG.LOGIN_API_URL}checkSessionState?session_id=${decoded.sessionId}`,
)
context.sessionId = decoded.sessionId
context.setHeaders.push({ key: 'token', value: encode(decoded.sessionId) })
return result.success
}
}

View File

@ -4,10 +4,11 @@
import { Resolver, Query, Args, Arg, Authorized, Ctx } from 'type-graphql'
import CONFIG from '../../config'
import { CheckUsernameResponse } from '../models/CheckUsernameResponse'
import { User } from '../models/User'
import { LoginViaVerificationCode } from '../models/LoginViaVerificationCode'
import { SendPasswordResetEmailResponse } from '../models/SendPasswordResetEmailResponse'
import { UpdateUserInfosResponse } from '../models/UpdateUserInfosResponse'
import { User } from '../models/User'
import encode from '../../jwt/encode'
import {
ChangePasswordArgs,
CheckUsernameArgs,
@ -16,12 +17,11 @@ import {
UpdateUserInfosArgs,
} from '../inputs/LoginUserInput'
import { apiPost, apiGet } from '../../apis/loginAPI'
import encode from '../../jwt/encode'
@Resolver()
export class UserResolver {
@Query(() => String)
async login(@Args() { email, password }: UnsecureLoginArgs): Promise<string> {
@Query(() => User)
async login(@Args() { email, password }: UnsecureLoginArgs, @Ctx() context: any): Promise<User> {
email = email.trim().toLowerCase()
const result = await apiPost(CONFIG.LOGIN_API_URL + 'unsecureLogin', { email, password })
@ -30,10 +30,9 @@ export class UserResolver {
throw new Error(result.data)
}
const data = result.data
const sessionId = data.session_id
delete data.session_id
return encode({ sessionId, user: new User(data.user) })
context.setHeaders.push({ key: 'token', value: encode(result.data.session_id) })
return new User(result.data.user)
}
@Query(() => LoginViaVerificationCode)

View File

@ -2,6 +2,7 @@
import 'reflect-metadata'
import express from 'express'
import cors from 'cors'
import { buildSchema } from 'type-graphql'
import { ApolloServer } from 'apollo-server-express'
import { RowDataPacket } from 'mysql2/promise'
@ -22,14 +23,15 @@ import { isAuthorized } from './auth/auth'
const DB_VERSION = '0001-init_db'
const context = (req: any) => {
const authorization = req.req.headers.authorization
const context = (args: any) => {
const authorization = args.req.headers.authorization
let token = null
if (authorization) {
token = req.req.headers.authorization.replace(/^Bearer /, '')
token = authorization.replace(/^Bearer /, '')
}
const context = {
token,
setHeaders: [],
}
return context
}
@ -61,8 +63,31 @@ async function main() {
// Express Server
const server = express()
const corsOptions = {
origin: '*',
exposedHeaders: ['token'],
}
server.use(cors(corsOptions))
const plugins = [
{
requestDidStart() {
return {
willSendResponse(requestContext: any) {
const { setHeaders = [] } = requestContext.context
setHeaders.forEach(({ key, value }: { [key: string]: string }) => {
requestContext.response.http.headers.append(key, value)
})
return requestContext
},
}
},
},
]
// Apollo Server
const apollo = new ApolloServer({ schema, playground, context })
const apollo = new ApolloServer({ schema, playground, context, plugins })
apollo.applyMiddleware({ app: server })
// Start Server

View File

@ -7,15 +7,12 @@ import CONFIG from '../config/'
export default (token: string): any => {
if (!token) return null
let sessionId = null
const email = null
try {
const decoded = jwt.verify(token, CONFIG.JWT_SECRET)
sessionId = decoded.sub
// email = decoded.email
return {
token,
sessionId,
email,
}
} catch (err) {
return null

View File

@ -5,13 +5,9 @@ import jwt from 'jsonwebtoken'
import CONFIG from '../config/'
// Generate an Access Token
export default function encode(data: any): string {
const { user, sessionId } = data
const { email, language, firstName, lastName } = user
const token = jwt.sign({ email, language, firstName, lastName, sessionId }, CONFIG.JWT_SECRET, {
export default function encode(sessionId: string): string {
const token = jwt.sign({ sessionId }, CONFIG.JWT_SECRET, {
expiresIn: CONFIG.JWT_EXPIRES_IN,
// issuer: CONFIG.GRAPHQL_URI,
// audience: CONFIG.CLIENT_URI,
subject: sessionId.toString(),
})
return token

View File

@ -50,8 +50,8 @@ $this->assign('header', $header);
<?php if(intval($entry['gdt_entry_type_id']) == 7) : ?>
<?= $this->element('printGDT', ['number' => $entry['amount']*100.0]); ?>
<?php else : ?>
<?= $this->element('printEuro', ['number' => $entry['amount']]); ?>
<?php if($entry['amount2']) echo ' + ' . $this->element('printEuro', ['number' => $entry['amount2']]) ?>
<?= $this->element('printEuro', ['number' => $entry['amount']*100.0]); ?>
<?php if($entry['amount2']) echo ' + ' . $this->element('printEuro', ['number' => $entry['amount2']*100.0]) ?>
<?php endif; ?>
</div>
<div class="cell c2">
@ -96,8 +96,8 @@ $this->assign('header', $header);
<?php if(intval($gdtEntry['gdt_entry_type_id']) == 7) : ?>
<?= $this->element('printGDT', ['number' => $gdtEntry['amount']*100.0]); ?>
<?php else : ?>
<?= $this->element('printEuro', ['number' => $gdtEntry['amount']]); ?>
<?php if($gdtEntry['amount2']) echo ' + ' . $this->element('printEuro', ['number' => $gdtEntry['amount2']]) ?>
<?= $this->element('printEuro', ['number' => $gdtEntry['amount']*100.0]); ?>
<?php if($gdtEntry['amount2']) echo ' + ' . $this->element('printEuro', ['number' => $gdtEntry['amount2']*100.0]) ?>
<?php endif; ?>
</div>
<div class="cell c2">

View File

@ -22,7 +22,8 @@ loginServer.db.user = root
loginServer.db.password =
loginServer.db.port = 3306
frontend.checkEmailPath = http://localhost/reset
frontend.checkEmailPath = vue/checkEmail
frontend.resetPasswordPath = vue/reset
email.disable = true

View File

@ -72,7 +72,6 @@
"vue-good-table": "^2.21.3",
"vue-i18n": "^8.22.4",
"vue-jest": "^3.0.7",
"vue-jwt-decode": "^0.1.0",
"vue-loading-overlay": "^3.4.2",
"vue-moment": "^4.1.0",
"vue-qrcode": "^0.3.5",

View File

@ -0,0 +1,31 @@
import { mount } from '@vue/test-utils'
import Transaction from './Transaction'
const localVue = global.localVue
describe('Transaction', () => {
let wrapper
const mocks = {
$i18n: {
locale: 'en',
},
$t: jest.fn((t) => t),
$n: jest.fn((n) => n),
$d: jest.fn((d) => d),
}
const Wrapper = () => {
return mount(Transaction, { localVue, mocks })
}
describe('mount', () => {
beforeEach(() => {
wrapper = Wrapper()
})
it('renders the component', () => {
expect(wrapper.find('div.gdt-transaction-list-item').exists()).toBeTruthy()
})
})
})

View File

@ -0,0 +1,124 @@
<template>
<div>
<div class="list-group">
<div class="list-group-item gdt-transaction-list-item" v-b-toggle="'a' + date + ''">
<!-- icon -->
<div class="text-right" style="position: absolute">
<b-icon
:icon="getLinesByType(gdtEntryType).icon"
:class="getLinesByType(gdtEntryType).iconclasses"
></b-icon>
</div>
<!-- collaps Button -->
<div class="text-right" style="width: 96%; position: absolute">
<b-button class="btn-sm">
<b>i</b>
</b-button>
</div>
<!-- type -->
<b-row>
<div class="col-6 text-right">
{{ getLinesByType(gdtEntryType).description }}
</div>
<div class="col-6">
{{ getLinesByType(gdtEntryType).descriptiontext }}
</div>
</b-row>
<!-- credit -->
<b-row>
<div class="col-6 text-right">
{{ $t('gdt.credit') }}
</div>
<div class="col-6">
{{ getLinesByType(gdtEntryType).credittext }}
</div>
</b-row>
<!-- Message-->
<b-row v-if="comment && gdtEntryType !== 7">
<div class="col-6 text-right">
{{ $t('form.memo') }}
</div>
<div class="col-6">
{{ comment }}
</div>
</b-row>
<!-- date-->
<b-row class="gdt-list-row text-header">
<div class="col-6 text-right">
{{ $t('form.date') }}
</div>
<div class="col-6">
{{ $d($moment(date), 'long') }} {{ $i18n.locale === 'de' ? 'Uhr' : '' }}
</div>
</b-row>
</div>
<!-- collaps trancaction info-->
<b-collapse :id="'a' + date + ''" class="pb-4">
<transaction-collapse
:amount="amount"
:gdtEntryType="gdtEntryType"
:factor="factor"
:gdt="gdt"
></transaction-collapse>
</b-collapse>
</div>
</div>
</template>
<script>
import TransactionCollapse from './TransactionCollapse.vue'
export default {
name: 'Transaction',
components: {
TransactionCollapse,
},
props: {
amount: { type: Number },
date: { type: String },
comment: { type: String },
gdtEntryType: { type: Number, default: 1 },
factor: { type: Number },
gdt: { type: Number },
},
methods: {
getLinesByType(givenType) {
if (givenType === 2 || givenType === 3 || givenType === 5 || givenType === 6) givenType = 1
const linesByType = {
1: {
icon: 'heart',
iconclasses: 'gradido-global-color-accent m-mb-1 font2em',
description: this.$t('gdt.contribution'),
descriptiontext: this.$n(this.amount, 'decimal') + ' €',
credittext: this.$n(this.gdt, 'decimal') + ' GDT',
},
4: {
icon: 'person-check',
iconclasses: 'gradido-global-color-accent m-mb-1 font2em',
description: this.$t('gdt.recruited-member'),
descriptiontext: '5%',
credittext: this.$n(this.amount, 'decimal') + ' GDT',
},
7: {
icon: 'gift',
iconclasses: 'gradido-global-color-accent m-mb-1 font2em',
description: this.$t('gdt.gdt-received'),
descriptiontext: this.comment,
credittext: this.$n(this.gdt, 'decimal') + ' GDT',
},
}
const type = linesByType[givenType]
if (type) return type
throw new Error('no lines for this type: ' + givenType)
},
},
}
</script>

View File

@ -0,0 +1,152 @@
import { mount } from '@vue/test-utils'
import TransactionCollapse from './TransactionCollapse'
const localVue = global.localVue
describe('TransactionCollapse', () => {
let wrapper
const mocks = {
$t: jest.fn((t) => t),
$n: jest.fn((n) => n),
}
const Wrapper = (propsData) => {
return mount(TransactionCollapse, { localVue, mocks, propsData })
}
describe('mount with gdtEntryType: 1', () => {
beforeEach(() => {
const propsData = {
amount: 100,
gdt: 110,
factor: 22,
gdtEntryType: 1,
}
wrapper = Wrapper(propsData)
})
it('renders the component', () => {
expect(wrapper.find('div.gdt-transaction-collapse').exists()).toBeTruthy()
})
it('checks the prop gdtEntryType ', () => {
expect(wrapper.props().gdtEntryType).toBe(1)
})
it('renders the component collapse-header', () => {
expect(wrapper.find('.gdt-list-collapse-header-text')).toBeTruthy()
})
it('renders the component collapse-headline', () => {
expect(wrapper.find('#collapse-headline').text()).toBe('gdt.calculation')
})
it('renders the component collapse-first', () => {
expect(wrapper.find('#collapse-first').text()).toBe('gdt.factor')
})
it('renders the component collapse-second', () => {
expect(wrapper.find('#collapse-second').text()).toBe('gdt.formula')
})
it('renders the component collapse-firstMath', () => {
expect(wrapper.find('#collapse-firstMath').text()).toBe('22 GDT pro €')
})
it('renders the component collapse-secondMath', () => {
expect(wrapper.find('#collapse-secondMath').text()).toBe('100 € * 22 GDT / € = 110 GDT')
})
})
describe('mount with gdtEntryType: 7', () => {
beforeEach(() => {
const propsData = {
amount: 100,
gdt: 2200,
factor: 22,
gdtEntryType: 7,
}
wrapper = Wrapper(propsData)
})
it('renders the component', () => {
expect(wrapper.find('div.gdt-transaction-collapse').exists()).toBeTruthy()
})
it('checks the prop gdtEntryType ', () => {
expect(wrapper.props().gdtEntryType).toBe(7)
})
it('renders the component collapse-header', () => {
expect(wrapper.find('.gdt-list-collapse-header-text')).toBeTruthy()
})
it('renders the component collapse-headline', () => {
expect(wrapper.find('#collapse-headline').text()).toBe('gdt.conversion-gdt-euro')
})
it('renders the component collapse-first', () => {
expect(wrapper.find('#collapse-first').text()).toBe('gdt.raise')
})
it('renders the component collapse-second', () => {
expect(wrapper.find('#collapse-second').text()).toBe('gdt.conversion')
})
it('renders the component collapse-firstMath', () => {
expect(wrapper.find('#collapse-firstMath').text()).toBe('2200 %')
})
it('renders the component collapse-secondMath', () => {
expect(wrapper.find('#collapse-secondMath').text()).toBe('100 GDT * 2200 % = 2200 GDT')
})
})
describe('mount with gdtEntryType: 4', () => {
beforeEach(() => {
const propsData = {
amount: 100,
gdt: 2200,
factor: 22,
gdtEntryType: 4,
}
wrapper = Wrapper(propsData)
})
it('renders the component', () => {
expect(wrapper.find('div.gdt-transaction-collapse').exists()).toBeTruthy()
})
it('checks the prop gdtEntryType ', () => {
expect(wrapper.props().gdtEntryType).toBe(4)
})
it('renders the component collapse-header', () => {
expect(wrapper.find('.gdt-list-collapse-header-text')).toBeTruthy()
})
it('renders the component collapse-headline', () => {
expect(wrapper.find('#collapse-headline').text()).toBe('gdt.publisher')
})
it('renders the component collapse-first', () => {
expect(wrapper.find('#collapse-first').text()).toBe('')
})
it('renders the component collapse-second', () => {
expect(wrapper.find('#collapse-second').text()).toBe('')
})
it('renders the component collapse-firstMath', () => {
expect(wrapper.find('#collapse-firstMath').text()).toBe('')
})
it('renders the component collapse-secondMath', () => {
expect(wrapper.find('#collapse-secondMath').text()).toBe('')
})
})
})

View File

@ -0,0 +1,76 @@
<template>
<div class="gdt-transaction-collapse">
<b-row class="gdt-list-collapse-header-text text-center pb-3">
<div id="collapse-headline" class="col h4">
{{ getLinesByType(gdtEntryType).headline }}
</div>
</b-row>
<b-row class="gdt-list-collapse-box--all">
<div class="col-6 text-right collapse-col-left">
<div id="collapse-first">{{ getLinesByType(gdtEntryType).first }}</div>
<div id="collapse-second">{{ getLinesByType(gdtEntryType).second }}</div>
</div>
<div class="col-6 collapse-col-right">
<div id="collapse-firstMath">{{ getLinesByType(gdtEntryType).firstMath }}</div>
<div id="collapse-secondMath">
{{ getLinesByType(gdtEntryType).secondMath }}
</div>
</div>
</b-row>
</div>
</template>
<script>
export default {
name: 'TransactionCollapse',
props: {
amount: { type: Number },
gdtEntryType: { type: Number, default: 1 },
factor: { type: Number },
gdt: { type: Number },
},
methods: {
getLinesByType(givenType) {
const linesByType = {
1: {
headline: this.$t('gdt.calculation'),
first: this.$t('gdt.factor'),
firstMath: this.factor + ' GDT pro €',
second: this.$t('gdt.formula'),
secondMath:
this.$n(this.amount, 'decimal') +
' € * ' +
this.factor +
' GDT / € = ' +
this.$n(this.gdt, 'decimal') +
' GDT',
},
4: {
headline: this.$t('gdt.publisher'),
first: null,
firstMath: null,
second: null,
secondMath: null,
},
7: {
headline: this.$t('gdt.conversion-gdt-euro'),
first: this.$t('gdt.raise'),
firstMath: this.factor * 100 + ' % ',
second: this.$t('gdt.conversion'),
secondMath:
this.$n(this.amount, 'decimal') +
' GDT * ' +
this.factor * 100 +
' % = ' +
this.$n(this.gdt, 'decimal') +
' GDT',
},
}
const type = linesByType[givenType]
if (type) return type
throw new Error('no additional transaction info for this type: ' + givenType)
},
},
}
</script>

View File

@ -2,7 +2,14 @@ import gql from 'graphql-tag'
export const login = gql`
query($email: String!, $password: String!) {
login(email: $email, password: $password)
login(email: $email, password: $password) {
email
username
firstName
lastName
language
description
}
}
`

View File

@ -138,15 +138,6 @@
"send_gradido":"Gradido versenden",
"add_work":"neuer Gemeinschaftsbeitrag"
},
"profil": {
"activity": {
"new":"Neue Gemeinschaftsstunden eintragen",
"list":"Meine Gemeinschaftsstunden Liste"
},
"user-data": {
"change-success": "Deine Daten wurden gespeichert."
}
},
"navbar" : {
"my-profil":"Mein Profil",
"settings":"Einstellungen",
@ -184,8 +175,8 @@
"formula":"Berechungsformel",
"no-transactions":"Du hast zur Zeit keine Transaktionen",
"publisher":"Dein geworbenes Mitglied hat einen Beitrag bezahlt",
"gdt-receive":"Aktion",
"your-share":"Geworbenes Mitglied",
"action":"Aktion",
"recruited-member":"Geworbenes Mitglied",
"contribution":"Beitrag"
}
}

View File

@ -138,16 +138,6 @@
"send_gradido":"Send Gradido",
"add_work":"New Community Contribution"
},
"profil": {
"transactions":"transactions",
"activity": {
"new":"Register new community hours",
"list":"My Community Hours List"
},
"user-data": {
"change-success": "Your data has been saved."
}
},
"navbar" : {
"my-profil":"My profile",
"settings":"Settings",
@ -185,8 +175,8 @@
"formula": "Calculation formula",
"no-transactions":"You currently have no transactions",
"publisher":"A member you referred has paid a contribution",
"gdt-receive":"GDT receive",
"your-share":"Your share",
"action":"Action",
"recruited-member":"Recruited Member",
"contribution":"Contribution"
}
}

View File

@ -20,7 +20,11 @@ const authLink = new ApolloLink((operation, forward) => {
Authorization: token && token.length > 0 ? `Bearer ${token}` : '',
},
})
return forward(operation)
return forward(operation).map((response) => {
const newToken = operation.getContext().response.headers.get('token')
if (newToken) store.commit('token', newToken)
return response
})
})
const apolloClient = new ApolloClient({

View File

@ -1,7 +1,6 @@
import Vue from 'vue'
import Vuex from 'vuex'
import createPersistedState from 'vuex-persistedstate'
import VueJwtDecode from 'vue-jwt-decode'
Vue.use(Vuex)
@ -30,15 +29,13 @@ export const mutations = {
}
export const actions = {
login: ({ dispatch, commit }, token) => {
const decoded = VueJwtDecode.decode(token)
commit('token', token)
commit('email', decoded.email)
commit('language', decoded.language)
commit('username', decoded.username)
commit('firstName', decoded.firstName)
commit('lastName', decoded.lastName)
commit('description', decoded.description)
login: ({ dispatch, commit }, data) => {
commit('email', data.email)
commit('language', data.language)
commit('username', data.username)
commit('firstName', data.firstName)
commit('lastName', data.lastName)
commit('description', data.description)
},
logout: ({ commit, state }) => {
commit('token', null)

View File

@ -1,15 +1,4 @@
import { mutations, actions } from './store'
import VueJwtDecode from 'vue-jwt-decode'
jest.mock('vue-jwt-decode')
VueJwtDecode.decode.mockReturnValue({
email: 'user@example.org',
language: 'de',
username: 'peter',
firstName: 'Peter',
lastName: 'Lustig',
description: 'Nickelbrille',
})
const { language, email, token, username, firstName, lastName, description } = mutations
const { login, logout } = actions
@ -77,46 +66,48 @@ describe('Vuex store', () => {
describe('login', () => {
const commit = jest.fn()
const state = {}
const commitedData = 'token'
const commitedData = {
email: 'user@example.org',
language: 'de',
username: 'peter',
firstName: 'Peter',
lastName: 'Lustig',
description: 'Nickelbrille',
}
it('calls seven commits', () => {
login({ commit, state }, commitedData)
expect(commit).toHaveBeenCalledTimes(7)
})
it('commits token', () => {
login({ commit, state }, commitedData)
expect(commit).toHaveBeenNthCalledWith(1, 'token', 'token')
expect(commit).toHaveBeenCalledTimes(6)
})
it('commits email', () => {
login({ commit, state }, commitedData)
expect(commit).toHaveBeenNthCalledWith(2, 'email', 'user@example.org')
expect(commit).toHaveBeenNthCalledWith(1, 'email', 'user@example.org')
})
it('commits language', () => {
login({ commit, state }, commitedData)
expect(commit).toHaveBeenNthCalledWith(3, 'language', 'de')
expect(commit).toHaveBeenNthCalledWith(2, 'language', 'de')
})
it('commits username', () => {
login({ commit, state }, commitedData)
expect(commit).toHaveBeenNthCalledWith(4, 'username', 'peter')
expect(commit).toHaveBeenNthCalledWith(3, 'username', 'peter')
})
it('commits firstName', () => {
login({ commit, state }, commitedData)
expect(commit).toHaveBeenNthCalledWith(5, 'firstName', 'Peter')
expect(commit).toHaveBeenNthCalledWith(4, 'firstName', 'Peter')
})
it('commits lastName', () => {
login({ commit, state }, commitedData)
expect(commit).toHaveBeenNthCalledWith(6, 'lastName', 'Lustig')
expect(commit).toHaveBeenNthCalledWith(5, 'lastName', 'Lustig')
})
it('commits description', () => {
login({ commit, state }, commitedData)
expect(commit).toHaveBeenNthCalledWith(7, 'description', 'Nickelbrille')
expect(commit).toHaveBeenNthCalledWith(6, 'description', 'Nickelbrille')
})
})

View File

@ -17,134 +17,14 @@
} in transactionsGdt"
:key="transactionId"
>
<div class="list-group-item gdt-transaction-list-item" v-b-toggle="'a' + date + ''">
<!-- Icon -->
<div class="text-right" style="position: absolute">
<b-icon
v-if="gdtEntryType"
:icon="getIcon(gdtEntryType).icon"
:class="getIcon(gdtEntryType).class"
></b-icon>
</div>
<!-- Collaps Button -->
<div class="text-right" style="width: 96%; position: absolute">
<b-button class="btn-sm">
<b>i</b>
</b-button>
</div>
<!-- Betrag -->
<!-- 7 nur GDT erhalten -->
<b-row v-if="gdtEntryType === 7">
<div class="col-6 text-right">
<div>{{ $t('gdt.gdt-receive') }}</div>
<div>{{ $t('gdt.credit') }}</div>
</div>
<div class="col-6">
<div>{{ comment }}</div>
<div>{{ $n(gdt, 'decimal') }} GDT</div>
</div>
</b-row>
<!--4 publisher -->
<b-row v-else-if="gdtEntryType === 4">
<div class="col-6 text-right">
<div>{{ $t('gdt.your-share') }}</div>
<div>{{ $t('gdt.credit') }}</div>
</div>
<div class="col-6">
<div>5%</div>
<div>{{ $n(amount, 'decimal') }} GDT</div>
</div>
</b-row>
<!-- 1, 2, 3, 5, 6 spenden in euro -->
<b-row v-else>
<div class="col-6 text-right">
<div>{{ $t('gdt.contribution') }}</div>
<div>{{ $t('gdt.credit') }}</div>
</div>
<div class="col-6">
<div>{{ $n(amount, 'decimal') }} </div>
<div>{{ $n(gdt, 'decimal') }} GDT</div>
</div>
</b-row>
<!-- Betrag ENDE-->
<!-- Nachricht-->
<b-row v-if="comment && gdtEntryType !== 7">
<div class="col-6 text-right">
{{ $t('form.memo') }}
</div>
<div class="col-6">
{{ comment }}
</div>
</b-row>
<!-- Datum-->
<b-row v-if="date" class="gdt-list-row text-header">
<div class="col-6 text-right">
{{ $t('form.date') }}
</div>
<div class="col-6">
{{ $d($moment(date), 'long') }} {{ $i18n.locale === 'de' ? 'Uhr' : '' }}
</div>
</b-row>
</div>
<!-- Collaps START -->
<b-collapse v-if="gdtEntryType" :id="'a' + date + ''" class="pb-4">
<div style="border: 0px; background-color: #f1f1f1" class="p-2 pb-4 mb-4">
<!-- Überschrift -->
<b-row class="gdt-list-clooaps-header-text text-center pb-3">
<div class="col h4" v-if="gdtEntryType === 7">
{{ $t('gdt.conversion-gdt-euro') }}
</div>
<div class="col h4" v-else-if="gdtEntryType === 4">
{{ $t('gdt.publisher') }}
</div>
<div class="col h4" v-else>{{ $t('gdt.calculation') }}</div>
</b-row>
<!-- 7 nur GDT erhalten -->
<b-row class="gdt-list-clooaps-box-7" v-if="gdtEntryType == 7">
<div class="col-6 text-right clooaps-col-left">
<div>{{ $t('gdt.raise') }}</div>
<div>{{ $t('gdt.conversion') }}</div>
</div>
<div class="col-6 clooaps-col-right">
<div>{{ factor * 100 }} %</div>
<div>
{{ $n(amount, 'decimal') }} GDT * {{ factor * 100 }} % =
{{ $n(gdt, 'decimal') }} GDT
</div>
</div>
</b-row>
<!-- 4 publisher -->
<b-row class="gdt-list-clooaps-box-4" v-else-if="gdtEntryType === 4">
<div class="col-6 text-right clooaps-col-left"></div>
<div class="col-6 clooaps-col-right"></div>
</b-row>
<!-- 1, 2, 3, 5, 6 spenden in euro -->
<b-row class="gdt-list-clooaps-box--all" v-else>
<div class="col-6 text-right clooaps-col-left">
<div>{{ $t('gdt.factor') }}</div>
<div>{{ $t('gdt.formula') }}</div>
</div>
<div class="col-6 clooaps-col-right">
<div>{{ factor }} GDT pro </div>
<div>
{{ $n(amount, 'decimal') }} * {{ factor }} GDT / =
{{ $n(gdt, 'decimal') }} GDT
</div>
</div>
</b-row>
</div>
</b-collapse>
<!-- Collaps ENDE -->
<transaction
:amount="amount"
:date="date"
:comment="comment"
:gdtEntryType="gdtEntryType"
:factor="factor"
:gdt="gdt"
></transaction>
</div>
</div>
<pagination-buttons
@ -162,26 +42,13 @@
<script>
import { listGDTEntriesQuery } from '../../../graphql/queries'
import PaginationButtons from '../../../components/PaginationButtons'
function iconByType(typeId) {
switch (typeId) {
case 1:
case 2:
case 3:
case 5:
case 6:
return { icon: 'heart', classes: 'gradido-global-color-accent' }
case 4:
return { icon: 'person-check', classes: 'gradido-global-color-accent' }
case 7:
return { icon: 'gift', classes: 'gradido-global-color-accent' }
}
}
import Transaction from '../../../components/Transaction.vue'
export default {
name: 'gdt-transaction-list',
components: {
PaginationButtons,
Transaction,
},
data() {
return {
@ -223,18 +90,6 @@ export default {
this.$toasted.error(error.message)
})
},
getIcon(givenType) {
const type = iconByType(givenType)
if (type)
return {
icon: type.icon,
class: type.classes + ' m-mb-1 font2em',
}
this.throwError('no icon to given type: ' + givenType)
},
throwError(msg) {
throw new Error(msg)
},
showNext() {
this.currentPage++
this.updateGdt()

View File

@ -105,12 +105,13 @@ Poco::JSON::Object* JsonSendEmail::handle(Poco::Dynamic::Var params)
return stateSuccess();
}
auto receiver_user_id = receiver_user->getModel()->getID();
std::string checkEmailUrl = receiver_user->getGroupBaseUrl() + ServerConfig::g_frontend_checkEmailPath;
std::string linkInEmail = "";
if (emailVerificationCodeType == model::table::EMAIL_OPT_IN_RESET_PASSWORD)
{
linkInEmail = receiver_user->getGroupBaseUrl() + ServerConfig::g_frontend_resetPasswordPath;
session = sm->getNewSession();
if (emailType == model::EMAIL_USER_RESET_PASSWORD) {
auto r = session->sendResetPasswordEmail(receiver_user, true, checkEmailUrl);
auto r = session->sendResetPasswordEmail(receiver_user, true, linkInEmail);
if (1 == r) {
return stateWarning("email already sended");
}
@ -120,7 +121,7 @@ Poco::JSON::Object* JsonSendEmail::handle(Poco::Dynamic::Var params)
}
else if (emailType == model::EMAIL_CUSTOM_TEXT) {
auto email_verification_code_object = controller::EmailVerificationCode::loadOrCreate(receiver_user_id, model::table::EMAIL_OPT_IN_RESET_PASSWORD);
email_verification_code_object->setBaseUrl(checkEmailUrl);
email_verification_code_object->setBaseUrl(linkInEmail);
auto email = new model::Email(email_verification_code_object, receiver_user, emailCustomText, emailCustomSubject);
em->addEmail(email);
}
@ -131,12 +132,13 @@ Poco::JSON::Object* JsonSendEmail::handle(Poco::Dynamic::Var params)
}
else
{
linkInEmail = receiver_user->getGroupBaseUrl() + ServerConfig::g_frontend_checkEmailPath;
if (session->getNewUser()->getModel()->getRole() != model::table::ROLE_ADMIN) {
return stateError("admin needed");
}
auto email_verification_code_object = controller::EmailVerificationCode::loadOrCreate(receiver_user_id, emailVerificationCodeType);
email_verification_code_object->setBaseUrl(checkEmailUrl);
email_verification_code_object->setBaseUrl(linkInEmail);
model::Email* email = nullptr;
if (emailType == model::EMAIL_CUSTOM_TEXT) {
email = new model::Email(email_verification_code_object, receiver_user, emailCustomText, emailCustomSubject);

View File

@ -51,6 +51,7 @@ namespace ServerConfig {
std::string g_php_serverPath;
std::string g_php_serverHost;
std::string g_frontend_checkEmailPath;
std::string g_frontend_resetPasswordPath;
int g_phpServerPort;
Poco::Mutex g_TimeMutex;
int g_FakeLoginSleepTime = 820;
@ -238,8 +239,9 @@ namespace ServerConfig {
if ("" != app_secret_string) {
g_CryptoAppSecret = DataTypeConverter::hexToBin(app_secret_string);
}
std::string defaultCheckEmailPath = g_serverPath + "/checkEmail";
std::string defaultCheckEmailPath = "/account/checkEmail";
g_frontend_checkEmailPath = cfg.getString("frontend.checkEmailPath", defaultCheckEmailPath);
g_frontend_resetPasswordPath = cfg.getString("frontend.resetPasswordPath", defaultCheckEmailPath);
//g_CryptoAppSecret
// unsecure flags

View File

@ -67,6 +67,7 @@ namespace ServerConfig {
extern std::string g_php_serverPath;
extern std::string g_php_serverHost;
extern std::string g_frontend_checkEmailPath;
extern std::string g_frontend_resetPasswordPath;
extern int g_phpServerPort;
extern Poco::Mutex g_TimeMutex;
extern int g_FakeLoginSleepTime;