Merge branch 'master' into 1029-Change-text-for-expired-session

This commit is contained in:
Alexander Friedland 2021-12-07 12:47:08 +01:00 committed by GitHub
commit 707e5c6684
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 784 additions and 145 deletions

View File

@ -441,7 +441,7 @@ jobs:
report_name: Coverage Admin Interface report_name: Coverage Admin Interface
type: lcov type: lcov
result_path: ./coverage/lcov.info result_path: ./coverage/lcov.info
min_coverage: 55 min_coverage: 60
token: ${{ github.token }} token: ${{ github.token }}
############################################################################## ##############################################################################
@ -657,4 +657,4 @@ jobs:
- name: database | up - name: database | up
run: docker-compose -f docker-compose.yml run -T database yarn up run: docker-compose -f docker-compose.yml run -T database yarn up
- name: database | reset - name: database | reset
run: docker-compose -f docker-compose.yml run -T database yarn reset run: docker-compose -f docker-compose.yml run -T database yarn reset

View File

@ -11,7 +11,14 @@ const apolloMock = jest.fn().mockResolvedValue({
}, },
}, },
}) })
const apolloMutateMock = jest.fn().mockResolvedValue({
data: {
createPendingCreation: [0, 0, 0],
},
})
const stateCommitMock = jest.fn() const stateCommitMock = jest.fn()
const toastedErrorMock = jest.fn()
const toastedSuccessMock = jest.fn()
const mocks = { const mocks = {
$moment: jest.fn(() => { $moment: jest.fn(() => {
@ -26,15 +33,25 @@ const mocks = {
}), }),
$apollo: { $apollo: {
query: apolloMock, query: apolloMock,
mutate: apolloMutateMock,
}, },
$store: { $store: {
commit: stateCommitMock, commit: stateCommitMock,
state: {
moderator: {
id: 0,
name: 'test moderator',
},
},
},
$toasted: {
error: toastedErrorMock,
success: toastedSuccessMock,
}, },
} }
const propsData = { const propsData = {
type: '', type: '',
item: {},
creation: [], creation: [],
itemsMassCreation: {}, itemsMassCreation: {},
} }
@ -64,9 +81,10 @@ describe('CreationFormular', () => {
describe('server throws error for moderator data call', () => { describe('server throws error for moderator data call', () => {
beforeEach(() => { beforeEach(() => {
jest.clearAllMocks() jest.clearAllMocks()
apolloMock.mockRejectedValue({ message: 'Ouch!' }) apolloMock.mockRejectedValueOnce({ message: 'Ouch!' })
wrapper = Wrapper() wrapper = Wrapper()
}) })
it('has called store commit with fake data', () => { it('has called store commit with fake data', () => {
expect(stateCommitMock).toBeCalledWith('moderator', { id: 0, name: 'Test Moderator' }) expect(stateCommitMock).toBeCalledWith('moderator', { id: 0, name: 'Test Moderator' })
}) })
@ -125,6 +143,8 @@ describe('CreationFormular', () => {
jest.clearAllMocks() jest.clearAllMocks()
await wrapper.setProps({ type: 'singleCreation', creation: [200, 400, 600] }) await wrapper.setProps({ type: 'singleCreation', creation: [200, 400, 600] })
await wrapper.setData({ rangeMin: 180 }) await wrapper.setData({ rangeMin: 180 })
await wrapper.setData({ text: 'Test create coins' })
await wrapper.setData({ value: 90 })
}) })
describe('first radio button', () => { describe('first radio button', () => {
@ -139,6 +159,66 @@ describe('CreationFormular', () => {
it('sets rangeMax to 200', () => { it('sets rangeMax to 200', () => {
expect(wrapper.vm.rangeMax).toBe(200) expect(wrapper.vm.rangeMax).toBe(200)
}) })
describe('sendForm', () => {
beforeEach(async () => {
await wrapper.find('.test-submit').trigger('click')
})
it('sends ... to apollo', () => {
expect(apolloMutateMock).toBeCalled()
})
})
describe('sendForm', () => {
beforeEach(async () => {
apolloMutateMock.mockRejectedValueOnce({ message: 'Ouch!' })
await wrapper.find('.test-submit').trigger('click')
})
it('sends ... to apollo', () => {
expect(toastedErrorMock).toBeCalled()
})
})
describe('Negativ value', () => {
beforeEach(async () => {
jest.clearAllMocks()
await wrapper.setProps({ type: 'singleCreation', creation: [200, 400, 600] })
await wrapper.setData({ rangeMin: 180 })
await wrapper.setData({ value: -20 })
})
it('has no submit button', async () => {
expect(await wrapper.find('.test-submit').attributes('disabled')).toBe('disabled')
})
})
describe('Empty text', () => {
beforeEach(async () => {
jest.clearAllMocks()
await wrapper.setProps({ type: 'singleCreation', creation: [200, 400, 600] })
await wrapper.setData({ rangeMin: 180 })
await wrapper.setData({ text: '' })
})
it('has no submit button', async () => {
expect(await wrapper.find('.test-submit').attributes('disabled')).toBe('disabled')
})
})
describe('Text length less than 10', () => {
beforeEach(async () => {
jest.clearAllMocks()
await wrapper.setProps({ type: 'singleCreation', creation: [200, 400, 600] })
await wrapper.setData({ rangeMin: 180 })
await wrapper.setData({ text: 'Try this' })
})
it('has no submit button', async () => {
expect(await wrapper.find('.test-submit').attributes('disabled')).toBe('disabled')
})
})
}) })
describe('second radio button', () => { describe('second radio button', () => {
@ -153,6 +233,55 @@ describe('CreationFormular', () => {
it('sets rangeMax to 400', () => { it('sets rangeMax to 400', () => {
expect(wrapper.vm.rangeMax).toBe(400) expect(wrapper.vm.rangeMax).toBe(400)
}) })
describe('sendForm', () => {
beforeEach(async () => {
await wrapper.find('.test-submit').trigger('click')
})
it('sends ... to apollo', () => {
expect(apolloMutateMock).toBeCalled()
})
})
describe('Negativ value', () => {
beforeEach(async () => {
jest.clearAllMocks()
await wrapper.setProps({ type: 'singleCreation', creation: [200, 400, 600] })
await wrapper.setData({ rangeMin: 180 })
await wrapper.setData({ value: -20 })
})
it('has no submit button', async () => {
expect(await wrapper.find('.test-submit').attributes('disabled')).toBe('disabled')
})
})
describe('Empty text', () => {
beforeEach(async () => {
jest.clearAllMocks()
await wrapper.setProps({ type: 'singleCreation', creation: [200, 400, 600] })
await wrapper.setData({ rangeMin: 180 })
await wrapper.setData({ text: '' })
})
it('has no submit button', async () => {
expect(await wrapper.find('.test-submit').attributes('disabled')).toBe('disabled')
})
})
describe('Text length less than 10', () => {
beforeEach(async () => {
jest.clearAllMocks()
await wrapper.setProps({ type: 'singleCreation', creation: [200, 400, 600] })
await wrapper.setData({ rangeMin: 180 })
await wrapper.setData({ text: 'Try this' })
})
it('has no submit button', async () => {
expect(await wrapper.find('.test-submit').attributes('disabled')).toBe('disabled')
})
})
}) })
describe('third radio button', () => { describe('third radio button', () => {
@ -167,6 +296,63 @@ describe('CreationFormular', () => {
it('sets rangeMax to 400', () => { it('sets rangeMax to 400', () => {
expect(wrapper.vm.rangeMax).toBe(600) expect(wrapper.vm.rangeMax).toBe(600)
}) })
describe('sendForm', () => {
beforeEach(async () => {
await wrapper.find('.test-submit').trigger('click')
})
it('sends mutation to apollo', () => {
expect(apolloMutateMock).toBeCalled()
})
it('toast success message', () => {
expect(toastedSuccessMock).toBeCalled()
})
it('store commit openCreationPlus', () => {
expect(stateCommitMock).toBeCalledWith('openCreationsPlus', 1)
})
})
describe('Negativ value', () => {
beforeEach(async () => {
jest.clearAllMocks()
await wrapper.setProps({ type: 'singleCreation', creation: [200, 400, 600] })
await wrapper.setData({ rangeMin: 180 })
await wrapper.setData({ value: -20 })
})
it('has no submit button', async () => {
expect(await wrapper.find('.test-submit').attributes('disabled')).toBe('disabled')
})
})
describe('Empty text', () => {
beforeEach(async () => {
jest.clearAllMocks()
await wrapper.setProps({ type: 'singleCreation', creation: [200, 400, 600] })
await wrapper.setData({ rangeMin: 180 })
await wrapper.setData({ text: '' })
})
it('has no submit button', async () => {
expect(await wrapper.find('.test-submit').attributes('disabled')).toBe('disabled')
})
})
describe('Text length less than 10', () => {
beforeEach(async () => {
jest.clearAllMocks()
await wrapper.setProps({ type: 'singleCreation', creation: [200, 400, 600] })
await wrapper.setData({ rangeMin: 180 })
await wrapper.setData({ text: 'Try this' })
})
it('has no submit button', async () => {
expect(await wrapper.find('.test-submit').attributes('disabled')).toBe('disabled')
})
})
}) })
}) })
}) })

View File

@ -6,6 +6,7 @@
<label>Monat Auswählen</label> <label>Monat Auswählen</label>
<b-col class="text-left"> <b-col class="text-left">
<b-form-radio <b-form-radio
id="beforeLastMonth"
v-model="radioSelected" v-model="radioSelected"
:value="beforeLastMonth" :value="beforeLastMonth"
:disabled="creation[0] === 0" :disabled="creation[0] === 0"
@ -19,6 +20,7 @@
</b-col> </b-col>
<b-col> <b-col>
<b-form-radio <b-form-radio
id="lastMonth"
v-model="radioSelected" v-model="radioSelected"
:value="lastMonth" :value="lastMonth"
:disabled="creation[1] === 0" :disabled="creation[1] === 0"
@ -32,6 +34,7 @@
</b-col> </b-col>
<b-col class="text-right"> <b-col class="text-right">
<b-form-radio <b-form-radio
id="currentMonth"
v-model="radioSelected" v-model="radioSelected"
:value="currentMonth" :value="currentMonth"
:disabled="creation[2] === 0" :disabled="creation[2] === 0"
@ -45,7 +48,7 @@
</b-col> </b-col>
</b-row> </b-row>
<b-row class="m-4" v-show="createdIndex"> <b-row class="m-4" v-show="createdIndex != null">
<label>Betrag Auswählen</label> <label>Betrag Auswählen</label>
<div> <div>
<b-input-group prepend="GDD" append=".00"> <b-input-group prepend="GDD" append=".00">
@ -92,6 +95,7 @@
v-if="pagetype === 'PageCreationConfirm'" v-if="pagetype === 'PageCreationConfirm'"
type="button" type="button"
variant="success" variant="success"
class="test-submit"
@click="submitCreation" @click="submitCreation"
:disabled="radioSelected === '' || value <= 0 || text.length < 10" :disabled="radioSelected === '' || value <= 0 || text.length < 10"
> >
@ -102,6 +106,7 @@
v-else v-else
type="button" type="button"
variant="success" variant="success"
class="test-submit"
@click="submitCreation" @click="submitCreation"
:disabled="radioSelected === '' || value <= 0 || text.length < 10" :disabled="radioSelected === '' || value <= 0 || text.length < 10"
> >
@ -159,7 +164,7 @@ export default {
return { return {
radioSelected: '', radioSelected: '',
text: !this.creationUserData.memo ? '' : this.creationUserData.memo, text: !this.creationUserData.memo ? '' : this.creationUserData.memo,
value: !this.creationUserData.amount ? 0 : this.creationUserData.amount / 10000, value: !this.creationUserData.amount ? 0 : this.creationUserData.amount,
rangeMin: 0, rangeMin: 0,
rangeMax: 1000, rangeMax: 1000,
currentMonth: { currentMonth: {
@ -195,28 +200,12 @@ export default {
} }
}, },
submitCreation() { submitCreation() {
// Formular Prüfen ob ein Zeitraum ausgewählt wurde. Ansonsten abbrechen und Hinweis anzeigen
if (this.radioSelected === '') {
return alert('Bitte wähle einen Zeitraum!')
}
// Formular Prüfen ob der GDD Betrag grösser 0 ist. Ansonsten abbrechen und Hinweis anzeigen
if (this.value === 0) {
return alert('Bitte gib einen GDD Betrag an!')
}
// Formular Prüfen ob der Text vorhanden ist. Ansonsten abbrechen und Hinweis anzeigen
if (this.text === '') {
return alert('Bitte gib einen Text ein!')
}
// Formular Prüfen ob der Text länger als 10 Zeichen hat. Ansonsten abbrechen und Hinweis anzeigen
if (this.text.length < 10) {
return alert('Bitte gib einen Text ein der länger als 10 Zeichen ist!')
}
if (this.type === 'massCreation') { if (this.type === 'massCreation') {
// Die anzahl der Mitglieder aus der Mehrfachschöpfung // Die anzahl der Mitglieder aus der Mehrfachschöpfung
const i = Object.keys(this.itemsMassCreation).length const i = Object.keys(this.itemsMassCreation).length
// hinweis das eine Mehrfachschöpfung ausgeführt wird an (Anzahl der MItgleider an die geschöpft wird) // hinweis das eine Mehrfachschöpfung ausgeführt wird an (Anzahl der MItgleider an die geschöpft wird)
alert('SUBMIT CREATION => ' + this.type + ' >> für VIELE ' + i + ' Mitglieder') // eslint-disable-next-line no-console
console.log('SUBMIT CREATION => ' + this.type + ' >> für VIELE ' + i + ' Mitglieder')
this.submitObj = [ this.submitObj = [
{ {
item: this.itemsMassCreation, item: this.itemsMassCreation,
@ -227,7 +216,8 @@ export default {
moderator: this.$store.state.moderator.id, moderator: this.$store.state.moderator.id,
}, },
] ]
alert('MehrfachSCHÖPFUNG ABSENDEN FÜR >> ' + i + ' Mitglieder') // eslint-disable-next-line no-console
console.log('MehrfachSCHÖPFUNG ABSENDEN FÜR >> ' + i + ' Mitglieder')
// $store - offene Schöpfungen hochzählen // $store - offene Schöpfungen hochzählen
this.$store.commit('openCreationsPlus', i) this.$store.commit('openCreationsPlus', i)

View File

@ -15,6 +15,7 @@ const apolloMutateMock = jest.fn().mockResolvedValue({
}) })
const stateCommitMock = jest.fn() const stateCommitMock = jest.fn()
const toastedErrorMock = jest.fn()
const mocks = { const mocks = {
$moment: jest.fn(() => { $moment: jest.fn(() => {
@ -31,14 +32,21 @@ const mocks = {
mutate: apolloMutateMock, mutate: apolloMutateMock,
}, },
$store: { $store: {
state: {
moderator: {
id: 0,
name: 'test moderator',
},
},
commit: stateCommitMock, commit: stateCommitMock,
}, },
$toasted: {
error: toastedErrorMock,
},
} }
const propsData = { const propsData = {
type: '', type: '',
item: {},
row: [],
creation: [], creation: [],
itemsMassCreation: {}, itemsMassCreation: {},
} }
@ -69,6 +77,8 @@ describe('EditCreationFormular', () => {
jest.clearAllMocks() jest.clearAllMocks()
await wrapper.setProps({ type: 'singleCreation', creation: [200, 400, 600] }) await wrapper.setProps({ type: 'singleCreation', creation: [200, 400, 600] })
await wrapper.setData({ rangeMin: 180 }) await wrapper.setData({ rangeMin: 180 })
await wrapper.setData({ text: 'Test create coins' })
await wrapper.setData({ value: 90 })
}) })
describe('first radio button', () => { describe('first radio button', () => {
@ -83,6 +93,27 @@ describe('EditCreationFormular', () => {
it('sets rangeMax to 200', () => { it('sets rangeMax to 200', () => {
expect(wrapper.vm.rangeMax).toBe(200) expect(wrapper.vm.rangeMax).toBe(200)
}) })
describe('sendForm', () => {
beforeEach(async () => {
await wrapper.find('.test-submit').trigger('click')
})
it('sends ... to apollo', () => {
expect(apolloMutateMock).toBeCalledWith(
expect.objectContaining({
variables: {
amount: 90,
creationDate: 'YYYY-MM-01',
email: undefined,
id: undefined,
memo: 'Test create coins',
moderator: 0,
},
}),
)
})
})
}) })
describe('second radio button', () => { describe('second radio button', () => {
@ -97,6 +128,27 @@ describe('EditCreationFormular', () => {
it('sets rangeMax to 400', () => { it('sets rangeMax to 400', () => {
expect(wrapper.vm.rangeMax).toBe(400) expect(wrapper.vm.rangeMax).toBe(400)
}) })
describe('sendForm', () => {
beforeEach(async () => {
await wrapper.find('.test-submit').trigger('click')
})
it('sends ... to apollo', () => {
expect(apolloMutateMock).toBeCalledWith(
expect.objectContaining({
variables: {
amount: 90,
creationDate: 'YYYY-MM-01',
email: undefined,
id: undefined,
memo: 'Test create coins',
moderator: 0,
},
}),
)
})
})
}) })
describe('third radio button', () => { describe('third radio button', () => {
@ -111,6 +163,27 @@ describe('EditCreationFormular', () => {
it('sets rangeMax to 400', () => { it('sets rangeMax to 400', () => {
expect(wrapper.vm.rangeMax).toBe(600) expect(wrapper.vm.rangeMax).toBe(600)
}) })
describe('sendForm', () => {
beforeEach(async () => {
await wrapper.find('.test-submit').trigger('click')
})
it('sends ... to apollo', () => {
expect(apolloMutateMock).toBeCalledWith(
expect.objectContaining({
variables: {
amount: 90,
creationDate: 'YYYY-MM-DD',
email: undefined,
id: undefined,
memo: 'Test create coins',
moderator: 0,
},
}),
)
})
})
}) })
}) })
}) })

View File

@ -6,6 +6,7 @@
<label>Monat Auswählen</label> <label>Monat Auswählen</label>
<b-col class="text-left"> <b-col class="text-left">
<b-form-radio <b-form-radio
id="beforeLastMonth"
v-model="radioSelected" v-model="radioSelected"
:value="beforeLastMonth" :value="beforeLastMonth"
:disabled="selectedOpenCreationAmount[0] === 0" :disabled="selectedOpenCreationAmount[0] === 0"
@ -24,6 +25,7 @@
</b-col> </b-col>
<b-col> <b-col>
<b-form-radio <b-form-radio
id="lastMonth"
v-model="radioSelected" v-model="radioSelected"
:value="lastMonth" :value="lastMonth"
:disabled="selectedOpenCreationAmount[1] === 0" :disabled="selectedOpenCreationAmount[1] === 0"
@ -42,6 +44,7 @@
</b-col> </b-col>
<b-col class="text-right"> <b-col class="text-right">
<b-form-radio <b-form-radio
id="currentMonth"
v-model="radioSelected" v-model="radioSelected"
:value="currentMonth" :value="currentMonth"
:disabled="selectedOpenCreationAmount[2] === 0" :disabled="selectedOpenCreationAmount[2] === 0"
@ -106,6 +109,7 @@
<b-button <b-button
type="button" type="button"
variant="success" variant="success"
class="test-submit"
@click="submitCreation" @click="submitCreation"
:disabled="radioSelected === '' || value <= 0 || text.length < 10" :disabled="radioSelected === '' || value <= 0 || text.length < 10"
> >
@ -147,10 +151,10 @@ export default {
}, },
}, },
row: { row: {
type: Array, type: Object,
required: Object, required: false,
default() { default() {
return [] return {}
}, },
}, },
creationUserData: { creationUserData: {
@ -165,34 +169,11 @@ export default {
required: true, required: true,
}, },
}, },
created() {
if (this.pagetype === 'PageCreationConfirm' && this.creationUserData.date) {
switch (this.$moment(this.creationUserData.date).format('MMMM')) {
case this.currentMonth.short:
this.createdIndex = 2
this.radioSelected = this.currentMonth
break
case this.lastMonth.short:
this.createdIndex = 1
this.radioSelected = this.lastMonth
break
case this.beforeLastMonth.short:
this.createdIndex = 0
this.radioSelected = this.beforeLastMonth
break
default:
throw new Error('Something went wrong')
}
this.selectedOpenCreationAmount[this.createdIndex] =
this.creation[this.createdIndex] + this.creationUserData.amount / 10000
this.rangeMax = this.selectedOpenCreationAmount[this.createdIndex]
}
},
data() { data() {
return { return {
radioSelected: '', radioSelected: '',
text: !this.creationUserData.memo ? '' : this.creationUserData.memo, text: !this.creationUserData.memo ? '' : this.creationUserData.memo,
value: !this.creationUserData.amount ? 0 : this.creationUserData.amount / 10000, value: !this.creationUserData.amount ? 0 : this.creationUserData.amount,
rangeMin: 0, rangeMin: 0,
rangeMax: 1000, rangeMax: 1000,
currentMonth: { currentMonth: {
@ -221,22 +202,6 @@ export default {
this.rangeMax = this.creation[index] this.rangeMax = this.creation[index]
}, },
submitCreation() { submitCreation() {
// Formular Prüfen ob ein Zeitraum ausgewählt wurde. Ansonsten abbrechen und Hinweis anzeigen
if (this.radioSelected === '') {
return alert('Bitte wähle einen Zeitraum!')
}
// Formular Prüfen ob der GDD Betrag grösser 0 ist. Ansonsten abbrechen und Hinweis anzeigen
if (this.value <= 0) {
return alert('Bitte gib einen GDD Betrag an!')
}
// Formular Prüfen ob der Text vorhanden ist. Ansonsten abbrechen und Hinweis anzeigen
if (this.text === '') {
return alert('Bitte gib einen Text ein!')
}
// Formular Prüfen ob der Text länger als 10 Zeichen hat. Ansonsten abbrechen und Hinweis anzeigen
if (this.text.length < 10) {
return alert('Bitte gib einen Text ein der länger als 10 Zeichen ist!')
}
this.submitObj = { this.submitObj = {
id: this.item.id, id: this.item.id,
email: this.item.email, email: this.item.email,
@ -281,5 +246,28 @@ export default {
}) })
}, },
}, },
created() {
if (this.pagetype === 'PageCreationConfirm' && this.creationUserData.date) {
switch (this.$moment(this.creationUserData.date).format('MMMM')) {
case this.currentMonth.short:
this.createdIndex = 2
this.radioSelected = this.currentMonth
break
case this.lastMonth.short:
this.createdIndex = 1
this.radioSelected = this.lastMonth
break
case this.beforeLastMonth.short:
this.createdIndex = 0
this.radioSelected = this.beforeLastMonth
break
default:
throw new Error('Something went wrong')
}
this.selectedOpenCreationAmount[this.createdIndex] =
this.creation[this.createdIndex] + this.creationUserData.amount
this.rangeMax = this.selectedOpenCreationAmount[this.createdIndex]
}
},
} }
</script> </script>

View File

@ -132,6 +132,7 @@
<script> <script>
import CreationFormular from '../components/CreationFormular.vue' import CreationFormular from '../components/CreationFormular.vue'
import EditCreationFormular from '../components/EditCreationFormular.vue' import EditCreationFormular from '../components/EditCreationFormular.vue'
import { confirmPendingCreation } from '../graphql/confirmPendingCreation'
export default { export default {
name: 'UserTable', name: 'UserTable',
@ -228,9 +229,19 @@ export default {
} }
}, },
bookmarkConfirm(item) { bookmarkConfirm(item) {
alert('die schöpfung bestätigen und abschließen') this.$apollo
alert(JSON.stringify(item)) .mutate({
this.$emit('remove-confirm-result', item, 'remove') mutation: confirmPendingCreation,
variables: {
id: item.id,
},
})
.then(() => {
this.$emit('remove-confirm-result', item, 'remove')
})
.catch((error) => {
this.$toasted.error(error.message)
})
}, },
editCreationUserTable(row, rowItem) { editCreationUserTable(row, rowItem) {
if (!row.detailsShowing) { if (!row.detailsShowing) {
@ -241,14 +252,6 @@ export default {
row.toggleDetails() row.toggleDetails()
}, },
updateCreationData(data) { updateCreationData(data) {
// console.log('updateCreationData this.creationUserData11=> ', this.creationUserData)
// console.log('updateCreationData data=> ', data)
// this.creationUserData = {
// ...this.creationUserData,
// ...data,
// }
// console.log('updateCreationData this.creationUserData22=> ', this.creationUserData)
this.creationUserData.amount = data.amount this.creationUserData.amount = data.amount
this.creationUserData.date = data.date this.creationUserData.date = data.date
this.creationUserData.memo = data.memo this.creationUserData.memo = data.memo

View File

@ -0,0 +1,7 @@
import gql from 'graphql-tag'
export const confirmPendingCreation = gql`
mutation ($id: Float!) {
confirmPendingCreation(id: $id)
}
`

View File

@ -1,7 +0,0 @@
import gql from 'graphql-tag'
export const countPendingCreations = gql`
query {
countPendingCreations
}
`

View File

@ -1,5 +1,5 @@
<template> <template>
<div> <div class="admin-overview">
<b-card <b-card
v-show="$store.state.openCreations > 0" v-show="$store.state.openCreations > 0"
border-variant="primary" border-variant="primary"

View File

@ -24,7 +24,7 @@ export class PendingCreation {
memo: string memo: string
@Field(() => Number) @Field(() => Number)
amount: BigInt amount: number
@Field(() => Number) @Field(() => Number)
moderator: number moderator: number

View File

@ -4,13 +4,18 @@ import { UserAdmin } from '../model/UserAdmin'
import { PendingCreation } from '../model/PendingCreation' import { PendingCreation } from '../model/PendingCreation'
import { UpdatePendingCreation } from '../model/UpdatePendingCreation' import { UpdatePendingCreation } from '../model/UpdatePendingCreation'
import { RIGHTS } from '../../auth/RIGHTS' import { RIGHTS } from '../../auth/RIGHTS'
import { TransactionRepository } from '../../typeorm/repository/Transaction'
import { TransactionCreationRepository } from '../../typeorm/repository/TransactionCreation' import { TransactionCreationRepository } from '../../typeorm/repository/TransactionCreation'
import { PendingCreationRepository } from '../../typeorm/repository/PendingCreation' import { PendingCreationRepository } from '../../typeorm/repository/PendingCreation'
import { UserRepository } from '../../typeorm/repository/User' import { UserRepository } from '../../typeorm/repository/User'
import CreatePendingCreationArgs from '../arg/CreatePendingCreationArgs' import CreatePendingCreationArgs from '../arg/CreatePendingCreationArgs'
import UpdatePendingCreationArgs from '../arg/UpdatePendingCreationArgs' import UpdatePendingCreationArgs from '../arg/UpdatePendingCreationArgs'
import moment from 'moment' import moment from 'moment'
import { LoginPendingTasksAdmin } from '@entity/LoginPendingTasksAdmin' import { Transaction } from '@entity/Transaction'
import { TransactionCreation } from '@entity/TransactionCreation'
import { UserTransaction } from '@entity/UserTransaction'
import { UserTransactionRepository } from '../../typeorm/repository/UserTransaction'
import { BalanceRepository } from '../../typeorm/repository/Balance'
@Resolver() @Resolver()
export class AdminResolver { export class AdminResolver {
@ -113,8 +118,11 @@ export class AdminResolver {
const userRepository = getCustomRepository(UserRepository) const userRepository = getCustomRepository(UserRepository)
const user = await userRepository.findOneOrFail({ id: pendingCreation.userId }) const user = await userRepository.findOneOrFail({ id: pendingCreation.userId })
const parsedAmount = Number(parseInt(pendingCreation.amount.toString()) / 10000)
// pendingCreation.amount = parsedAmount
const newPendingCreation = { const newPendingCreation = {
...pendingCreation, ...pendingCreation,
amount: parsedAmount,
firstName: user.firstName, firstName: user.firstName,
lastName: user.lastName, lastName: user.lastName,
email: user.email, email: user.email,
@ -134,6 +142,66 @@ export class AdminResolver {
const res = await pendingCreationRepository.delete(entity) const res = await pendingCreationRepository.delete(entity)
return !!res return !!res
} }
@Mutation(() => Boolean)
async confirmPendingCreation(@Arg('id') id: number): Promise<boolean> {
const pendingCreationRepository = getCustomRepository(PendingCreationRepository)
const pendingCreation = await pendingCreationRepository.findOneOrFail(id)
const transactionRepository = getCustomRepository(TransactionRepository)
let transaction = new Transaction()
transaction.transactionTypeId = 1
transaction.memo = pendingCreation.memo
transaction.received = new Date()
transaction.blockchainTypeId = 1
transaction = await transactionRepository.save(transaction)
if (!transaction) throw new Error('Could not create transaction')
const transactionCreationRepository = getCustomRepository(TransactionCreationRepository)
let transactionCreation = new TransactionCreation()
transactionCreation.transactionId = transaction.id
transactionCreation.userId = pendingCreation.userId
transactionCreation.amount = parseInt(pendingCreation.amount.toString())
transactionCreation.targetDate = pendingCreation.date
transactionCreation = await transactionCreationRepository.save(transactionCreation)
if (!transactionCreation) throw new Error('Could not create transactionCreation')
const userTransactionRepository = getCustomRepository(UserTransactionRepository)
const lastUserTransaction = await userTransactionRepository.findLastForUser(
pendingCreation.userId,
)
let newBalance = 0
if (!lastUserTransaction) {
newBalance = 0
} else {
newBalance = lastUserTransaction.balance
}
newBalance = Number(newBalance) + Number(parseInt(pendingCreation.amount.toString()) / 10000)
const newUserTransaction = new UserTransaction()
newUserTransaction.userId = pendingCreation.userId
newUserTransaction.transactionId = transaction.id
newUserTransaction.transactionTypeId = transaction.transactionTypeId
newUserTransaction.balance = Number(newBalance)
newUserTransaction.balanceDate = transaction.received
await userTransactionRepository.save(newUserTransaction).catch((error) => {
throw new Error('Error saving user transaction: ' + error)
})
const balanceRepository = getCustomRepository(BalanceRepository)
let userBalance = await balanceRepository.findByUser(pendingCreation.userId)
if (!userBalance) userBalance = balanceRepository.create()
userBalance.userId = pendingCreation.userId
userBalance.amount = Number(newBalance * 10000)
userBalance.modified = new Date()
userBalance.recordDate = userBalance.recordDate ? userBalance.recordDate : new Date()
await balanceRepository.save(userBalance)
await pendingCreationRepository.delete(pendingCreation)
return true
}
} }
async function getUserCreations(id: number): Promise<number[]> { async function getUserCreations(id: number): Promise<number[]> {

View File

@ -428,7 +428,7 @@ async function addUserTransaction(
if (lastUserTransaction) { if (lastUserTransaction) {
newBalance += Number( newBalance += Number(
await calculateDecay( await calculateDecay(
Number(lastUserTransaction.balance), Number(lastUserTransaction.balance * 10000),
lastUserTransaction.balanceDate, lastUserTransaction.balanceDate,
transaction.received, transaction.received,
).catch(() => { ).catch(() => {

View File

@ -39,6 +39,7 @@ yarn seed
## Seeded Users ## Seeded Users
| email | password | admin | | email | password | admin |
|------------------------|------------|---------|
| peter@lustig.de | `Aa12345_` | `true` | | peter@lustig.de | `Aa12345_` | `true` |
| bibi@bloxberg.de | `Aa12345_` | `false` | | bibi@bloxberg.de | `Aa12345_` | `false` |
| raeuber@hotzenplotz.de | `Aa12345_` | `false` | | raeuber@hotzenplotz.de | `Aa12345_` | `false` |

View File

@ -1,4 +1,5 @@
import { BaseEntity, Entity, PrimaryGeneratedColumn, Column } from 'typeorm' import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, JoinColumn, OneToOne } from 'typeorm'
import { User } from '../User'
@Entity('state_balances') @Entity('state_balances')
export class Balance extends BaseEntity { export class Balance extends BaseEntity {
@ -16,4 +17,8 @@ export class Balance extends BaseEntity {
@Column({ type: 'bigint' }) @Column({ type: 'bigint' })
amount: number amount: number
@OneToOne(() => User, { nullable: false })
@JoinColumn({ name: 'state_user_id' })
user: User
} }

View File

@ -1,12 +1,4 @@
import { import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, OneToOne, JoinColumn } from 'typeorm'
BaseEntity,
Entity,
PrimaryGeneratedColumn,
Column,
Timestamp,
OneToOne,
JoinColumn,
} from 'typeorm'
import { Transaction } from './Transaction' import { Transaction } from './Transaction'
@Entity('transaction_creations') @Entity('transaction_creations')
@ -24,7 +16,7 @@ export class TransactionCreation extends BaseEntity {
amount: number amount: number
@Column({ name: 'target_date', type: 'timestamp' }) @Column({ name: 'target_date', type: 'timestamp' })
targetDate: Timestamp targetDate: Date
@OneToOne(() => Transaction) @OneToOne(() => Transaction)
@JoinColumn({ name: 'transaction_id' }) @JoinColumn({ name: 'transaction_id' })

View File

@ -0,0 +1,21 @@
import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, ManyToOne, JoinColumn } from 'typeorm'
import { Transaction } from './Transaction'
@Entity('transaction_signatures')
export class TransactionSignature extends BaseEntity {
@PrimaryGeneratedColumn()
id: number
@Column({ name: 'transaction_id' })
transactionId: number
@Column({ type: 'binary', length: 64 })
signature: Buffer
@Column({ type: 'binary', length: 32 })
pubkey: Buffer
@ManyToOne(() => Transaction)
@JoinColumn({ name: 'transaction_id' })
transaction: Transaction
}

View File

@ -1,4 +1,5 @@
import { BaseEntity, Entity, PrimaryGeneratedColumn, Column } from 'typeorm' import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, OneToOne } from 'typeorm'
import { Balance } from '../Balance'
// Moriz: I do not like the idea of having two user tables // Moriz: I do not like the idea of having two user tables
@Entity('state_users') @Entity('state_users')
@ -29,4 +30,7 @@ export class User extends BaseEntity {
@Column() @Column()
disabled: boolean disabled: boolean
@OneToOne(() => Balance, (balance) => balance.user)
balance: Balance
} }

View File

@ -0,0 +1 @@
export { TransactionSignature } from './0001-init_db/TransactionSignature'

View File

@ -8,6 +8,7 @@ import { Migration } from './Migration'
import { ServerUser } from './ServerUser' import { ServerUser } from './ServerUser'
import { Transaction } from './Transaction' import { Transaction } from './Transaction'
import { TransactionCreation } from './TransactionCreation' import { TransactionCreation } from './TransactionCreation'
import { TransactionSignature } from './TransactionSignature'
import { TransactionSendCoin } from './TransactionSendCoin' import { TransactionSendCoin } from './TransactionSendCoin'
import { User } from './User' import { User } from './User'
import { UserSetting } from './UserSetting' import { UserSetting } from './UserSetting'
@ -25,6 +26,7 @@ export const entities = [
ServerUser, ServerUser,
Transaction, Transaction,
TransactionCreation, TransactionCreation,
TransactionSignature,
TransactionSendCoin, TransactionSendCoin,
User, User,
UserSetting, UserSetting,

View File

@ -14,7 +14,7 @@
export async function upgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) { export async function upgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
await queryFn(` await queryFn(`
CREATE TABLE \`user_setting\` ( CREATE TABLE IF NOT EXISTS \`user_setting\` (
\`id\` int(10) unsigned NOT NULL AUTO_INCREMENT, \`id\` int(10) unsigned NOT NULL AUTO_INCREMENT,
\`userId\` int(11) NOT NULL, \`userId\` int(11) NOT NULL,
\`key\` varchar(255) NOT NULL, \`key\` varchar(255) NOT NULL,
@ -25,5 +25,5 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis
export async function downgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) { export async function downgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
// write downgrade logic as parameter of queryFn // write downgrade logic as parameter of queryFn
await queryFn(`DROP TABLE \`user_setting\`;`) await queryFn(`DROP TABLE IF EXISTS \`user_setting\`;`)
} }

View File

@ -14,7 +14,7 @@
export async function upgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) { export async function upgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
await queryFn(` await queryFn(`
CREATE TABLE \`login_app_access_tokens\` ( CREATE TABLE IF NOT EXISTS \`login_app_access_tokens\` (
\`id\` int unsigned NOT NULL AUTO_INCREMENT, \`id\` int unsigned NOT NULL AUTO_INCREMENT,
\`user_id\` int NOT NULL, \`user_id\` int NOT NULL,
\`access_code\` bigint unsigned NOT NULL, \`access_code\` bigint unsigned NOT NULL,
@ -25,7 +25,7 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
`) `)
await queryFn(` await queryFn(`
CREATE TABLE \`login_elopage_buys\` ( CREATE TABLE IF NOT EXISTS \`login_elopage_buys\` (
\`id\` int unsigned NOT NULL AUTO_INCREMENT, \`id\` int unsigned NOT NULL AUTO_INCREMENT,
\`elopage_user_id\` int DEFAULT NULL, \`elopage_user_id\` int DEFAULT NULL,
\`affiliate_program_id\` int NOT NULL, \`affiliate_program_id\` int NOT NULL,
@ -42,7 +42,7 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
`) `)
await queryFn(` await queryFn(`
CREATE TABLE \`login_email_opt_in_types\` ( CREATE TABLE IF NOT EXISTS \`login_email_opt_in_types\` (
\`id\` int unsigned NOT NULL AUTO_INCREMENT, \`id\` int unsigned NOT NULL AUTO_INCREMENT,
\`name\` varchar(255) NOT NULL, \`name\` varchar(255) NOT NULL,
\`description\` varchar(255) NOT NULL, \`description\` varchar(255) NOT NULL,
@ -50,7 +50,7 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
`) `)
await queryFn(` await queryFn(`
CREATE TABLE \`login_email_opt_in\` ( CREATE TABLE IF NOT EXISTS \`login_email_opt_in\` (
\`id\` int unsigned NOT NULL AUTO_INCREMENT, \`id\` int unsigned NOT NULL AUTO_INCREMENT,
\`user_id\` int NOT NULL, \`user_id\` int NOT NULL,
\`verification_code\` bigint unsigned NOT NULL, \`verification_code\` bigint unsigned NOT NULL,
@ -63,7 +63,7 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
`) `)
await queryFn(` await queryFn(`
CREATE TABLE \`login_groups\` ( CREATE TABLE IF NOT EXISTS \`login_groups\` (
\`id\` int unsigned NOT NULL AUTO_INCREMENT, \`id\` int unsigned NOT NULL AUTO_INCREMENT,
\`alias\` varchar(190) NOT NULL, \`alias\` varchar(190) NOT NULL,
\`name\` varchar(255) NOT NULL, \`name\` varchar(255) NOT NULL,
@ -76,7 +76,7 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
`) `)
await queryFn(` await queryFn(`
CREATE TABLE \`login_pending_tasks\` ( CREATE TABLE IF NOT EXISTS \`login_pending_tasks\` (
\`id\` int UNSIGNED NOT NULL AUTO_INCREMENT, \`id\` int UNSIGNED NOT NULL AUTO_INCREMENT,
\`user_id\` int UNSIGNED DEFAULT 0, \`user_id\` int UNSIGNED DEFAULT 0,
\`request\` varbinary(2048) NOT NULL, \`request\` varbinary(2048) NOT NULL,
@ -91,7 +91,7 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis
) ENGINE = InnoDB DEFAULT CHARSET=utf8mb4; ) ENGINE = InnoDB DEFAULT CHARSET=utf8mb4;
`) `)
await queryFn(` await queryFn(`
CREATE TABLE \`login_roles\` ( CREATE TABLE IF NOT EXISTS \`login_roles\` (
\`id\` int unsigned NOT NULL AUTO_INCREMENT, \`id\` int unsigned NOT NULL AUTO_INCREMENT,
\`name\` varchar(255) NOT NULL, \`name\` varchar(255) NOT NULL,
\`description\` varchar(255) NOT NULL, \`description\` varchar(255) NOT NULL,
@ -100,7 +100,7 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
`) `)
await queryFn(` await queryFn(`
CREATE TABLE \`login_user_backups\` ( CREATE TABLE IF NOT EXISTS \`login_user_backups\` (
\`id\` int unsigned NOT NULL AUTO_INCREMENT, \`id\` int unsigned NOT NULL AUTO_INCREMENT,
\`user_id\` int NOT NULL, \`user_id\` int NOT NULL,
\`passphrase\` text NOT NULL, \`passphrase\` text NOT NULL,
@ -109,7 +109,7 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
`) `)
await queryFn(` await queryFn(`
CREATE TABLE \`login_user_roles\` ( CREATE TABLE IF NOT EXISTS \`login_user_roles\` (
\`id\` int unsigned NOT NULL AUTO_INCREMENT, \`id\` int unsigned NOT NULL AUTO_INCREMENT,
\`user_id\` int NOT NULL, \`user_id\` int NOT NULL,
\`role_id\` int NOT NULL, \`role_id\` int NOT NULL,
@ -117,7 +117,7 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
`) `)
await queryFn(` await queryFn(`
CREATE TABLE \`login_users\` ( CREATE TABLE IF NOT EXISTS \`login_users\` (
\`id\` int unsigned NOT NULL AUTO_INCREMENT, \`id\` int unsigned NOT NULL AUTO_INCREMENT,
\`email\` varchar(191) NOT NULL, \`email\` varchar(191) NOT NULL,
\`first_name\` varchar(150) NOT NULL, \`first_name\` varchar(150) NOT NULL,
@ -143,14 +143,14 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis
export async function downgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) { export async function downgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
// write downgrade logic as parameter of queryFn // write downgrade logic as parameter of queryFn
await queryFn(`DROP TABLE \`login_app_access_tokens\`;`) await queryFn(`DROP TABLE IF EXISTS \`login_app_access_tokens\`;`)
await queryFn(`DROP TABLE \`login_elopage_buys\`;`) await queryFn(`DROP TABLE IF EXISTS \`login_elopage_buys\`;`)
await queryFn(`DROP TABLE \`login_email_opt_in_types\`;`) await queryFn(`DROP TABLE IF EXISTS \`login_email_opt_in_types\`;`)
await queryFn(`DROP TABLE \`login_email_opt_in\`;`) await queryFn(`DROP TABLE IF EXISTS \`login_email_opt_in\`;`)
await queryFn(`DROP TABLE \`login_groups\`;`) await queryFn(`DROP TABLE IF EXISTS \`login_groups\`;`)
await queryFn(`DROP TABLE \`login_pending_tasks\`;`) await queryFn(`DROP TABLE IF EXISTS \`login_pending_tasks\`;`)
await queryFn(`DROP TABLE \`login_roles\`;`) await queryFn(`DROP TABLE IF EXISTS \`login_roles\`;`)
await queryFn(`DROP TABLE \`login_user_backups\`;`) await queryFn(`DROP TABLE IF EXISTS \`login_user_backups\`;`)
await queryFn(`DROP TABLE \`login_user_roles\`;`) await queryFn(`DROP TABLE IF EXISTS \`login_user_roles\`;`)
await queryFn(`DROP TABLE \`login_users\`;`) await queryFn(`DROP TABLE IF EXISTS \`login_users\`;`)
} }

View File

@ -63,15 +63,5 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis
} }
export async function downgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) { export async function downgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
// write downgrade logic as parameter of queryFn // TODO NO EMPTY FUNCTION
await queryFn(`DELETE FROM \`login_app_access_tokens\`;`)
await queryFn(`DELETE FROM \`login_elopage_buys\`;`)
await queryFn(`DELETE FROM \`login_email_opt_in_types\`;`)
await queryFn(`DELETE FROM \`login_email_opt_in\`;`)
await queryFn(`DELETE FROM \`login_groups\`;`)
await queryFn(`DELETE FROM \`login_pending_tasks\`;`)
await queryFn(`DELETE FROM \`login_roles\`;`)
await queryFn(`DELETE FROM \`login_user_backups\`;`)
await queryFn(`DELETE FROM \`login_user_roles\`;`)
await queryFn(`DELETE FROM \`login_users\`;`)
} }

View File

@ -11,7 +11,7 @@
export async function upgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) { export async function upgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
await queryFn(` await queryFn(`
CREATE TABLE \`login_pending_tasks_admin\` ( CREATE TABLE IF NOT EXISTS \`login_pending_tasks_admin\` (
\`id\` int UNSIGNED NOT NULL AUTO_INCREMENT, \`id\` int UNSIGNED NOT NULL AUTO_INCREMENT,
\`userId\` int UNSIGNED DEFAULT 0, \`userId\` int UNSIGNED DEFAULT 0,
\`created\` datetime NOT NULL, \`created\` datetime NOT NULL,
@ -25,5 +25,5 @@ export async function upgrade(queryFn: (query: string, values?: any[]) => Promis
} }
export async function downgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) { export async function downgrade(queryFn: (query: string, values?: any[]) => Promise<Array<any>>) {
await queryFn(`DROP TABLE \`login_pending_tasks_admin\`;`) await queryFn(`DROP TABLE IF EXISTS \`login_pending_tasks_admin\`;`)
} }

View File

@ -0,0 +1,18 @@
import Faker from 'faker'
import { define } from 'typeorm-seeding'
import { Balance } from '../../entity/Balance'
import { BalanceContext } from '../interface/TransactionContext'
define(Balance, (faker: typeof Faker, context?: BalanceContext) => {
if (!context || !context.user) {
throw new Error('Balance: No user present!')
}
const balance = new Balance()
balance.modified = context.modified ? context.modified : faker.date.recent()
balance.recordDate = context.recordDate ? context.recordDate : faker.date.recent()
balance.amount = context.amount ? context.amount : 10000000
balance.user = context.user
return balance
})

View File

@ -0,0 +1,18 @@
import Faker from 'faker'
import { define } from 'typeorm-seeding'
import { TransactionCreation } from '../../entity/TransactionCreation'
import { TransactionCreationContext } from '../interface/TransactionContext'
define(TransactionCreation, (faker: typeof Faker, context?: TransactionCreationContext) => {
if (!context || !context.userId || !context.transaction) {
throw new Error('TransactionCreation: No userId and/or transaction present!')
}
const transactionCreation = new TransactionCreation()
transactionCreation.userId = context.userId
transactionCreation.amount = context.amount ? context.amount : 100000
transactionCreation.targetDate = context.targetDate ? context.targetDate : new Date()
transactionCreation.transaction = context.transaction
return transactionCreation
})

View File

@ -0,0 +1,18 @@
import Faker from 'faker'
import { define } from 'typeorm-seeding'
import { TransactionSignature } from '../../entity/TransactionSignature'
import { TransactionSignatureContext } from '../interface/TransactionContext'
import { randomBytes } from 'crypto'
define(TransactionSignature, (faker: typeof Faker, context?: TransactionSignatureContext) => {
if (!context || !context.transaction) {
throw new Error('TransactionSignature: No transaction present!')
}
const transactionSignature = new TransactionSignature()
transactionSignature.signature = context.signature ? context.signature : randomBytes(64)
transactionSignature.pubkey = context.pubkey ? context.pubkey : randomBytes(32)
transactionSignature.transaction = context.transaction
return transactionSignature
})

View File

@ -0,0 +1,20 @@
import Faker from 'faker'
import { define } from 'typeorm-seeding'
import { Transaction } from '../../entity/Transaction'
import { TransactionContext } from '../interface/TransactionContext'
import { randomBytes } from 'crypto'
define(Transaction, (faker: typeof Faker, context?: TransactionContext) => {
if (!context) context = {}
const transaction = new Transaction()
transaction.transactionTypeId = context.transactionTypeId ? context.transactionTypeId : 2
transaction.txHash = context.txHash ? context.txHash : randomBytes(48)
transaction.memo = context.memo || context.memo === '' ? context.memo : faker.lorem.sentence()
transaction.received = context.received ? context.received : new Date()
transaction.blockchainTypeId = context.blockchainTypeId ? context.blockchainTypeId : 1
if (context.transactionSendCoin) transaction.transactionSendCoin = context.transactionSendCoin
if (context.transactionCreation) transaction.transactionCreation = context.transactionCreation
return transaction
})

View File

@ -0,0 +1,19 @@
import Faker from 'faker'
import { define } from 'typeorm-seeding'
import { UserTransaction } from '../../entity/UserTransaction'
import { UserTransactionContext } from '../interface/TransactionContext'
define(UserTransaction, (faker: typeof Faker, context?: UserTransactionContext) => {
if (!context || !context.userId || !context.transactionId) {
throw new Error('UserTransaction: No userId and/or transactionId present!')
}
const userTransaction = new UserTransaction()
userTransaction.userId = context.userId
userTransaction.transactionId = context.transactionId
userTransaction.transactionTypeId = context.transactionTypeId ? context.transactionTypeId : 1
userTransaction.balance = context.balance ? context.balance : 100000
userTransaction.balanceDate = context.balanceDate ? context.balanceDate : new Date()
return userTransaction
})

View File

@ -9,6 +9,7 @@ import { CreatePeterLustigSeed } from './seeds/users/peter-lustig.admin.seed'
import { CreateBibiBloxbergSeed } from './seeds/users/bibi-bloxberg.seed' import { CreateBibiBloxbergSeed } from './seeds/users/bibi-bloxberg.seed'
import { CreateRaeuberHotzenplotzSeed } from './seeds/users/raeuber-hotzenplotz.seed' import { CreateRaeuberHotzenplotzSeed } from './seeds/users/raeuber-hotzenplotz.seed'
import { CreateBobBaumeisterSeed } from './seeds/users/bob-baumeister.seed' import { CreateBobBaumeisterSeed } from './seeds/users/bob-baumeister.seed'
import { DecayStartBlockSeed } from './seeds/decay-start-block.seed'
const run = async (command: string) => { const run = async (command: string) => {
// Database actions not supported by our migration library // Database actions not supported by our migration library
@ -59,6 +60,7 @@ const run = async (command: string) => {
root: process.cwd(), root: process.cwd(),
configName: 'ormconfig.js', configName: 'ormconfig.js',
}) })
await runSeeder(DecayStartBlockSeed)
await runSeeder(CreatePeterLustigSeed) await runSeeder(CreatePeterLustigSeed)
await runSeeder(CreateBibiBloxbergSeed) await runSeeder(CreateBibiBloxbergSeed)
await runSeeder(CreateRaeuberHotzenplotzSeed) await runSeeder(CreateRaeuberHotzenplotzSeed)

View File

@ -0,0 +1,52 @@
import { Transaction } from '../../entity/Transaction'
import { TransactionSendCoin } from '../../entity/TransactionSendCoin'
import { TransactionCreation } from '../../entity/TransactionCreation'
import { User } from '../../entity/User'
export interface TransactionContext {
transactionTypeId?: number
txHash?: Buffer
memo?: string
received?: Date
blockchainTypeId?: number
transactionSendCoin?: TransactionSendCoin
transactionCreation?: TransactionCreation
}
export interface BalanceContext {
modified?: Date
recordDate?: Date
amount?: number
user?: User
}
export interface TransactionSendCoinContext {
senderPublic?: Buffer
userId?: number
recipiantPublic?: Buffer
recipiantUserId?: number
amount?: number
senderFinalBalance?: number
transaction?: Transaction
}
export interface TransactionCreationContext {
userId?: number
amount?: number
targetDate?: Date
transaction?: Transaction
}
export interface UserTransactionContext {
userId?: number
transactionId?: number
transactionTypeId?: number
balance?: number
balanceDate?: Date
}
export interface TransactionSignatureContext {
signature?: Buffer
pubkey?: Buffer
transaction?: Transaction
}

View File

@ -27,4 +27,14 @@ export interface UserInterface {
modified?: Date modified?: Date
// flag for admin // flag for admin
isAdmin?: boolean isAdmin?: boolean
// flag for balance (creation of 1000 GDD)
addBalance?: boolean
// balance
balanceModified?: Date
recordDate?: Date
targetDate?: Date
amount?: number
creationTxHash?: Buffer
signature?: Buffer
signaturePubkey?: Buffer
} }

View File

@ -0,0 +1,17 @@
import { Factory, Seeder } from 'typeorm-seeding'
import { Transaction } from '../../entity/Transaction'
export class DecayStartBlockSeed implements Seeder {
public async run(factory: Factory): Promise<void> {
await factory(Transaction)({
transactionTypeId: 9,
txHash: Buffer.from(
'9c9c4152b8a4cfbac287eee18d2d262e9de756fae726fc0ca36b788564973fff00000000000000000000000000000000',
'hex',
),
memo: '',
received: new Date('2021-11-30T09:13:26'),
blockchainTypeId: 1,
}).create()
}
}

View File

@ -5,16 +5,28 @@ import {
ServerUserContext, ServerUserContext,
LoginUserRolesContext, LoginUserRolesContext,
} from '../../interface/UserContext' } from '../../interface/UserContext'
import {
BalanceContext,
TransactionContext,
TransactionCreationContext,
UserTransactionContext,
TransactionSignatureContext,
} from '../../interface/TransactionContext'
import { UserInterface } from '../../interface/UserInterface' import { UserInterface } from '../../interface/UserInterface'
import { User } from '../../../entity/User' import { User } from '../../../entity/User'
import { LoginUser } from '../../../entity/LoginUser' import { LoginUser } from '../../../entity/LoginUser'
import { LoginUserBackup } from '../../../entity/LoginUserBackup' import { LoginUserBackup } from '../../../entity/LoginUserBackup'
import { ServerUser } from '../../../entity/ServerUser' import { ServerUser } from '../../../entity/ServerUser'
import { LoginUserRoles } from '../../../entity/LoginUserRoles' import { LoginUserRoles } from '../../../entity/LoginUserRoles'
import { Balance } from '../../../entity/Balance'
import { Transaction } from '../../../entity/Transaction'
import { TransactionSignature } from '../../../entity/TransactionSignature'
import { UserTransaction } from '../../../entity/UserTransaction'
import { TransactionCreation } from '../../../entity/TransactionCreation'
import { Factory } from 'typeorm-seeding' import { Factory } from 'typeorm-seeding'
export const userSeeder = async (factory: Factory, userData: UserInterface): Promise<void> => { export const userSeeder = async (factory: Factory, userData: UserInterface): Promise<void> => {
await factory(User)(createUserContext(userData)).create() const user = await factory(User)(createUserContext(userData)).create()
const loginUser = await factory(LoginUser)(createLoginUserContext(userData)).create() const loginUser = await factory(LoginUser)(createLoginUserContext(userData)).create()
await factory(LoginUserBackup)(createLoginUserBackupContext(userData, loginUser)).create() await factory(LoginUserBackup)(createLoginUserBackupContext(userData, loginUser)).create()
@ -25,9 +37,26 @@ export const userSeeder = async (factory: Factory, userData: UserInterface): Pro
// It works with LoginRoles empty!! // It works with LoginRoles empty!!
await factory(LoginUserRoles)(createLoginUserRolesContext(loginUser)).create() await factory(LoginUserRoles)(createLoginUserRolesContext(loginUser)).create()
} }
if (userData.addBalance) {
// create some GDD for the user
await factory(Balance)(createBalanceContext(userData, user)).create()
const transaction = await factory(Transaction)(
createTransactionContext(userData, 1, 'Herzlich Willkommen bei Gradido!'),
).create()
await factory(TransactionCreation)(
createTransactionCreationContext(userData, user, transaction),
).create()
await factory(UserTransaction)(
createUserTransactionContext(userData, user, transaction),
).create()
await factory(TransactionSignature)(
createTransactionSignatureContext(userData, transaction),
).create()
}
} }
export const createUserContext = (context: UserInterface): UserContext => { const createUserContext = (context: UserInterface): UserContext => {
return { return {
pubkey: context.pubKey, pubkey: context.pubKey,
email: context.email, email: context.email,
@ -38,7 +67,7 @@ export const createUserContext = (context: UserInterface): UserContext => {
} }
} }
export const createLoginUserContext = (context: UserInterface): LoginUserContext => { const createLoginUserContext = (context: UserInterface): LoginUserContext => {
return { return {
email: context.email, email: context.email,
firstName: context.firstName, firstName: context.firstName,
@ -59,7 +88,7 @@ export const createLoginUserContext = (context: UserInterface): LoginUserContext
} }
} }
export const createLoginUserBackupContext = ( const createLoginUserBackupContext = (
context: UserInterface, context: UserInterface,
loginUser: LoginUser, loginUser: LoginUser,
): LoginUserBackupContext => { ): LoginUserBackupContext => {
@ -70,7 +99,7 @@ export const createLoginUserBackupContext = (
} }
} }
export const createServerUserContext = (context: UserInterface): ServerUserContext => { const createServerUserContext = (context: UserInterface): ServerUserContext => {
return { return {
role: context.role, role: context.role,
username: context.username, username: context.username,
@ -83,9 +112,69 @@ export const createServerUserContext = (context: UserInterface): ServerUserConte
} }
} }
export const createLoginUserRolesContext = (loginUser: LoginUser): LoginUserRolesContext => { const createLoginUserRolesContext = (loginUser: LoginUser): LoginUserRolesContext => {
return { return {
userId: loginUser.id, userId: loginUser.id,
roleId: 1, roleId: 1,
} }
} }
const createBalanceContext = (context: UserInterface, user: User): BalanceContext => {
return {
modified: context.balanceModified,
recordDate: context.recordDate,
amount: context.amount,
user,
}
}
const createTransactionContext = (
context: UserInterface,
type: number,
memo: string,
): TransactionContext => {
return {
transactionTypeId: type,
txHash: context.creationTxHash,
memo,
received: context.recordDate,
}
}
const createTransactionCreationContext = (
context: UserInterface,
user: User,
transaction: Transaction,
): TransactionCreationContext => {
return {
userId: user.id,
amount: context.amount,
targetDate: context.targetDate,
transaction,
}
}
const createUserTransactionContext = (
context: UserInterface,
user: User,
transaction: Transaction,
): UserTransactionContext => {
return {
userId: user.id,
transactionId: transaction.id,
transactionTypeId: transaction.transactionTypeId,
balance: context.amount,
balanceDate: context.recordDate,
}
}
const createTransactionSignatureContext = (
context: UserInterface,
transaction: Transaction,
): TransactionSignatureContext => {
return {
signature: context.signature,
pubkey: context.signaturePubkey,
transaction,
}
}

View File

@ -22,4 +22,21 @@ export const bibiBloxberg = {
'knife normal level all hurdle crucial color avoid warrior stadium road bachelor affair topple hawk pottery right afford immune two ceiling budget glance hour ', 'knife normal level all hurdle crucial color avoid warrior stadium road bachelor affair topple hawk pottery right afford immune two ceiling budget glance hour ',
mnemonicType: 2, mnemonicType: 2,
isAdmin: false, isAdmin: false,
addBalance: true,
balanceModified: new Date('2021-11-30T10:37:11'),
recordDate: new Date('2021-11-30T10:37:11'),
targetDate: new Date('2021-08-01 00:00:00'),
amount: 10000000,
creationTxHash: Buffer.from(
'51103dc0fc2ca5d5d75a9557a1e899304e5406cfdb1328d8df6414d527b0118100000000000000000000000000000000',
'hex',
),
signature: Buffer.from(
'2a2c71f3e41adc060bbc3086577e2d57d24eeeb0a7727339c3f85aad813808f601d7e1df56a26e0929d2e67fc054fca429ccfa283ed2782185c7f009fe008f0c',
'hex',
),
signaturePubkey: Buffer.from(
'7281e0ee3258b08801f3ec73e431b4519677f65c03b0382c63a913b5784ee770',
'hex',
),
} }

View File

@ -22,4 +22,21 @@ export const bobBaumeister = {
'detail master source effort unable waste tilt flush domain orchard art truck hint barrel response gate impose peanut secret merry three uncle wink resource ', 'detail master source effort unable waste tilt flush domain orchard art truck hint barrel response gate impose peanut secret merry three uncle wink resource ',
mnemonicType: 2, mnemonicType: 2,
isAdmin: false, isAdmin: false,
addBalance: true,
balanceModified: new Date('2021-11-30T10:37:14'),
recordDate: new Date('2021-11-30T10:37:14'),
targetDate: new Date('2021-08-01 00:00:00'),
amount: 10000000,
creationTxHash: Buffer.from(
'be095dc87acb94987e71168fee8ecbf50ecb43a180b1006e75d573b35725c69c00000000000000000000000000000000',
'hex',
),
signature: Buffer.from(
'1fbd6b9a3d359923b2501557f3bc79fa7e428127c8090fb16bc490b4d87870ab142b3817ddd902d22f0b26472a483233784a0e460c0622661752a13978903905',
'hex',
),
signaturePubkey: Buffer.from(
'7281e0ee3258b08801f3ec73e431b4519677f65c03b0382c63a913b5784ee770',
'hex',
),
} }

View File

@ -22,4 +22,21 @@ export const raeuberHotzenplotz = {
'gospel trip tenant mouse spider skill auto curious man video chief response same little over expire drum display fancy clinic keen throw urge basket ', 'gospel trip tenant mouse spider skill auto curious man video chief response same little over expire drum display fancy clinic keen throw urge basket ',
mnemonicType: 2, mnemonicType: 2,
isAdmin: false, isAdmin: false,
addBalance: true,
balanceModified: new Date('2021-11-30T10:37:13'),
recordDate: new Date('2021-11-30T10:37:13'),
targetDate: new Date('2021-08-01 00:00:00'),
amount: 10000000,
creationTxHash: Buffer.from(
'23ba44fd84deb59b9f32969ad0cb18bfa4588be1bdb99c396888506474c16c1900000000000000000000000000000000',
'hex',
),
signature: Buffer.from(
'756d3da061687c575d1dbc5073908f646aa5f498b0927b217c83b48af471450e571dfe8421fb8e1f1ebd1104526b7e7c6fa78684e2da59c8f7f5a8dc3d9e5b0b',
'hex',
),
signaturePubkey: Buffer.from(
'7281e0ee3258b08801f3ec73e431b4519677f65c03b0382c63a913b5784ee770',
'hex',
),
} }

View File

@ -23,6 +23,7 @@
variant="outline-light" variant="outline-light"
@click="toggleShowPassword" @click="toggleShowPassword"
class="border-left-0 rounded-right" class="border-left-0 rounded-right"
tabindex="-1"
> >
<b-icon :icon="showPassword ? 'eye' : 'eye-slash'" /> <b-icon :icon="showPassword ? 'eye' : 'eye-slash'" />
</b-button> </b-button>