Merge branch 'master' into log-error

This commit is contained in:
Ulf Gebhardt 2023-02-02 12:16:12 +01:00 committed by GitHub
commit 9b057c5c10
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 514 additions and 76 deletions

View File

@ -45,6 +45,7 @@ import { Transaction as DbTransaction } from '@entity/Transaction'
import { User } from '@entity/User' import { User } from '@entity/User'
import { EventProtocolType } from '@/event/EventProtocolType' import { EventProtocolType } from '@/event/EventProtocolType'
import { logger, i18n as localization } from '@test/testSetup' import { logger, i18n as localization } from '@test/testSetup'
import { UserInputError } from 'apollo-server-express'
// mock account activation email to avoid console spam // mock account activation email to avoid console spam
// mock account activation email to avoid console spam // mock account activation email to avoid console spam
@ -681,7 +682,7 @@ describe('ContributionResolver', () => {
currentPage: 1, currentPage: 1,
pageSize: 25, pageSize: 25,
order: 'DESC', order: 'DESC',
filterConfirmed: false, statusFilter: null,
}, },
}), }),
).resolves.toEqual( ).resolves.toEqual(
@ -718,7 +719,76 @@ describe('ContributionResolver', () => {
resetToken() resetToken()
}) })
it('returns allCreation', async () => { it('throws an error with "NOT_VALID" in statusFilter', async () => {
await expect(
query({
query: listAllContributions,
variables: {
currentPage: 1,
pageSize: 25,
order: 'DESC',
statusFilter: ['NOT_VALID'],
},
}),
).resolves.toEqual(
expect.objectContaining({
errors: [
new UserInputError(
'Variable "$statusFilter" got invalid value "NOT_VALID" at "statusFilter[0]"; Value "NOT_VALID" does not exist in "ContributionStatus" enum.',
),
],
}),
)
})
it('throws an error with a null in statusFilter', async () => {
await expect(
query({
query: listAllContributions,
variables: {
currentPage: 1,
pageSize: 25,
order: 'DESC',
statusFilter: [null],
},
}),
).resolves.toEqual(
expect.objectContaining({
errors: [
new UserInputError(
'Variable "$statusFilter" got invalid value null at "statusFilter[0]"; Expected non-nullable type "ContributionStatus!" not to be null.',
),
],
}),
)
})
it('throws an error with null and "NOT_VALID" in statusFilter', async () => {
await expect(
query({
query: listAllContributions,
variables: {
currentPage: 1,
pageSize: 25,
order: 'DESC',
statusFilter: [null, 'NOT_VALID'],
},
}),
).resolves.toEqual(
expect.objectContaining({
errors: [
new UserInputError(
'Variable "$statusFilter" got invalid value null at "statusFilter[0]"; Expected non-nullable type "ContributionStatus!" not to be null.',
),
new UserInputError(
'Variable "$statusFilter" got invalid value "NOT_VALID" at "statusFilter[1]"; Value "NOT_VALID" does not exist in "ContributionStatus" enum.',
),
],
}),
)
})
it('returns all contributions without statusFilter', async () => {
await expect( await expect(
query({ query({
query: listAllContributions, query: listAllContributions,
@ -726,7 +796,6 @@ describe('ContributionResolver', () => {
currentPage: 1, currentPage: 1,
pageSize: 25, pageSize: 25,
order: 'DESC', order: 'DESC',
filterConfirmed: false,
}, },
}), }),
).resolves.toEqual( ).resolves.toEqual(
@ -737,11 +806,301 @@ describe('ContributionResolver', () => {
contributionList: expect.arrayContaining([ contributionList: expect.arrayContaining([
expect.objectContaining({ expect.objectContaining({
id: expect.any(Number), id: expect.any(Number),
state: 'CONFIRMED',
memo: 'Herzlich Willkommen bei Gradido!', memo: 'Herzlich Willkommen bei Gradido!',
amount: '1000', amount: '1000',
}), }),
expect.objectContaining({ expect.objectContaining({
id: expect.any(Number), id: expect.any(Number),
state: 'PENDING',
memo: 'Test env contribution',
amount: '100',
}),
]),
},
},
}),
)
})
it('returns all contributions for statusFilter = null', async () => {
await expect(
query({
query: listAllContributions,
variables: {
currentPage: 1,
pageSize: 25,
order: 'DESC',
statusFilter: null,
},
}),
).resolves.toEqual(
expect.objectContaining({
data: {
listAllContributions: {
contributionCount: 2,
contributionList: expect.arrayContaining([
expect.objectContaining({
id: expect.any(Number),
state: 'CONFIRMED',
memo: 'Herzlich Willkommen bei Gradido!',
amount: '1000',
}),
expect.objectContaining({
id: expect.any(Number),
state: 'PENDING',
memo: 'Test env contribution',
amount: '100',
}),
]),
},
},
}),
)
})
it('returns all contributions for statusFilter = []', async () => {
await expect(
query({
query: listAllContributions,
variables: {
currentPage: 1,
pageSize: 25,
order: 'DESC',
statusFilter: [],
},
}),
).resolves.toEqual(
expect.objectContaining({
data: {
listAllContributions: {
contributionCount: 2,
contributionList: expect.arrayContaining([
expect.objectContaining({
id: expect.any(Number),
state: 'CONFIRMED',
memo: 'Herzlich Willkommen bei Gradido!',
amount: '1000',
}),
expect.objectContaining({
id: expect.any(Number),
state: 'PENDING',
memo: 'Test env contribution',
amount: '100',
}),
]),
},
},
}),
)
})
it('returns all CONFIRMED contributions', async () => {
await expect(
query({
query: listAllContributions,
variables: {
currentPage: 1,
pageSize: 25,
order: 'DESC',
statusFilter: ['CONFIRMED'],
},
}),
).resolves.toEqual(
expect.objectContaining({
data: {
listAllContributions: {
contributionCount: 1,
contributionList: expect.arrayContaining([
expect.objectContaining({
id: expect.any(Number),
state: 'CONFIRMED',
memo: 'Herzlich Willkommen bei Gradido!',
amount: '1000',
}),
expect.not.objectContaining({
id: expect.any(Number),
state: 'PENDING',
memo: 'Test env contribution',
amount: '100',
}),
]),
},
},
}),
)
})
it('returns all PENDING contributions', async () => {
await expect(
query({
query: listAllContributions,
variables: {
currentPage: 1,
pageSize: 25,
order: 'DESC',
statusFilter: ['PENDING'],
},
}),
).resolves.toEqual(
expect.objectContaining({
data: {
listAllContributions: {
contributionCount: 1,
contributionList: expect.arrayContaining([
expect.not.objectContaining({
id: expect.any(Number),
state: 'CONFIRMED',
memo: 'Herzlich Willkommen bei Gradido!',
amount: '1000',
}),
expect.objectContaining({
id: expect.any(Number),
state: 'PENDING',
memo: 'Test env contribution',
amount: '100',
}),
]),
},
},
}),
)
})
it('returns all IN_PROGRESS Creation', async () => {
await expect(
query({
query: listAllContributions,
variables: {
currentPage: 1,
pageSize: 25,
order: 'DESC',
statusFilter: ['IN_PROGRESS'],
},
}),
).resolves.toEqual(
expect.objectContaining({
data: {
listAllContributions: {
contributionCount: 0,
contributionList: expect.not.arrayContaining([
expect.objectContaining({
id: expect.any(Number),
state: 'CONFIRMED',
memo: 'Herzlich Willkommen bei Gradido!',
amount: '1000',
}),
expect.objectContaining({
id: expect.any(Number),
state: 'PENDING',
memo: 'Test env contribution',
amount: '100',
}),
]),
},
},
}),
)
})
it('returns all DENIED Creation', async () => {
await expect(
query({
query: listAllContributions,
variables: {
currentPage: 1,
pageSize: 25,
order: 'DESC',
statusFilter: ['DENIED'],
},
}),
).resolves.toEqual(
expect.objectContaining({
data: {
listAllContributions: {
contributionCount: 0,
contributionList: expect.not.arrayContaining([
expect.objectContaining({
id: expect.any(Number),
state: 'CONFIRMED',
memo: 'Herzlich Willkommen bei Gradido!',
amount: '1000',
}),
expect.objectContaining({
id: expect.any(Number),
state: 'PENDING',
memo: 'Test env contribution',
amount: '100',
}),
]),
},
},
}),
)
})
it('returns all DELETED Creation', async () => {
await expect(
query({
query: listAllContributions,
variables: {
currentPage: 1,
pageSize: 25,
order: 'DESC',
statusFilter: ['DELETED'],
},
}),
).resolves.toEqual(
expect.objectContaining({
data: {
listAllContributions: {
contributionCount: 0,
contributionList: expect.not.arrayContaining([
expect.objectContaining({
id: expect.any(Number),
state: 'CONFIRMED',
memo: 'Herzlich Willkommen bei Gradido!',
amount: '1000',
}),
expect.objectContaining({
id: expect.any(Number),
state: 'PENDING',
memo: 'Test env contribution',
amount: '100',
}),
]),
},
},
}),
)
})
it('returns all CONFIRMED and PENDING Creation', async () => {
await expect(
query({
query: listAllContributions,
variables: {
currentPage: 1,
pageSize: 25,
order: 'DESC',
statusFilter: ['CONFIRMED', 'PENDING'],
},
}),
).resolves.toEqual(
expect.objectContaining({
data: {
listAllContributions: {
contributionCount: 2,
contributionList: expect.arrayContaining([
expect.objectContaining({
id: expect.any(Number),
state: 'CONFIRMED',
memo: 'Herzlich Willkommen bei Gradido!',
amount: '1000',
}),
expect.objectContaining({
id: expect.any(Number),
state: 'PENDING',
memo: 'Test env contribution', memo: 'Test env contribution',
amount: '100', amount: '100',
}), }),

View File

@ -179,12 +179,23 @@ export class ContributionResolver {
async listAllContributions( async listAllContributions(
@Args() @Args()
{ currentPage = 1, pageSize = 5, order = Order.DESC }: Paginated, { currentPage = 1, pageSize = 5, order = Order.DESC }: Paginated,
@Arg('statusFilter', () => [ContributionStatus], { nullable: true })
statusFilter?: ContributionStatus[],
): Promise<ContributionListResult> { ): Promise<ContributionListResult> {
const where: {
contributionStatus?: FindOperator<string> | null
} = {}
if (statusFilter && statusFilter.length) {
where.contributionStatus = In(statusFilter)
}
const [dbContributions, count] = await getConnection() const [dbContributions, count] = await getConnection()
.createQueryBuilder() .createQueryBuilder()
.select('c') .select('c')
.from(DbContribution, 'c') .from(DbContribution, 'c')
.innerJoinAndSelect('c.user', 'u') .innerJoinAndSelect('c.user', 'u')
.where(where)
.orderBy('c.createdAt', order) .orderBy('c.createdAt', order)
.limit(pageSize) .limit(pageSize)
.offset((currentPage - 1) * pageSize) .offset((currentPage - 1) * pageSize)

View File

@ -172,8 +172,8 @@ export const listContributions = gql`
` `
export const listAllContributions = ` export const listAllContributions = `
query ($currentPage: Int = 1, $pageSize: Int = 5, $order: Order = DESC) { query ($currentPage: Int = 1, $pageSize: Int = 5, $order: Order = DESC, $statusFilter: [ContributionStatus!]) {
listAllContributions(currentPage: $currentPage, pageSize: $pageSize, order: $order) { listAllContributions(currentPage: $currentPage, pageSize: $pageSize, order: $order, statusFilter: $statusFilter) {
contributionCount contributionCount
contributionList { contributionList {
id id
@ -184,6 +184,11 @@ query ($currentPage: Int = 1, $pageSize: Int = 5, $order: Order = DESC) {
createdAt createdAt
confirmedAt confirmedAt
confirmedBy confirmedBy
contributionDate
state
messagesCount
deniedAt
deniedBy
} }
} }
} }

View File

@ -3,7 +3,7 @@
<b-form <b-form
ref="form" ref="form"
@submit.prevent="submit" @submit.prevent="submit"
class="p-3 bg-white appBoxShadow gradido-border-radius" class="form-style p-3 bg-white appBoxShadow gradido-border-radius"
> >
<label>{{ $t('contribution.selectDate') }}</label> <label>{{ $t('contribution.selectDate') }}</label>
<b-form-datepicker <b-form-datepicker
@ -23,6 +23,13 @@
<template #nav-next-year><span></span></template> <template #nav-next-year><span></span></template>
</b-form-datepicker> </b-form-datepicker>
<div
v-if="(isThisMonth && maxGddThisMonth <= 0) || (!isThisMonth && maxGddLastMonth <= 0)"
class="p-3"
>
{{ noOpenCreation }}
</div>
<div v-else>
<input-textarea <input-textarea
id="contribution-memo" id="contribution-memo"
v-model="form.memo" v-model="form.memo"
@ -56,17 +63,30 @@
></input-amount> ></input-amount>
<b-row class="mt-5"> <b-row class="mt-5">
<b-col> <b-col cols="12" lg="6">
<b-button type="reset" variant="secondary" @click="reset" data-test="button-cancel"> <b-button
block
type="reset"
variant="secondary"
@click="reset"
data-test="button-cancel"
>
{{ $t('form.cancel') }} {{ $t('form.cancel') }}
</b-button> </b-button>
</b-col> </b-col>
<b-col class="text-right"> <b-col cols="12" lg="6" class="text-right mt-4 mt-lg-0">
<b-button type="submit" variant="gradido" :disabled="disabled" data-test="button-submit"> <b-button
block
type="submit"
variant="gradido"
:disabled="disabled"
data-test="button-submit"
>
{{ form.id ? $t('form.change') : $t('contribution.submit') }} {{ form.id ? $t('form.change') : $t('contribution.submit') }}
</b-button> </b-button>
</b-col> </b-col>
</b-row> </b-row>
</div>
</b-form> </b-form>
</div> </div>
</template> </template>
@ -133,6 +153,18 @@ export default {
validMaxTime() { validMaxTime() {
return Number(this.validMaxGDD / 20) return Number(this.validMaxGDD / 20)
}, },
noOpenCreation() {
if (this.maxGddThisMonth <= 0 && this.maxGddLastMonth <= 0) {
return this.$t('contribution.noOpenCreation.allMonth')
}
if (this.isThisMonth && this.maxGddThisMonth <= 0) {
return this.$t('contribution.noOpenCreation.thisMonth')
}
if (!this.isThisMonth && this.maxGddLastMonth <= 0) {
return this.$t('contribution.noOpenCreation.lastMonth')
}
return ''
},
}, },
watch: { watch: {
value() { value() {
@ -142,6 +174,9 @@ export default {
} }
</script> </script>
<style> <style>
.form-style {
min-height: 410px;
}
span.errors { span.errors {
color: red; color: red;
} }

View File

@ -57,7 +57,16 @@
"yourContribution": "Dein Beitrag zum Gemeinwohl" "yourContribution": "Dein Beitrag zum Gemeinwohl"
}, },
"lastContribution": "Letzte Beiträge", "lastContribution": "Letzte Beiträge",
"noContributions": {
"allContributions": "Es wurden noch keine Beiträge eingereicht.",
"myContributions": "Du hast noch keine Beiträge eingereicht."
},
"noDateSelected": "Wähle irgendein Datum im Monat", "noDateSelected": "Wähle irgendein Datum im Monat",
"noOpenCreation": {
"allMonth": "Für alle beiden Monate ist dein Schöpfungslimit erreicht. Den Nächsten Monat kannst du wieder 1000 GDD Schöpfen.",
"lastMonth": "Für den ausgewählten Monat ist das Schöpfungslimit erreicht.",
"thisMonth": "Für den aktuellen Monat ist das Schöpfungslimit erreicht."
},
"selectDate": "Wann war dein Beitrag?", "selectDate": "Wann war dein Beitrag?",
"submit": "Einreichen", "submit": "Einreichen",
"submitted": "Der Beitrag wurde eingereicht.", "submitted": "Der Beitrag wurde eingereicht.",

View File

@ -57,7 +57,16 @@
"yourContribution": "Your Contributions to the Common Good" "yourContribution": "Your Contributions to the Common Good"
}, },
"lastContribution": "Last Contributions", "lastContribution": "Last Contributions",
"noContributions": {
"allContributions": "No contributions have been submitted yet.",
"myContributions": "You have not submitted any entries yet."
},
"noDateSelected": "Choose any date in the month", "noDateSelected": "Choose any date in the month",
"noOpenCreation": {
"allMonth": "For all two months your creation limit is reached. The next month you can create 1000 GDD again.",
"lastMonth": "The creation limit is reached for the selected month.",
"thisMonth": "The creation limit has been reached for the current month."
},
"selectDate": "When was your contribution?", "selectDate": "When was your contribution?",
"submit": "Submit", "submit": "Submit",
"submitted": "The contribution was submitted.", "submitted": "The contribution was submitted.",

View File

@ -20,6 +20,10 @@
/> />
</b-tab> </b-tab>
<b-tab no-body> <b-tab no-body>
<div v-if="items.length === 0">
{{ $t('contribution.noContributions.myContributions') }}
</div>
<div v-else>
<contribution-list <contribution-list
@closeAllOpenCollapse="closeAllOpenCollapse" @closeAllOpenCollapse="closeAllOpenCollapse"
:items="items" :items="items"
@ -31,8 +35,13 @@
:showPagination="true" :showPagination="true"
:pageSize="pageSize" :pageSize="pageSize"
/> />
</div>
</b-tab> </b-tab>
<b-tab no-body> <b-tab no-body>
<div v-if="itemsAll.length === 0">
{{ $t('contribution.noContributions.allContributions') }}
</div>
<div v-else>
<contribution-list <contribution-list
:items="itemsAll" :items="itemsAll"
@update-list-contributions="updateListAllContributions" @update-list-contributions="updateListAllContributions"
@ -42,6 +51,7 @@
:pageSize="pageSizeAll" :pageSize="pageSizeAll"
:allContribution="true" :allContribution="true"
/> />
</div>
</b-tab> </b-tab>
</b-tabs> </b-tabs>
</div> </div>