mirror of
https://github.com/IT4Change/gradido.git
synced 2026-01-20 20:01:31 +00:00
Merge branch 'master' into 2343-feature-gradido-is-free-worldwide-on-startpage-slider
This commit is contained in:
commit
26284aaef8
@ -20,10 +20,10 @@ ENV PORT="8080"
|
||||
# Labels
|
||||
LABEL org.label-schema.build-date="${BUILD_DATE}"
|
||||
LABEL org.label-schema.name="gradido:admin"
|
||||
LABEL org.label-schema.description="Gradido Vue Admin Interface"
|
||||
LABEL org.label-schema.usage="https://github.com/gradido/gradido/admin/README.md"
|
||||
LABEL org.label-schema.description="Gradido Admin Interface"
|
||||
LABEL org.label-schema.usage="https://github.com/gradido/gradido/blob/master/README.md"
|
||||
LABEL org.label-schema.url="https://gradido.net"
|
||||
LABEL org.label-schema.vcs-url="https://github.com/gradido/gradido/backend"
|
||||
LABEL org.label-schema.vcs-url="https://github.com/gradido/gradido/tree/master/admin"
|
||||
LABEL org.label-schema.vcs-ref="${BUILD_COMMIT}"
|
||||
LABEL org.label-schema.vendor="gradido Community"
|
||||
LABEL org.label-schema.version="${BUILD_VERSION}"
|
||||
|
||||
@ -53,6 +53,7 @@
|
||||
"vuex-persistedstate": "^4.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@apollo/client": "^3.7.1",
|
||||
"@babel/eslint-parser": "^7.15.8",
|
||||
"@intlify/eslint-plugin-vue-i18n": "^1.4.0",
|
||||
"@vue/cli-plugin-babel": "~4.5.0",
|
||||
@ -71,6 +72,7 @@
|
||||
"eslint-plugin-prettier": "3.3.1",
|
||||
"eslint-plugin-promise": "^5.1.1",
|
||||
"eslint-plugin-vue": "^7.20.0",
|
||||
"mock-apollo-client": "^1.2.1",
|
||||
"postcss": "^8.4.8",
|
||||
"postcss-html": "^1.3.0",
|
||||
"postcss-scss": "^4.0.3",
|
||||
|
||||
@ -46,5 +46,10 @@ describe('ContributionLink', () => {
|
||||
wrapper.vm.editContributionLinkData()
|
||||
expect(wrapper.vm.$root.$emit('bv::toggle::collapse', 'newContribution')).toBeTruthy()
|
||||
})
|
||||
|
||||
it('emits toggle::collapse close Contribution-Form ', async () => {
|
||||
wrapper.vm.closeContributionForm()
|
||||
expect(wrapper.vm.$root.$emit('bv::toggle::collapse', 'newContribution')).toBeTruthy()
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -8,7 +8,11 @@
|
||||
header-class="text-center"
|
||||
class="mt-5"
|
||||
>
|
||||
<b-button v-b-toggle.newContribution class="my-3 d-flex justify-content-left">
|
||||
<b-button
|
||||
v-if="!editContributionLink"
|
||||
v-b-toggle.newContribution
|
||||
class="my-3 d-flex justify-content-left"
|
||||
>
|
||||
{{ $t('math.plus') }} {{ $t('contributionLink.newContributionLink') }}
|
||||
</b-button>
|
||||
|
||||
@ -17,7 +21,9 @@
|
||||
<p class="h2 ml-5">{{ $t('contributionLink.contributionLinks') }}</p>
|
||||
<contribution-link-form
|
||||
:contributionLinkData="contributionLinkData"
|
||||
:editContributionLink="editContributionLink"
|
||||
@get-contribution-links="$emit('get-contribution-links')"
|
||||
@closeContributionForm="closeContributionForm"
|
||||
/>
|
||||
</b-card>
|
||||
</b-collapse>
|
||||
@ -58,12 +64,23 @@ export default {
|
||||
return {
|
||||
visible: false,
|
||||
contributionLinkData: {},
|
||||
editContributionLink: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
closeContributionForm() {
|
||||
if (this.visible) {
|
||||
this.$root.$emit('bv::toggle::collapse', 'newContribution')
|
||||
this.editContributionLink = false
|
||||
this.contributionLinkData = {}
|
||||
}
|
||||
},
|
||||
editContributionLinkData(data) {
|
||||
if (!this.visible) this.$root.$emit('bv::toggle::collapse', 'newContribution')
|
||||
if (!this.visible) {
|
||||
this.$root.$emit('bv::toggle::collapse', 'newContribution')
|
||||
}
|
||||
this.contributionLinkData = data
|
||||
this.editContributionLink = true
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -9,6 +9,7 @@ global.alert = jest.fn()
|
||||
|
||||
const propsData = {
|
||||
contributionLinkData: {},
|
||||
editContributionLink: false,
|
||||
}
|
||||
const apolloMutateMock = jest.fn().mockResolvedValue()
|
||||
|
||||
@ -108,6 +109,7 @@ describe('ContributionLinkForm', () => {
|
||||
cycle: 'ONCE',
|
||||
maxPerCycle: 1,
|
||||
maxAmountPerMonth: '0',
|
||||
id: null,
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
<b-col>
|
||||
<b-form-group :label="$t('contributionLink.validFrom')">
|
||||
<b-form-datepicker
|
||||
reset-button
|
||||
v-model="form.validFrom"
|
||||
size="lg"
|
||||
:min="min"
|
||||
@ -19,6 +20,7 @@
|
||||
<b-col>
|
||||
<b-form-group :label="$t('contributionLink.validTo')">
|
||||
<b-form-datepicker
|
||||
reset-button
|
||||
v-model="form.validTo"
|
||||
size="lg"
|
||||
:min="form.validFrom ? form.validFrom : min"
|
||||
@ -102,16 +104,25 @@
|
||||
</b-form-group>
|
||||
-->
|
||||
<div class="mt-6">
|
||||
<b-button type="submit" variant="primary">{{ $t('contributionLink.create') }}</b-button>
|
||||
<b-button type="submit" variant="primary">
|
||||
{{
|
||||
editContributionLink ? $t('contributionLink.saveChange') : $t('contributionLink.create')
|
||||
}}
|
||||
</b-button>
|
||||
<b-button type="reset" variant="danger" @click.prevent="onReset">
|
||||
{{ $t('contributionLink.clear') }}
|
||||
</b-button>
|
||||
<b-button @click.prevent="$emit('closeContributionForm')">
|
||||
{{ $t('contributionLink.close') }}
|
||||
</b-button>
|
||||
</div>
|
||||
</b-form>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { createContributionLink } from '@/graphql/createContributionLink.js'
|
||||
import { updateContributionLink } from '@/graphql/updateContributionLink.js'
|
||||
|
||||
export default {
|
||||
name: 'ContributionLinkForm',
|
||||
props: {
|
||||
@ -121,6 +132,7 @@ export default {
|
||||
return {}
|
||||
},
|
||||
},
|
||||
editContributionLink: { type: Boolean, required: true },
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
@ -157,23 +169,24 @@ export default {
|
||||
if (this.form.validFrom === null)
|
||||
return this.toastError(this.$t('contributionLink.noStartDate'))
|
||||
if (this.form.validTo === null) return this.toastError(this.$t('contributionLink.noEndDate'))
|
||||
|
||||
const variables = {
|
||||
...this.form,
|
||||
id: this.contributionLinkData.id ? this.contributionLinkData.id : null,
|
||||
}
|
||||
|
||||
this.$apollo
|
||||
.mutate({
|
||||
mutation: createContributionLink,
|
||||
variables: {
|
||||
validFrom: this.form.validFrom,
|
||||
validTo: this.form.validTo,
|
||||
name: this.form.name,
|
||||
amount: this.form.amount,
|
||||
memo: this.form.memo,
|
||||
cycle: this.form.cycle,
|
||||
maxPerCycle: this.form.maxPerCycle,
|
||||
maxAmountPerMonth: this.form.maxAmountPerMonth,
|
||||
},
|
||||
mutation: this.editContributionLink ? updateContributionLink : createContributionLink,
|
||||
variables: variables,
|
||||
})
|
||||
.then((result) => {
|
||||
this.link = result.data.createContributionLink.link
|
||||
this.toastSuccess(this.link)
|
||||
const link = this.editContributionLink
|
||||
? result.data.updateContributionLink.link
|
||||
: result.data.createContributionLink.link
|
||||
this.toastSuccess(
|
||||
this.editContributionLink ? this.$t('contributionLink.changeSaved') : link,
|
||||
)
|
||||
this.onReset()
|
||||
this.$root.$emit('bv::toggle::collapse', 'newContribution')
|
||||
this.$emit('get-contribution-links')
|
||||
@ -195,14 +208,7 @@ export default {
|
||||
},
|
||||
watch: {
|
||||
contributionLinkData() {
|
||||
this.form.name = this.contributionLinkData.name
|
||||
this.form.memo = this.contributionLinkData.memo
|
||||
this.form.amount = this.contributionLinkData.amount
|
||||
this.form.validFrom = this.contributionLinkData.validFrom
|
||||
this.form.validTo = this.contributionLinkData.validTo
|
||||
this.form.cycle = this.contributionLinkData.cycle
|
||||
this.form.maxPerCycle = this.contributionLinkData.maxPerCycle
|
||||
this.form.maxAmountPerMonth = this.contributionLinkData.maxAmountPerMonth
|
||||
this.form = this.contributionLinkData
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
@ -118,12 +118,11 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
updateCreationData(data) {
|
||||
this.creationUserData = data
|
||||
// this.creationUserData.amount = data.amount
|
||||
// this.creationUserData.date = data.date
|
||||
// this.creationUserData.memo = data.memo
|
||||
// this.creationUserData.moderator = data.moderator
|
||||
data.row.toggleDetails()
|
||||
const row = data.row
|
||||
this.$emit('update-contributions', data)
|
||||
delete data.row
|
||||
this.creationUserData = { ...this.creationUserData, ...data }
|
||||
row.toggleDetails()
|
||||
},
|
||||
updateUserData(rowItem, newCreation) {
|
||||
rowItem.creation = newCreation
|
||||
|
||||
40
admin/src/graphql/updateContributionLink.js
Normal file
40
admin/src/graphql/updateContributionLink.js
Normal file
@ -0,0 +1,40 @@
|
||||
import gql from 'graphql-tag'
|
||||
|
||||
export const updateContributionLink = gql`
|
||||
mutation (
|
||||
$amount: Decimal!
|
||||
$name: String!
|
||||
$memo: String!
|
||||
$cycle: String!
|
||||
$validFrom: String
|
||||
$validTo: String
|
||||
$maxAmountPerMonth: Decimal
|
||||
$maxPerCycle: Int! = 1
|
||||
$id: Int!
|
||||
) {
|
||||
updateContributionLink(
|
||||
amount: $amount
|
||||
name: $name
|
||||
memo: $memo
|
||||
cycle: $cycle
|
||||
validFrom: $validFrom
|
||||
validTo: $validTo
|
||||
maxAmountPerMonth: $maxAmountPerMonth
|
||||
maxPerCycle: $maxPerCycle
|
||||
id: $id
|
||||
) {
|
||||
id
|
||||
amount
|
||||
name
|
||||
memo
|
||||
code
|
||||
link
|
||||
createdAt
|
||||
validFrom
|
||||
validTo
|
||||
maxAmountPerMonth
|
||||
cycle
|
||||
maxPerCycle
|
||||
}
|
||||
}
|
||||
`
|
||||
@ -3,7 +3,9 @@
|
||||
"back": "zurück",
|
||||
"contributionLink": {
|
||||
"amount": "Betrag",
|
||||
"changeSaved": "Änderungen gespeichert",
|
||||
"clear": "Löschen",
|
||||
"close": "Schließen",
|
||||
"contributionLinks": "Beitragslinks",
|
||||
"create": "Anlegen",
|
||||
"cycle": "Zyklus",
|
||||
@ -23,6 +25,7 @@
|
||||
"once": "einmalig"
|
||||
}
|
||||
},
|
||||
"saveChange": "Änderungen speichern",
|
||||
"validFrom": "Startdatum",
|
||||
"validTo": "Enddatum"
|
||||
},
|
||||
|
||||
@ -3,7 +3,9 @@
|
||||
"back": "back",
|
||||
"contributionLink": {
|
||||
"amount": "Amount",
|
||||
"changeSaved": "Changes saved",
|
||||
"clear": "Clear",
|
||||
"close": "Close",
|
||||
"contributionLinks": "Contribution Links",
|
||||
"create": "Create",
|
||||
"cycle": "Cycle",
|
||||
@ -23,6 +25,7 @@
|
||||
"once": "once"
|
||||
}
|
||||
},
|
||||
"saveChange": "Save Changes",
|
||||
"validFrom": "Start-date",
|
||||
"validTo": "End-Date"
|
||||
},
|
||||
|
||||
@ -1,42 +1,22 @@
|
||||
import { mount } from '@vue/test-utils'
|
||||
import CreationConfirm from './CreationConfirm.vue'
|
||||
import { adminDeleteContribution } from '../graphql/adminDeleteContribution'
|
||||
import { listUnconfirmedContributions } from '../graphql/listUnconfirmedContributions'
|
||||
import { confirmContribution } from '../graphql/confirmContribution'
|
||||
import { toastErrorSpy, toastSuccessSpy } from '../../test/testSetup'
|
||||
import VueApollo from 'vue-apollo'
|
||||
import { createMockClient } from 'mock-apollo-client'
|
||||
|
||||
const mockClient = createMockClient()
|
||||
const apolloProvider = new VueApollo({
|
||||
defaultClient: mockClient,
|
||||
})
|
||||
|
||||
const localVue = global.localVue
|
||||
|
||||
const storeCommitMock = jest.fn()
|
||||
const apolloQueryMock = jest.fn().mockResolvedValue({
|
||||
data: {
|
||||
listUnconfirmedContributions: [
|
||||
{
|
||||
id: 1,
|
||||
firstName: 'Bibi',
|
||||
lastName: 'Bloxberg',
|
||||
userId: 99,
|
||||
email: 'bibi@bloxberg.de',
|
||||
amount: 500,
|
||||
memo: 'Danke für alles',
|
||||
date: new Date(),
|
||||
moderator: 1,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
firstName: 'Räuber',
|
||||
lastName: 'Hotzenplotz',
|
||||
userId: 100,
|
||||
email: 'raeuber@hotzenplotz.de',
|
||||
amount: 1000000,
|
||||
memo: 'Gut Ergattert',
|
||||
date: new Date(),
|
||||
moderator: 1,
|
||||
},
|
||||
],
|
||||
},
|
||||
})
|
||||
localVue.use(VueApollo)
|
||||
|
||||
const apolloMutateMock = jest.fn().mockResolvedValue({})
|
||||
const storeCommitMock = jest.fn()
|
||||
|
||||
const mocks = {
|
||||
$t: jest.fn((t) => t),
|
||||
@ -53,17 +33,69 @@ const mocks = {
|
||||
},
|
||||
},
|
||||
},
|
||||
$apollo: {
|
||||
query: apolloQueryMock,
|
||||
mutate: apolloMutateMock,
|
||||
},
|
||||
}
|
||||
|
||||
const defaultData = () => {
|
||||
return {
|
||||
listUnconfirmedContributions: [
|
||||
{
|
||||
id: 1,
|
||||
firstName: 'Bibi',
|
||||
lastName: 'Bloxberg',
|
||||
userId: 99,
|
||||
email: 'bibi@bloxberg.de',
|
||||
amount: 500,
|
||||
memo: 'Danke für alles',
|
||||
date: new Date(),
|
||||
moderator: 1,
|
||||
state: 'PENDING',
|
||||
creation: [500, 500, 500],
|
||||
messageCount: 0,
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
firstName: 'Räuber',
|
||||
lastName: 'Hotzenplotz',
|
||||
userId: 100,
|
||||
email: 'raeuber@hotzenplotz.de',
|
||||
amount: 1000000,
|
||||
memo: 'Gut Ergattert',
|
||||
date: new Date(),
|
||||
moderator: 1,
|
||||
state: 'PENDING',
|
||||
creation: [500, 500, 500],
|
||||
messageCount: 0,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
describe('CreationConfirm', () => {
|
||||
let wrapper
|
||||
|
||||
const listUnconfirmedContributionsMock = jest.fn()
|
||||
const adminDeleteContributionMock = jest.fn()
|
||||
const confirmContributionMock = jest.fn()
|
||||
|
||||
mockClient.setRequestHandler(
|
||||
listUnconfirmedContributions,
|
||||
listUnconfirmedContributionsMock
|
||||
.mockRejectedValueOnce({ message: 'Ouch!' })
|
||||
.mockResolvedValue({ data: defaultData() }),
|
||||
)
|
||||
|
||||
mockClient.setRequestHandler(
|
||||
adminDeleteContribution,
|
||||
adminDeleteContributionMock.mockResolvedValue({ data: { adminDeleteContribution: true } }),
|
||||
)
|
||||
|
||||
mockClient.setRequestHandler(
|
||||
confirmContribution,
|
||||
confirmContributionMock.mockResolvedValue({ data: { confirmContribution: true } }),
|
||||
)
|
||||
|
||||
const Wrapper = () => {
|
||||
return mount(CreationConfirm, { localVue, mocks })
|
||||
return mount(CreationConfirm, { localVue, mocks, apolloProvider })
|
||||
}
|
||||
|
||||
describe('mount', () => {
|
||||
@ -72,12 +104,20 @@ describe('CreationConfirm', () => {
|
||||
wrapper = Wrapper()
|
||||
})
|
||||
|
||||
it('has a DIV element with the class.creation-confirm', () => {
|
||||
expect(wrapper.find('div.creation-confirm').exists()).toBeTruthy()
|
||||
describe('server response for get pending creations is error', () => {
|
||||
it('toast an error message', () => {
|
||||
expect(toastErrorSpy).toBeCalledWith('Ouch!')
|
||||
})
|
||||
})
|
||||
|
||||
it('has two pending creations', () => {
|
||||
expect(wrapper.vm.pendingCreations).toHaveLength(2)
|
||||
describe('server response is succes', () => {
|
||||
it('has a DIV element with the class.creation-confirm', () => {
|
||||
expect(wrapper.find('div.creation-confirm').exists()).toBeTruthy()
|
||||
})
|
||||
|
||||
it('has two pending creations', () => {
|
||||
expect(wrapper.vm.pendingCreations).toHaveLength(2)
|
||||
})
|
||||
})
|
||||
|
||||
describe('store', () => {
|
||||
@ -105,10 +145,7 @@ describe('CreationConfirm', () => {
|
||||
})
|
||||
|
||||
it('calls the adminDeleteContribution mutation', () => {
|
||||
expect(apolloMutateMock).toBeCalledWith({
|
||||
mutation: adminDeleteContribution,
|
||||
variables: { id: 1 },
|
||||
})
|
||||
expect(adminDeleteContributionMock).toBeCalledWith({ id: 1 })
|
||||
})
|
||||
|
||||
it('commits openCreationsMinus to store', () => {
|
||||
@ -128,7 +165,7 @@ describe('CreationConfirm', () => {
|
||||
})
|
||||
|
||||
it('does not call the adminDeleteContribution mutation', () => {
|
||||
expect(apolloMutateMock).not.toBeCalled()
|
||||
expect(adminDeleteContributionMock).not.toBeCalled()
|
||||
})
|
||||
})
|
||||
})
|
||||
@ -139,7 +176,7 @@ describe('CreationConfirm', () => {
|
||||
beforeEach(async () => {
|
||||
spy = jest.spyOn(wrapper.vm.$bvModal, 'msgBoxConfirm')
|
||||
spy.mockImplementation(() => Promise.resolve('some value'))
|
||||
apolloMutateMock.mockRejectedValue({ message: 'Ouchhh!' })
|
||||
adminDeleteContributionMock.mockRejectedValue({ message: 'Ouchhh!' })
|
||||
await wrapper.findAll('tr').at(1).findAll('button').at(0).trigger('click')
|
||||
})
|
||||
|
||||
@ -150,7 +187,6 @@ describe('CreationConfirm', () => {
|
||||
|
||||
describe('confirm creation with success', () => {
|
||||
beforeEach(async () => {
|
||||
apolloMutateMock.mockResolvedValue({})
|
||||
await wrapper.findAll('tr').at(2).findAll('button').at(2).trigger('click')
|
||||
})
|
||||
|
||||
@ -179,10 +215,7 @@ describe('CreationConfirm', () => {
|
||||
})
|
||||
|
||||
it('calls the confirmContribution mutation', () => {
|
||||
expect(apolloMutateMock).toBeCalledWith({
|
||||
mutation: confirmContribution,
|
||||
variables: { id: 2 },
|
||||
})
|
||||
expect(confirmContributionMock).toBeCalledWith({ id: 2 })
|
||||
})
|
||||
|
||||
it('commits openCreationsMinus to store', () => {
|
||||
@ -200,7 +233,7 @@ describe('CreationConfirm', () => {
|
||||
|
||||
describe('confirm creation with error', () => {
|
||||
beforeEach(async () => {
|
||||
apolloMutateMock.mockRejectedValue({ message: 'Ouchhh!' })
|
||||
confirmContributionMock.mockRejectedValue({ message: 'Ouchhh!' })
|
||||
await wrapper.find('#overlay').findAll('button').at(1).trigger('click')
|
||||
})
|
||||
|
||||
@ -210,19 +243,5 @@ describe('CreationConfirm', () => {
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
describe('server response for get pending creations is error', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks()
|
||||
apolloQueryMock.mockRejectedValue({
|
||||
message: 'Ouch!',
|
||||
})
|
||||
wrapper = Wrapper()
|
||||
})
|
||||
|
||||
it('toast an error message', () => {
|
||||
expect(toastErrorSpy).toBeCalledWith('Ouch!')
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@ -10,6 +10,7 @@
|
||||
@remove-creation="removeCreation"
|
||||
@show-overlay="showOverlay"
|
||||
@update-state="updateState"
|
||||
@update-contributions="$apollo.queries.PendingContributions.refetch()"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
@ -71,21 +72,6 @@ export default {
|
||||
this.toastError(error.message)
|
||||
})
|
||||
},
|
||||
getPendingCreations() {
|
||||
this.$apollo
|
||||
.query({
|
||||
query: listUnconfirmedContributions,
|
||||
fetchPolicy: 'network-only',
|
||||
})
|
||||
.then((result) => {
|
||||
this.$store.commit('resetOpenCreations')
|
||||
this.pendingCreations = result.data.listUnconfirmedContributions
|
||||
this.$store.commit('setOpenCreations', result.data.listUnconfirmedContributions.length)
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toastError(error.message)
|
||||
})
|
||||
},
|
||||
updatePendingCreations(id) {
|
||||
this.pendingCreations = this.pendingCreations.filter((obj) => obj.id !== id)
|
||||
this.$store.commit('openCreationsMinus', 1)
|
||||
@ -127,8 +113,24 @@ export default {
|
||||
]
|
||||
},
|
||||
},
|
||||
async created() {
|
||||
await this.getPendingCreations()
|
||||
apollo: {
|
||||
PendingContributions: {
|
||||
query() {
|
||||
return listUnconfirmedContributions
|
||||
},
|
||||
variables() {
|
||||
// may be at some point we need a pagination here
|
||||
return {}
|
||||
},
|
||||
update({ listUnconfirmedContributions }) {
|
||||
this.$store.commit('resetOpenCreations')
|
||||
this.pendingCreations = listUnconfirmedContributions
|
||||
this.$store.commit('setOpenCreations', listUnconfirmedContributions.length)
|
||||
},
|
||||
error({ message }) {
|
||||
this.toastError(message)
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
123
admin/yarn.lock
123
admin/yarn.lock
@ -2,6 +2,25 @@
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
"@apollo/client@^3.7.1":
|
||||
version "3.7.1"
|
||||
resolved "https://registry.yarnpkg.com/@apollo/client/-/client-3.7.1.tgz#86ce47c18a0714e229231148b0306562550c2248"
|
||||
integrity sha512-xu5M/l7p9gT9Fx7nF3AQivp0XukjB7TM7tOd5wifIpI8RskYveL4I+rpTijzWrnqCPZabkbzJKH7WEAKdctt9w==
|
||||
dependencies:
|
||||
"@graphql-typed-document-node/core" "^3.1.1"
|
||||
"@wry/context" "^0.7.0"
|
||||
"@wry/equality" "^0.5.0"
|
||||
"@wry/trie" "^0.3.0"
|
||||
graphql-tag "^2.12.6"
|
||||
hoist-non-react-statics "^3.3.2"
|
||||
optimism "^0.16.1"
|
||||
prop-types "^15.7.2"
|
||||
response-iterator "^0.2.6"
|
||||
symbol-observable "^4.0.0"
|
||||
ts-invariant "^0.10.3"
|
||||
tslib "^2.3.0"
|
||||
zen-observable-ts "^1.2.5"
|
||||
|
||||
"@babel/code-frame@7.12.11":
|
||||
version "7.12.11"
|
||||
resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f"
|
||||
@ -1030,6 +1049,11 @@
|
||||
minimatch "^3.0.4"
|
||||
strip-json-comments "^3.1.1"
|
||||
|
||||
"@graphql-typed-document-node/core@^3.1.1":
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.1.1.tgz#076d78ce99822258cf813ecc1e7fa460fa74d052"
|
||||
integrity sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg==
|
||||
|
||||
"@hapi/address@2.x.x":
|
||||
version "2.1.4"
|
||||
resolved "https://registry.yarnpkg.com/@hapi/address/-/address-2.1.4.tgz#5d67ed43f3fd41a69d4b9ff7b56e7c0d1d0a81e5"
|
||||
@ -2419,6 +2443,20 @@
|
||||
"@types/node" ">=6"
|
||||
tslib "^1.9.3"
|
||||
|
||||
"@wry/context@^0.6.0":
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/@wry/context/-/context-0.6.1.tgz#c3c29c0ad622adb00f6a53303c4f965ee06ebeb2"
|
||||
integrity sha512-LOmVnY1iTU2D8tv4Xf6MVMZZ+juIJ87Kt/plMijjN20NMAXGmH4u8bS1t0uT74cZ5gwpocYueV58YwyI8y+GKw==
|
||||
dependencies:
|
||||
tslib "^2.3.0"
|
||||
|
||||
"@wry/context@^0.7.0":
|
||||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/@wry/context/-/context-0.7.0.tgz#be88e22c0ddf62aeb0ae9f95c3d90932c619a5c8"
|
||||
integrity sha512-LcDAiYWRtwAoSOArfk7cuYvFXytxfVrdX7yxoUmK7pPITLk5jYh2F8knCwS7LjgYL8u1eidPlKKV6Ikqq0ODqQ==
|
||||
dependencies:
|
||||
tslib "^2.3.0"
|
||||
|
||||
"@wry/equality@^0.1.2":
|
||||
version "0.1.11"
|
||||
resolved "https://registry.yarnpkg.com/@wry/equality/-/equality-0.1.11.tgz#35cb156e4a96695aa81a9ecc4d03787bc17f1790"
|
||||
@ -2426,6 +2464,20 @@
|
||||
dependencies:
|
||||
tslib "^1.9.3"
|
||||
|
||||
"@wry/equality@^0.5.0":
|
||||
version "0.5.3"
|
||||
resolved "https://registry.yarnpkg.com/@wry/equality/-/equality-0.5.3.tgz#fafebc69561aa2d40340da89fa7dc4b1f6fb7831"
|
||||
integrity sha512-avR+UXdSrsF2v8vIqIgmeTY0UR91UT+IyablCyKe/uk22uOJ8fusKZnH9JH9e1/EtLeNJBtagNmL3eJdnOV53g==
|
||||
dependencies:
|
||||
tslib "^2.3.0"
|
||||
|
||||
"@wry/trie@^0.3.0":
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@wry/trie/-/trie-0.3.2.tgz#a06f235dc184bd26396ba456711f69f8c35097e6"
|
||||
integrity sha512-yRTyhWSls2OY/pYLfwff867r8ekooZ4UI+/gxot5Wj8EFwSf2rG+n+Mo/6LoLQm1TKA4GRj2+LCpbfS937dClQ==
|
||||
dependencies:
|
||||
tslib "^2.3.0"
|
||||
|
||||
"@xtuc/ieee754@^1.2.0":
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790"
|
||||
@ -6704,6 +6756,13 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6
|
||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a"
|
||||
integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==
|
||||
|
||||
graphql-tag@^2.12.6:
|
||||
version "2.12.6"
|
||||
resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.12.6.tgz#d441a569c1d2537ef10ca3d1633b48725329b5f1"
|
||||
integrity sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==
|
||||
dependencies:
|
||||
tslib "^2.1.0"
|
||||
|
||||
graphql-tag@^2.4.2:
|
||||
version "2.12.5"
|
||||
resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.12.5.tgz#5cff974a67b417747d05c8d9f5f3cb4495d0db8f"
|
||||
@ -6880,6 +6939,13 @@ hmac-drbg@^1.0.1:
|
||||
minimalistic-assert "^1.0.0"
|
||||
minimalistic-crypto-utils "^1.0.1"
|
||||
|
||||
hoist-non-react-statics@^3.3.2:
|
||||
version "3.3.2"
|
||||
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
|
||||
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
|
||||
dependencies:
|
||||
react-is "^16.7.0"
|
||||
|
||||
homedir-polyfill@^1.0.1:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8"
|
||||
@ -9174,7 +9240,7 @@ lolex@^5.0.0:
|
||||
dependencies:
|
||||
"@sinonjs/commons" "^1.7.0"
|
||||
|
||||
loose-envify@^1.0.0:
|
||||
loose-envify@^1.0.0, loose-envify@^1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
|
||||
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
|
||||
@ -9498,6 +9564,11 @@ mkdirp@0.x, mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.5, mkdirp@~0.5.1:
|
||||
dependencies:
|
||||
minimist "^1.2.5"
|
||||
|
||||
mock-apollo-client@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/mock-apollo-client/-/mock-apollo-client-1.2.1.tgz#e3bfdc3ff73b1fea28fa7e91ec82e43ba8cbfa39"
|
||||
integrity sha512-QYQ6Hxo+t7hard1bcHHbsHxlNQYTQsaMNsm2Psh/NbwLMi2R4tGzplJKt97MUWuARHMq3GHB4PTLj/gxej4Caw==
|
||||
|
||||
moo-color@^1.0.2:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/moo-color/-/moo-color-1.0.3.tgz#d56435f8359c8284d83ac58016df7427febece74"
|
||||
@ -9987,6 +10058,14 @@ optimism@^0.10.0:
|
||||
dependencies:
|
||||
"@wry/context" "^0.4.0"
|
||||
|
||||
optimism@^0.16.1:
|
||||
version "0.16.1"
|
||||
resolved "https://registry.yarnpkg.com/optimism/-/optimism-0.16.1.tgz#7c8efc1f3179f18307b887e18c15c5b7133f6e7d"
|
||||
integrity sha512-64i+Uw3otrndfq5kaoGNoY7pvOhSsjFEN4bdEFh80MWVk/dbgJfMv7VFDeCT8LxNAlEVhQmdVEbfE7X2nWNIIg==
|
||||
dependencies:
|
||||
"@wry/context" "^0.6.0"
|
||||
"@wry/trie" "^0.3.0"
|
||||
|
||||
optionator@^0.8.1:
|
||||
version "0.8.3"
|
||||
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495"
|
||||
@ -10901,6 +10980,15 @@ prompts@^2.0.1:
|
||||
kleur "^3.0.3"
|
||||
sisteransi "^1.0.5"
|
||||
|
||||
prop-types@^15.7.2:
|
||||
version "15.8.1"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
|
||||
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
|
||||
dependencies:
|
||||
loose-envify "^1.4.0"
|
||||
object-assign "^4.1.1"
|
||||
react-is "^16.13.1"
|
||||
|
||||
proto-list@~1.2.1:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849"
|
||||
@ -11080,7 +11168,7 @@ raw-body@2.4.0:
|
||||
iconv-lite "0.4.24"
|
||||
unpipe "1.0.0"
|
||||
|
||||
react-is@^16.8.4:
|
||||
react-is@^16.13.1, react-is@^16.7.0, react-is@^16.8.4:
|
||||
version "16.13.1"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
||||
@ -11423,6 +11511,11 @@ resolve@1.x, resolve@^1.10.0, resolve@^1.10.1, resolve@^1.12.0, resolve@^1.14.2,
|
||||
is-core-module "^2.2.0"
|
||||
path-parse "^1.0.6"
|
||||
|
||||
response-iterator@^0.2.6:
|
||||
version "0.2.6"
|
||||
resolved "https://registry.yarnpkg.com/response-iterator/-/response-iterator-0.2.6.tgz#249005fb14d2e4eeb478a3f735a28fd8b4c9f3da"
|
||||
integrity sha512-pVzEEzrsg23Sh053rmDUvLSkGXluZio0qu8VT6ukrYuvtjVfCbDZH9d6PGXb8HZfzdNZt8feXv/jvUzlhRgLnw==
|
||||
|
||||
restore-cursor@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
|
||||
@ -12446,6 +12539,11 @@ symbol-observable@^1.0.2:
|
||||
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"
|
||||
integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==
|
||||
|
||||
symbol-observable@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-4.0.0.tgz#5b425f192279e87f2f9b937ac8540d1984b39205"
|
||||
integrity sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==
|
||||
|
||||
symbol-tree@^3.2.2, symbol-tree@^3.2.4:
|
||||
version "3.2.4"
|
||||
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"
|
||||
@ -12727,6 +12825,13 @@ tryer@^1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8"
|
||||
integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==
|
||||
|
||||
ts-invariant@^0.10.3:
|
||||
version "0.10.3"
|
||||
resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.10.3.tgz#3e048ff96e91459ffca01304dbc7f61c1f642f6c"
|
||||
integrity sha512-uivwYcQaxAucv1CzRp2n/QdYPo4ILf9VXgH19zEIjFx2EJufV16P0JtJVpYHy89DItG6Kwj2oIUjrcK5au+4tQ==
|
||||
dependencies:
|
||||
tslib "^2.1.0"
|
||||
|
||||
ts-invariant@^0.4.0:
|
||||
version "0.4.4"
|
||||
resolved "https://registry.yarnpkg.com/ts-invariant/-/ts-invariant-0.4.4.tgz#97a523518688f93aafad01b0e80eb803eb2abd86"
|
||||
@ -12785,6 +12890,11 @@ tslib@^2.1.0:
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01"
|
||||
integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==
|
||||
|
||||
tslib@^2.3.0:
|
||||
version "2.4.1"
|
||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e"
|
||||
integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==
|
||||
|
||||
tsutils@^3.21.0:
|
||||
version "3.21.0"
|
||||
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623"
|
||||
@ -13844,7 +13954,14 @@ zen-observable-ts@^0.8.21:
|
||||
tslib "^1.9.3"
|
||||
zen-observable "^0.8.0"
|
||||
|
||||
zen-observable@^0.8.0:
|
||||
zen-observable-ts@^1.2.5:
|
||||
version "1.2.5"
|
||||
resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-1.2.5.tgz#6c6d9ea3d3a842812c6e9519209365a122ba8b58"
|
||||
integrity sha512-QZWQekv6iB72Naeake9hS1KxHlotfRpe+WGNbNx5/ta+R3DNjVO2bswf63gXlWDcs+EMd7XY8HfVQyP1X6T4Zg==
|
||||
dependencies:
|
||||
zen-observable "0.8.15"
|
||||
|
||||
zen-observable@0.8.15, zen-observable@^0.8.0:
|
||||
version "0.8.15"
|
||||
resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15"
|
||||
integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==
|
||||
|
||||
@ -139,6 +139,7 @@ describe('AdminResolver', () => {
|
||||
|
||||
describe('user to get a new role does not exist', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({ mutation: setUserRole, variables: { userId: admin.id + 1, isAdmin: true } }),
|
||||
).resolves.toEqual(
|
||||
@ -195,6 +196,7 @@ describe('AdminResolver', () => {
|
||||
describe('change role with error', () => {
|
||||
describe('is own role', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({ mutation: setUserRole, variables: { userId: admin.id, isAdmin: false } }),
|
||||
).resolves.toEqual(
|
||||
@ -211,6 +213,7 @@ describe('AdminResolver', () => {
|
||||
describe('user has already role to be set', () => {
|
||||
describe('to admin', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
await mutate({
|
||||
mutation: setUserRole,
|
||||
variables: { userId: user.id, isAdmin: true },
|
||||
@ -231,6 +234,7 @@ describe('AdminResolver', () => {
|
||||
|
||||
describe('to usual user', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
await mutate({
|
||||
mutation: setUserRole,
|
||||
variables: { userId: user.id, isAdmin: false },
|
||||
@ -307,6 +311,7 @@ describe('AdminResolver', () => {
|
||||
|
||||
describe('user to be deleted does not exist', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({ mutation: deleteUser, variables: { userId: admin.id + 1 } }),
|
||||
).resolves.toEqual(
|
||||
@ -323,6 +328,7 @@ describe('AdminResolver', () => {
|
||||
|
||||
describe('delete self', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({ mutation: deleteUser, variables: { userId: admin.id } }),
|
||||
).resolves.toEqual(
|
||||
@ -356,6 +362,7 @@ describe('AdminResolver', () => {
|
||||
|
||||
describe('delete deleted user', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({ mutation: deleteUser, variables: { userId: user.id } }),
|
||||
).resolves.toEqual(
|
||||
@ -427,6 +434,7 @@ describe('AdminResolver', () => {
|
||||
|
||||
describe('user to be undelete does not exist', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({ mutation: unDeleteUser, variables: { userId: admin.id + 1 } }),
|
||||
).resolves.toEqual(
|
||||
@ -447,6 +455,7 @@ describe('AdminResolver', () => {
|
||||
})
|
||||
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({ mutation: unDeleteUser, variables: { userId: user.id } }),
|
||||
).resolves.toEqual(
|
||||
@ -939,6 +948,7 @@ describe('AdminResolver', () => {
|
||||
|
||||
describe('user to create for does not exist', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({ mutation: adminCreateContribution, variables }),
|
||||
).resolves.toEqual(
|
||||
@ -962,6 +972,7 @@ describe('AdminResolver', () => {
|
||||
})
|
||||
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({ mutation: adminCreateContribution, variables }),
|
||||
).resolves.toEqual(
|
||||
@ -987,6 +998,7 @@ describe('AdminResolver', () => {
|
||||
})
|
||||
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({ mutation: adminCreateContribution, variables }),
|
||||
).resolves.toEqual(
|
||||
@ -1013,6 +1025,7 @@ describe('AdminResolver', () => {
|
||||
|
||||
describe('date of creation is not a date string', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({ mutation: adminCreateContribution, variables }),
|
||||
).resolves.toEqual(
|
||||
@ -1034,6 +1047,7 @@ describe('AdminResolver', () => {
|
||||
|
||||
describe('date of creation is four months ago', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
const now = new Date()
|
||||
variables.creationDate = new Date(
|
||||
now.getFullYear(),
|
||||
@ -1061,6 +1075,7 @@ describe('AdminResolver', () => {
|
||||
|
||||
describe('date of creation is in the future', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
const now = new Date()
|
||||
variables.creationDate = new Date(
|
||||
now.getFullYear(),
|
||||
@ -1088,6 +1103,7 @@ describe('AdminResolver', () => {
|
||||
|
||||
describe('amount of creation is too high', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
variables.creationDate = new Date().toString()
|
||||
await expect(
|
||||
mutate({ mutation: adminCreateContribution, variables }),
|
||||
@ -1213,6 +1229,7 @@ describe('AdminResolver', () => {
|
||||
|
||||
describe('user for creation to update does not exist', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: adminUpdateContribution,
|
||||
@ -1242,6 +1259,7 @@ describe('AdminResolver', () => {
|
||||
|
||||
describe('user for creation to update is deleted', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: adminUpdateContribution,
|
||||
@ -1267,6 +1285,7 @@ describe('AdminResolver', () => {
|
||||
|
||||
describe('creation does not exist', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: adminUpdateContribution,
|
||||
@ -1292,6 +1311,7 @@ describe('AdminResolver', () => {
|
||||
|
||||
describe('user email does not match creation user', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: adminUpdateContribution,
|
||||
@ -1326,6 +1346,7 @@ describe('AdminResolver', () => {
|
||||
describe('creation update is not valid', () => {
|
||||
// as this test has not clearly defined that date, it is a false positive
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: adminUpdateContribution,
|
||||
@ -1502,6 +1523,7 @@ describe('AdminResolver', () => {
|
||||
describe('adminDeleteContribution', () => {
|
||||
describe('creation id does not exist', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: adminDeleteContribution,
|
||||
@ -1538,6 +1560,7 @@ describe('AdminResolver', () => {
|
||||
})
|
||||
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: adminDeleteContribution,
|
||||
@ -1583,6 +1606,7 @@ describe('AdminResolver', () => {
|
||||
describe('confirmContribution', () => {
|
||||
describe('creation does not exits', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: confirmContribution,
|
||||
|
||||
@ -63,6 +63,7 @@ import ContributionMessageArgs from '@arg/ContributionMessageArgs'
|
||||
import { ContributionMessageType } from '@enum/MessageType'
|
||||
import { ContributionMessage } from '@model/ContributionMessage'
|
||||
import { sendContributionConfirmedEmail } from '@/mailer/sendContributionConfirmedEmail'
|
||||
import { sendContributionRejectedEmail } from '@/mailer/sendContributionRejectedEmail'
|
||||
import { sendAddedContributionMessageEmail } from '@/mailer/sendAddedContributionMessageEmail'
|
||||
import { eventProtocol } from '@/event/EventProtocolEmitter'
|
||||
import {
|
||||
@ -455,6 +456,10 @@ export class AdminResolver {
|
||||
) {
|
||||
throw new Error('Own contribution can not be deleted as admin')
|
||||
}
|
||||
const user = await dbUser.findOneOrFail(
|
||||
{ id: contribution.userId },
|
||||
{ relations: ['emailContact'] },
|
||||
)
|
||||
contribution.contributionStatus = ContributionStatus.DELETED
|
||||
contribution.deletedBy = moderator.id
|
||||
await contribution.save()
|
||||
@ -468,6 +473,16 @@ export class AdminResolver {
|
||||
await eventProtocol.writeEvent(
|
||||
event.setEventAdminContributionDelete(eventAdminContributionDelete),
|
||||
)
|
||||
sendContributionRejectedEmail({
|
||||
senderFirstName: moderator.firstName,
|
||||
senderLastName: moderator.lastName,
|
||||
recipientEmail: user.emailContact.email,
|
||||
recipientFirstName: user.firstName,
|
||||
recipientLastName: user.lastName,
|
||||
contributionMemo: contribution.memo,
|
||||
contributionAmount: contribution.amount,
|
||||
overviewURL: CONFIG.EMAIL_LINK_OVERVIEW,
|
||||
})
|
||||
|
||||
return !!res
|
||||
}
|
||||
|
||||
@ -74,6 +74,7 @@ describe('ContributionResolver', () => {
|
||||
|
||||
describe('input not valid', () => {
|
||||
it('throws error when memo length smaller than 5 chars', async () => {
|
||||
jest.clearAllMocks()
|
||||
const date = new Date()
|
||||
await expect(
|
||||
mutate({
|
||||
@ -92,10 +93,11 @@ describe('ContributionResolver', () => {
|
||||
})
|
||||
|
||||
it('logs the error found', () => {
|
||||
expect(logger.error).toBeCalledWith(`memo text is too short: memo.length=4 < (5)`)
|
||||
expect(logger.error).toBeCalledWith(`memo text is too short: memo.length=4 < 5`)
|
||||
})
|
||||
|
||||
it('throws error when memo length greater than 255 chars', async () => {
|
||||
jest.clearAllMocks()
|
||||
const date = new Date()
|
||||
await expect(
|
||||
mutate({
|
||||
@ -114,10 +116,11 @@ describe('ContributionResolver', () => {
|
||||
})
|
||||
|
||||
it('logs the error found', () => {
|
||||
expect(logger.error).toBeCalledWith(`memo text is too long: memo.length=259 > (255)`)
|
||||
expect(logger.error).toBeCalledWith(`memo text is too long: memo.length=259 > 255`)
|
||||
})
|
||||
|
||||
it('throws error when creationDate not-valid', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: createContribution,
|
||||
@ -144,6 +147,7 @@ describe('ContributionResolver', () => {
|
||||
})
|
||||
|
||||
it('throws error when creationDate 3 month behind', async () => {
|
||||
jest.clearAllMocks()
|
||||
const date = new Date()
|
||||
await expect(
|
||||
mutate({
|
||||
@ -375,6 +379,7 @@ describe('ContributionResolver', () => {
|
||||
|
||||
describe('wrong contribution id', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: updateContribution,
|
||||
@ -399,6 +404,7 @@ describe('ContributionResolver', () => {
|
||||
|
||||
describe('Memo length smaller than 5 chars', () => {
|
||||
it('throws error', async () => {
|
||||
jest.clearAllMocks()
|
||||
const date = new Date()
|
||||
await expect(
|
||||
mutate({
|
||||
@ -418,12 +424,13 @@ describe('ContributionResolver', () => {
|
||||
})
|
||||
|
||||
it('logs the error found', () => {
|
||||
expect(logger.error).toBeCalledWith('memo text is too short: memo.length=4 < (5)')
|
||||
expect(logger.error).toBeCalledWith('memo text is too short: memo.length=4 < 5')
|
||||
})
|
||||
})
|
||||
|
||||
describe('Memo length greater than 255 chars', () => {
|
||||
it('throws error', async () => {
|
||||
jest.clearAllMocks()
|
||||
const date = new Date()
|
||||
await expect(
|
||||
mutate({
|
||||
@ -443,7 +450,7 @@ describe('ContributionResolver', () => {
|
||||
})
|
||||
|
||||
it('logs the error found', () => {
|
||||
expect(logger.error).toBeCalledWith('memo text is too long: memo.length=259 > (255)')
|
||||
expect(logger.error).toBeCalledWith('memo text is too long: memo.length=259 > 255')
|
||||
})
|
||||
})
|
||||
|
||||
@ -456,6 +463,7 @@ describe('ContributionResolver', () => {
|
||||
})
|
||||
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: updateContribution,
|
||||
@ -486,6 +494,7 @@ describe('ContributionResolver', () => {
|
||||
|
||||
describe('admin tries to update a user contribution', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: adminUpdateContribution,
|
||||
@ -516,6 +525,7 @@ describe('ContributionResolver', () => {
|
||||
})
|
||||
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: updateContribution,
|
||||
@ -546,6 +556,7 @@ describe('ContributionResolver', () => {
|
||||
|
||||
describe('update creation to a date that is older than 3 months', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
const date = new Date()
|
||||
await expect(
|
||||
mutate({
|
||||
@ -564,7 +575,7 @@ describe('ContributionResolver', () => {
|
||||
)
|
||||
})
|
||||
|
||||
it('logs the error found', () => {
|
||||
it.skip('logs the error found', () => {
|
||||
expect(logger.error).toBeCalledWith(
|
||||
'No information for available creations with the given creationDate=',
|
||||
'Invalid Date',
|
||||
@ -830,6 +841,7 @@ describe('ContributionResolver', () => {
|
||||
|
||||
describe('User deletes already confirmed contribution', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
await mutate({
|
||||
mutation: login,
|
||||
variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
|
||||
|
||||
@ -32,12 +32,12 @@ export class ContributionResolver {
|
||||
@Ctx() context: Context,
|
||||
): Promise<UnconfirmedContribution> {
|
||||
if (memo.length > MEMO_MAX_CHARS) {
|
||||
logger.error(`memo text is too long: memo.length=${memo.length} > (${MEMO_MAX_CHARS})`)
|
||||
logger.error(`memo text is too long: memo.length=${memo.length} > ${MEMO_MAX_CHARS}`)
|
||||
throw new Error(`memo text is too long (${MEMO_MAX_CHARS} characters maximum)`)
|
||||
}
|
||||
|
||||
if (memo.length < MEMO_MIN_CHARS) {
|
||||
logger.error(`memo text is too short: memo.length=${memo.length} < (${MEMO_MIN_CHARS})`)
|
||||
logger.error(`memo text is too short: memo.length=${memo.length} < ${MEMO_MIN_CHARS}`)
|
||||
throw new Error(`memo text is too short (${MEMO_MIN_CHARS} characters minimum)`)
|
||||
}
|
||||
|
||||
@ -172,12 +172,12 @@ export class ContributionResolver {
|
||||
@Ctx() context: Context,
|
||||
): Promise<UnconfirmedContribution> {
|
||||
if (memo.length > MEMO_MAX_CHARS) {
|
||||
logger.error(`memo text is too long: memo.length=${memo.length} > (${MEMO_MAX_CHARS}`)
|
||||
logger.error(`memo text is too long: memo.length=${memo.length} > ${MEMO_MAX_CHARS}`)
|
||||
throw new Error(`memo text is too long (${MEMO_MAX_CHARS} characters maximum)`)
|
||||
}
|
||||
|
||||
if (memo.length < MEMO_MIN_CHARS) {
|
||||
logger.error(`memo text is too short: memo.length=${memo.length} < (${MEMO_MIN_CHARS}`)
|
||||
logger.error(`memo text is too short: memo.length=${memo.length} < ${MEMO_MIN_CHARS}`)
|
||||
throw new Error(`memo text is too short (${MEMO_MIN_CHARS} characters minimum)`)
|
||||
}
|
||||
|
||||
|
||||
@ -67,6 +67,7 @@ describe('send coins', () => {
|
||||
|
||||
describe('unknown recipient', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
await mutate({
|
||||
mutation: login,
|
||||
variables: bobData,
|
||||
@ -93,6 +94,7 @@ describe('send coins', () => {
|
||||
|
||||
describe('deleted recipient', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
await mutate({
|
||||
mutation: login,
|
||||
variables: peterData,
|
||||
@ -125,6 +127,7 @@ describe('send coins', () => {
|
||||
|
||||
describe('recipient account not activated', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
await mutate({
|
||||
mutation: login,
|
||||
variables: peterData,
|
||||
@ -166,6 +169,7 @@ describe('send coins', () => {
|
||||
|
||||
describe('sender and recipient are the same', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
expect(
|
||||
await mutate({
|
||||
mutation: sendCoins,
|
||||
@ -189,6 +193,7 @@ describe('send coins', () => {
|
||||
|
||||
describe('memo text is too long', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
expect(
|
||||
await mutate({
|
||||
mutation: sendCoins,
|
||||
@ -212,6 +217,7 @@ describe('send coins', () => {
|
||||
|
||||
describe('memo text is too short', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
expect(
|
||||
await mutate({
|
||||
mutation: sendCoins,
|
||||
@ -235,6 +241,7 @@ describe('send coins', () => {
|
||||
|
||||
describe('user has not enough GDD', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
expect(
|
||||
await mutate({
|
||||
mutation: sendCoins,
|
||||
@ -260,6 +267,7 @@ describe('send coins', () => {
|
||||
|
||||
describe('sending negative amount', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
expect(
|
||||
await mutate({
|
||||
mutation: sendCoins,
|
||||
|
||||
@ -514,18 +514,20 @@ describe('UserResolver', () => {
|
||||
await mutate({ mutation: createUser, variables: createUserVariables })
|
||||
const emailContact = await UserContact.findOneOrFail({ email: createUserVariables.email })
|
||||
emailVerificationCode = emailContact.emailVerificationCode.toString()
|
||||
result = await mutate({
|
||||
mutation: setPassword,
|
||||
variables: { code: emailVerificationCode, password: 'not-valid' },
|
||||
})
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDB()
|
||||
})
|
||||
|
||||
it('throws an error', () => {
|
||||
expect(result).toEqual(
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
expect(
|
||||
await mutate({
|
||||
mutation: setPassword,
|
||||
variables: { code: emailVerificationCode, password: 'not-valid' },
|
||||
}),
|
||||
).toEqual(
|
||||
expect.objectContaining({
|
||||
errors: [
|
||||
new GraphQLError(
|
||||
@ -544,18 +546,20 @@ describe('UserResolver', () => {
|
||||
describe('no valid optin code', () => {
|
||||
beforeAll(async () => {
|
||||
await mutate({ mutation: createUser, variables: createUserVariables })
|
||||
result = await mutate({
|
||||
mutation: setPassword,
|
||||
variables: { code: 'not valid', password: 'Aa12345_' },
|
||||
})
|
||||
})
|
||||
|
||||
afterAll(async () => {
|
||||
await cleanDB()
|
||||
})
|
||||
|
||||
it('throws an error', () => {
|
||||
expect(result).toEqual(
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
expect(
|
||||
await mutate({
|
||||
mutation: setPassword,
|
||||
variables: { code: 'not valid', password: 'Aa12345_' },
|
||||
}),
|
||||
).toEqual(
|
||||
expect.objectContaining({
|
||||
errors: [new GraphQLError('Could not login with emailVerificationCode')],
|
||||
}),
|
||||
@ -582,13 +586,9 @@ describe('UserResolver', () => {
|
||||
})
|
||||
|
||||
describe('no users in database', () => {
|
||||
beforeAll(async () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
result = await mutate({ mutation: login, variables })
|
||||
})
|
||||
|
||||
it('throws an error', () => {
|
||||
expect(result).toEqual(
|
||||
expect(await mutate({ mutation: login, variables })).toEqual(
|
||||
expect.objectContaining({
|
||||
errors: [new GraphQLError('No user with this credentials')],
|
||||
}),
|
||||
@ -666,6 +666,7 @@ describe('UserResolver', () => {
|
||||
describe('logout', () => {
|
||||
describe('unauthenticated', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
resetToken()
|
||||
await expect(mutate({ mutation: logout })).resolves.toEqual(
|
||||
expect.objectContaining({
|
||||
@ -704,6 +705,7 @@ describe('UserResolver', () => {
|
||||
describe('verifyLogin', () => {
|
||||
describe('unauthenticated', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
resetToken()
|
||||
await expect(query({ query: verifyLogin })).resolves.toEqual(
|
||||
expect.objectContaining({
|
||||
@ -723,6 +725,7 @@ describe('UserResolver', () => {
|
||||
})
|
||||
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
resetToken()
|
||||
await expect(query({ query: verifyLogin })).resolves.toEqual(
|
||||
expect.objectContaining({
|
||||
@ -883,6 +886,7 @@ describe('UserResolver', () => {
|
||||
|
||||
describe('wrong optin code', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
query({ query: queryOptIn, variables: { optIn: 'not-valid' } }),
|
||||
).resolves.toEqual(
|
||||
@ -919,6 +923,7 @@ describe('UserResolver', () => {
|
||||
describe('updateUserInfos', () => {
|
||||
describe('unauthenticated', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
resetToken()
|
||||
await expect(mutate({ mutation: updateUserInfos })).resolves.toEqual(
|
||||
expect.objectContaining({
|
||||
@ -976,6 +981,7 @@ describe('UserResolver', () => {
|
||||
|
||||
describe('language is not valid', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: updateUserInfos,
|
||||
@ -998,6 +1004,7 @@ describe('UserResolver', () => {
|
||||
describe('password', () => {
|
||||
describe('wrong old password', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: updateUserInfos,
|
||||
@ -1020,6 +1027,7 @@ describe('UserResolver', () => {
|
||||
|
||||
describe('invalid new password', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
await expect(
|
||||
mutate({
|
||||
mutation: updateUserInfos,
|
||||
@ -1108,6 +1116,7 @@ describe('UserResolver', () => {
|
||||
describe('searchAdminUsers', () => {
|
||||
describe('unauthenticated', () => {
|
||||
it('throws an error', async () => {
|
||||
jest.clearAllMocks()
|
||||
resetToken()
|
||||
await expect(mutate({ mutation: searchAdminUsers })).resolves.toEqual(
|
||||
expect.objectContaining({
|
||||
|
||||
38
backend/src/mailer/sendContributionRejectedEmail.test.ts
Normal file
38
backend/src/mailer/sendContributionRejectedEmail.test.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import Decimal from 'decimal.js-light'
|
||||
import { sendContributionRejectedEmail } from './sendContributionRejectedEmail'
|
||||
import { sendEMail } from './sendEMail'
|
||||
|
||||
jest.mock('./sendEMail', () => {
|
||||
return {
|
||||
__esModule: true,
|
||||
sendEMail: jest.fn(),
|
||||
}
|
||||
})
|
||||
|
||||
describe('sendContributionConfirmedEmail', () => {
|
||||
beforeEach(async () => {
|
||||
await sendContributionRejectedEmail({
|
||||
senderFirstName: 'Peter',
|
||||
senderLastName: 'Lustig',
|
||||
recipientFirstName: 'Bibi',
|
||||
recipientLastName: 'Bloxberg',
|
||||
recipientEmail: 'bibi@bloxberg.de',
|
||||
contributionMemo: 'Vielen herzlichen Dank für den neuen Hexenbesen!',
|
||||
contributionAmount: new Decimal(200.0),
|
||||
overviewURL: 'http://localhost/overview',
|
||||
})
|
||||
})
|
||||
|
||||
it('calls sendEMail', () => {
|
||||
expect(sendEMail).toBeCalledWith({
|
||||
to: 'Bibi Bloxberg <bibi@bloxberg.de>',
|
||||
subject: 'Schöpfung wurde abgelehnt',
|
||||
text:
|
||||
expect.stringContaining('Hallo Bibi Bloxberg') &&
|
||||
expect.stringContaining(
|
||||
'Dein Gradido Schöpfungsantrag "Vielen herzlichen Dank für den neuen Hexenbesen!" wurde soeben von Peter Lustig abgelehnt.',
|
||||
) &&
|
||||
expect.stringContaining('Link zu deinem Konto: http://localhost/overview'),
|
||||
})
|
||||
})
|
||||
})
|
||||
26
backend/src/mailer/sendContributionRejectedEmail.ts
Normal file
26
backend/src/mailer/sendContributionRejectedEmail.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { backendLogger as logger } from '@/server/logger'
|
||||
import Decimal from 'decimal.js-light'
|
||||
import { sendEMail } from './sendEMail'
|
||||
import { contributionRejected } from './text/contributionRejected'
|
||||
|
||||
export const sendContributionRejectedEmail = (data: {
|
||||
senderFirstName: string
|
||||
senderLastName: string
|
||||
recipientFirstName: string
|
||||
recipientLastName: string
|
||||
recipientEmail: string
|
||||
contributionMemo: string
|
||||
contributionAmount: Decimal
|
||||
overviewURL: string
|
||||
}): Promise<boolean> => {
|
||||
logger.info(
|
||||
`sendEmail(): to=${data.recipientFirstName} ${data.recipientLastName} <${data.recipientEmail}>,
|
||||
subject=${contributionRejected.de.subject},
|
||||
text=${contributionRejected.de.text(data)}`,
|
||||
)
|
||||
return sendEMail({
|
||||
to: `${data.recipientFirstName} ${data.recipientLastName} <${data.recipientEmail}>`,
|
||||
subject: contributionRejected.de.subject,
|
||||
text: contributionRejected.de.text(data),
|
||||
})
|
||||
}
|
||||
27
backend/src/mailer/text/contributionRejected.ts
Normal file
27
backend/src/mailer/text/contributionRejected.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import Decimal from 'decimal.js-light'
|
||||
|
||||
export const contributionRejected = {
|
||||
de: {
|
||||
subject: 'Schöpfung wurde abgelehnt',
|
||||
text: (data: {
|
||||
senderFirstName: string
|
||||
senderLastName: string
|
||||
recipientFirstName: string
|
||||
recipientLastName: string
|
||||
contributionMemo: string
|
||||
contributionAmount: Decimal
|
||||
overviewURL: string
|
||||
}): string =>
|
||||
`Hallo ${data.recipientFirstName} ${data.recipientLastName},
|
||||
|
||||
Dein eingereichter Gemeinwohl-Beitrag "${data.contributionMemo}" wurde soeben von ${data.senderFirstName} ${data.senderLastName} abgelehnt.
|
||||
|
||||
Bitte antworte nicht auf diese E-Mail!
|
||||
|
||||
Mit freundlichen Grüßen,
|
||||
dein Gradido-Team
|
||||
|
||||
|
||||
Link zu deinem Konto: ${data.overviewURL}`,
|
||||
},
|
||||
}
|
||||
@ -18,7 +18,7 @@ ENV NODE_ENV="production"
|
||||
# Labels
|
||||
LABEL org.label-schema.build-date="${BUILD_DATE}"
|
||||
LABEL org.label-schema.name="gradido:database"
|
||||
LABEL org.label-schema.description="Gradido GraphQL Backend"
|
||||
LABEL org.label-schema.description="Gradido Database Migration Service"
|
||||
LABEL org.label-schema.usage="https://github.com/gradido/gradido/blob/master/README.md"
|
||||
LABEL org.label-schema.url="https://gradido.net"
|
||||
LABEL org.label-schema.vcs-url="https://github.com/gradido/gradido/tree/master/database"
|
||||
|
||||
@ -20,10 +20,10 @@ ENV PORT="3000"
|
||||
# Labels
|
||||
LABEL org.label-schema.build-date="${BUILD_DATE}"
|
||||
LABEL org.label-schema.name="gradido:frontend"
|
||||
LABEL org.label-schema.description="Gradido Vue Webwallet"
|
||||
LABEL org.label-schema.usage="https://github.com/gradido/gradido_vue_wallet/blob/master/README.md"
|
||||
LABEL org.label-schema.description="Gradido Wallet Interface"
|
||||
LABEL org.label-schema.usage="https://github.com/gradido/gradido/blob/master/README.md"
|
||||
LABEL org.label-schema.url="https://gradido.net"
|
||||
LABEL org.label-schema.vcs-url="https://github.com/gradido/gradido_vue_wallet/tree/master/backend"
|
||||
LABEL org.label-schema.vcs-url="https://github.com/gradido/gradido/tree/master/frontend"
|
||||
LABEL org.label-schema.vcs-ref="${BUILD_COMMIT}"
|
||||
LABEL org.label-schema.vendor="gradido Community"
|
||||
LABEL org.label-schema.version="${BUILD_VERSION}"
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
<div class="m-1 mt-2">{{ $t('GDD') }}</div>
|
||||
</b-input-group-prepend>
|
||||
|
||||
<div class="p-3">{{ (amount * -1) | GDD }}</div>
|
||||
<div class="p-3">{{ amount | GDD }}</div>
|
||||
</b-input-group>
|
||||
|
||||
<br />
|
||||
|
||||
@ -207,7 +207,7 @@
|
||||
},
|
||||
"language": "Sprache",
|
||||
"link-load": "den letzten Link nachladen | die letzten {n} Links nachladen | weitere {n} Links nachladen",
|
||||
"login": "Anmeldung",
|
||||
"login": "Anmelden",
|
||||
"math": {
|
||||
"aprox": "~",
|
||||
"asterisk": "*",
|
||||
|
||||
@ -207,7 +207,7 @@
|
||||
},
|
||||
"language": "Language",
|
||||
"link-load": "Load the last link | Load the last {n} links | Load more {n} links",
|
||||
"login": "Login",
|
||||
"login": "Sign in",
|
||||
"math": {
|
||||
"aprox": "~",
|
||||
"asterisk": "*",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user