mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
Merge branch 'master' into remove-adminCreateContributions
This commit is contained in:
commit
6e88068a88
@ -22,7 +22,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
listAllContributions,
|
listAllContributions,
|
||||||
listContributions,
|
listContributions,
|
||||||
listUnconfirmedContributions,
|
adminListAllContributions,
|
||||||
} from '@/seeds/graphql/queries'
|
} from '@/seeds/graphql/queries'
|
||||||
import { sendContributionConfirmedEmail } from '@/emails/sendEmailVariants'
|
import { sendContributionConfirmedEmail } from '@/emails/sendEmailVariants'
|
||||||
import {
|
import {
|
||||||
@ -45,9 +45,10 @@ 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'
|
import { UserInputError } from 'apollo-server-express'
|
||||||
import { raeuberHotzenplotz } from '@/seeds/users/raeuber-hotzenplotz'
|
import { raeuberHotzenplotz } from '@/seeds/users/raeuber-hotzenplotz'
|
||||||
import { UnconfirmedContribution } from '../model/UnconfirmedContribution'
|
import { UnconfirmedContribution } from '@model/UnconfirmedContribution'
|
||||||
import { ContributionListResult } from '../model/Contribution'
|
import { ContributionListResult } from '@model/Contribution'
|
||||||
import { ContributionStatus } from '../enum/ContributionStatus'
|
import { ContributionStatus } from '@enum/ContributionStatus'
|
||||||
|
import { Order } from '@enum/Order'
|
||||||
|
|
||||||
// mock account activation email to avoid console spam
|
// mock account activation email to avoid console spam
|
||||||
jest.mock('@/emails/sendEmailVariants', () => {
|
jest.mock('@/emails/sendEmailVariants', () => {
|
||||||
@ -876,6 +877,7 @@ describe('ContributionResolver', () => {
|
|||||||
|
|
||||||
describe('other user sends a deleteContribution', () => {
|
describe('other user sends a deleteContribution', () => {
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
|
jest.clearAllMocks()
|
||||||
await mutate({
|
await mutate({
|
||||||
mutation: login,
|
mutation: login,
|
||||||
variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
|
variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
|
||||||
@ -887,7 +889,6 @@ describe('ContributionResolver', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('returns an error', async () => {
|
it('returns an error', async () => {
|
||||||
jest.clearAllMocks()
|
|
||||||
const { errors: errorObjects }: { errors: [GraphQLError] } = await mutate({
|
const { errors: errorObjects }: { errors: [GraphQLError] } = await mutate({
|
||||||
mutation: deleteContribution,
|
mutation: deleteContribution,
|
||||||
variables: {
|
variables: {
|
||||||
@ -910,6 +911,7 @@ describe('ContributionResolver', () => {
|
|||||||
|
|
||||||
describe('User deletes own contribution', () => {
|
describe('User deletes own contribution', () => {
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
|
jest.clearAllMocks()
|
||||||
await mutate({
|
await mutate({
|
||||||
mutation: login,
|
mutation: login,
|
||||||
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
|
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
|
||||||
@ -1673,20 +1675,6 @@ describe('ContributionResolver', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('listUnconfirmedContributions', () => {
|
|
||||||
it('returns an error', async () => {
|
|
||||||
await expect(
|
|
||||||
query({
|
|
||||||
query: listUnconfirmedContributions,
|
|
||||||
}),
|
|
||||||
).resolves.toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
errors: [new GraphQLError('401 Unauthorized')],
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('adminDeleteContribution', () => {
|
describe('adminDeleteContribution', () => {
|
||||||
it('returns an error', async () => {
|
it('returns an error', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
@ -1766,20 +1754,6 @@ describe('ContributionResolver', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('listUnconfirmedContributions', () => {
|
|
||||||
it('returns an error', async () => {
|
|
||||||
await expect(
|
|
||||||
query({
|
|
||||||
query: listUnconfirmedContributions,
|
|
||||||
}),
|
|
||||||
).resolves.toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
errors: [new GraphQLError('401 Unauthorized')],
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('adminDeleteContribution', () => {
|
describe('adminDeleteContribution', () => {
|
||||||
it('returns an error', async () => {
|
it('returns an error', async () => {
|
||||||
await expect(
|
await expect(
|
||||||
@ -2328,72 +2302,6 @@ describe('ContributionResolver', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('listUnconfirmedContributions', () => {
|
|
||||||
it('returns four pending creations', async () => {
|
|
||||||
await expect(
|
|
||||||
query({
|
|
||||||
query: listUnconfirmedContributions,
|
|
||||||
}),
|
|
||||||
).resolves.toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
data: {
|
|
||||||
listUnconfirmedContributions: expect.arrayContaining([
|
|
||||||
expect.objectContaining({
|
|
||||||
id: expect.any(Number),
|
|
||||||
firstName: 'Peter',
|
|
||||||
lastName: 'Lustig',
|
|
||||||
email: 'peter@lustig.de',
|
|
||||||
date: expect.any(String),
|
|
||||||
memo: 'Das war leider zu Viel!',
|
|
||||||
amount: '200',
|
|
||||||
moderator: admin.id,
|
|
||||||
creation: ['1000', '800', '1000'],
|
|
||||||
}),
|
|
||||||
expect.not.objectContaining({
|
|
||||||
email: 'bibi@bloxberg.de',
|
|
||||||
memo: 'Test contribution to delete',
|
|
||||||
amount: '100',
|
|
||||||
}),
|
|
||||||
expect.objectContaining({
|
|
||||||
id: expect.any(Number),
|
|
||||||
firstName: 'Bibi',
|
|
||||||
lastName: 'Bloxberg',
|
|
||||||
email: 'bibi@bloxberg.de',
|
|
||||||
date: expect.any(String),
|
|
||||||
memo: 'Test PENDING contribution update',
|
|
||||||
amount: '10',
|
|
||||||
moderator: null,
|
|
||||||
creation: ['1000', '1000', '590'],
|
|
||||||
}),
|
|
||||||
expect.objectContaining({
|
|
||||||
id: expect.any(Number),
|
|
||||||
firstName: 'Bibi',
|
|
||||||
lastName: 'Bloxberg',
|
|
||||||
email: 'bibi@bloxberg.de',
|
|
||||||
date: expect.any(String),
|
|
||||||
memo: 'Test IN_PROGRESS contribution',
|
|
||||||
amount: '100',
|
|
||||||
moderator: null,
|
|
||||||
creation: ['1000', '1000', '590'],
|
|
||||||
}),
|
|
||||||
expect.objectContaining({
|
|
||||||
id: expect.any(Number),
|
|
||||||
firstName: 'Bibi',
|
|
||||||
lastName: 'Bloxberg',
|
|
||||||
email: 'bibi@bloxberg.de',
|
|
||||||
date: expect.any(String),
|
|
||||||
memo: 'Aktives Grundeinkommen',
|
|
||||||
amount: '200',
|
|
||||||
moderator: admin.id,
|
|
||||||
creation: ['1000', '1000', '590'],
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('adminDeleteContribution', () => {
|
describe('adminDeleteContribution', () => {
|
||||||
describe('creation id does not exist', () => {
|
describe('creation id does not exist', () => {
|
||||||
it('throws an error', async () => {
|
it('throws an error', async () => {
|
||||||
@ -2734,4 +2642,320 @@ describe('ContributionResolver', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('adminListAllContribution', () => {
|
||||||
|
describe('unauthenticated', () => {
|
||||||
|
it('returns an error', async () => {
|
||||||
|
await expect(
|
||||||
|
query({
|
||||||
|
query: adminListAllContributions,
|
||||||
|
}),
|
||||||
|
).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
errors: [new GraphQLError('401 Unauthorized')],
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('authenticated as user', () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
await mutate({
|
||||||
|
mutation: login,
|
||||||
|
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
resetToken()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns an error', async () => {
|
||||||
|
await expect(
|
||||||
|
query({
|
||||||
|
query: adminListAllContributions,
|
||||||
|
}),
|
||||||
|
).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
errors: [new GraphQLError('401 Unauthorized')],
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('authenticated as admin', () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
await mutate({
|
||||||
|
mutation: login,
|
||||||
|
variables: { email: 'peter@lustig.de', password: 'Aa12345_' },
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
resetToken()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns 19 creations in total', async () => {
|
||||||
|
const {
|
||||||
|
data: { adminListAllContributions: contributionListObject },
|
||||||
|
}: { data: { adminListAllContributions: ContributionListResult } } = await query({
|
||||||
|
query: adminListAllContributions,
|
||||||
|
})
|
||||||
|
expect(contributionListObject.contributionList).toHaveLength(19)
|
||||||
|
expect(contributionListObject).toMatchObject({
|
||||||
|
contributionCount: 19,
|
||||||
|
contributionList: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
amount: expect.decimalEqual(50),
|
||||||
|
firstName: 'Bibi',
|
||||||
|
id: expect.any(Number),
|
||||||
|
lastName: 'Bloxberg',
|
||||||
|
memo: 'Herzlich Willkommen bei Gradido liebe Bibi!',
|
||||||
|
messagesCount: 0,
|
||||||
|
state: 'CONFIRMED',
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
amount: expect.decimalEqual(50),
|
||||||
|
firstName: 'Bibi',
|
||||||
|
id: expect.any(Number),
|
||||||
|
lastName: 'Bloxberg',
|
||||||
|
memo: 'Herzlich Willkommen bei Gradido liebe Bibi!',
|
||||||
|
messagesCount: 0,
|
||||||
|
state: 'CONFIRMED',
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
amount: expect.decimalEqual(450),
|
||||||
|
firstName: 'Bibi',
|
||||||
|
id: expect.any(Number),
|
||||||
|
lastName: 'Bloxberg',
|
||||||
|
memo: 'Herzlich Willkommen bei Gradido liebe Bibi!',
|
||||||
|
messagesCount: 0,
|
||||||
|
state: 'CONFIRMED',
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
amount: expect.decimalEqual(100),
|
||||||
|
firstName: 'Bob',
|
||||||
|
id: expect.any(Number),
|
||||||
|
lastName: 'der Baumeister',
|
||||||
|
memo: 'Confirmed Contribution',
|
||||||
|
messagesCount: 0,
|
||||||
|
state: 'CONFIRMED',
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
amount: expect.decimalEqual(400),
|
||||||
|
firstName: 'Peter',
|
||||||
|
id: expect.any(Number),
|
||||||
|
lastName: 'Lustig',
|
||||||
|
memo: 'Herzlich Willkommen bei Gradido!',
|
||||||
|
messagesCount: 0,
|
||||||
|
state: 'PENDING',
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
amount: expect.decimalEqual(100),
|
||||||
|
firstName: 'Peter',
|
||||||
|
id: expect.any(Number),
|
||||||
|
lastName: 'Lustig',
|
||||||
|
memo: 'Test env contribution',
|
||||||
|
messagesCount: 0,
|
||||||
|
state: 'PENDING',
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
amount: expect.decimalEqual(200),
|
||||||
|
firstName: 'Bibi',
|
||||||
|
id: expect.any(Number),
|
||||||
|
lastName: 'Bloxberg',
|
||||||
|
memo: 'Aktives Grundeinkommen',
|
||||||
|
messagesCount: 0,
|
||||||
|
state: 'PENDING',
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
amount: expect.decimalEqual(500),
|
||||||
|
firstName: 'Bibi',
|
||||||
|
id: expect.any(Number),
|
||||||
|
lastName: 'Bloxberg',
|
||||||
|
memo: 'Grundeinkommen',
|
||||||
|
messagesCount: 0,
|
||||||
|
state: 'PENDING',
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
amount: expect.decimalEqual(500),
|
||||||
|
firstName: 'Peter',
|
||||||
|
id: expect.any(Number),
|
||||||
|
lastName: 'Lustig',
|
||||||
|
memo: 'Grundeinkommen',
|
||||||
|
messagesCount: 0,
|
||||||
|
state: 'PENDING',
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
amount: expect.decimalEqual(10),
|
||||||
|
firstName: 'Bibi',
|
||||||
|
id: expect.any(Number),
|
||||||
|
lastName: 'Bloxberg',
|
||||||
|
memo: 'Test PENDING contribution update',
|
||||||
|
messagesCount: 0,
|
||||||
|
state: 'PENDING',
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
amount: expect.decimalEqual(200),
|
||||||
|
firstName: 'Peter',
|
||||||
|
id: expect.any(Number),
|
||||||
|
lastName: 'Lustig',
|
||||||
|
memo: 'Das war leider zu Viel!',
|
||||||
|
messagesCount: 0,
|
||||||
|
state: 'DELETED',
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
amount: expect.decimalEqual(166),
|
||||||
|
firstName: 'Räuber',
|
||||||
|
id: expect.any(Number),
|
||||||
|
lastName: 'Hotzenplotz',
|
||||||
|
memo: 'Whatever contribution',
|
||||||
|
messagesCount: 0,
|
||||||
|
state: 'DELETED',
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
amount: expect.decimalEqual(166),
|
||||||
|
firstName: 'Räuber',
|
||||||
|
id: expect.any(Number),
|
||||||
|
lastName: 'Hotzenplotz',
|
||||||
|
memo: 'Whatever contribution',
|
||||||
|
messagesCount: 0,
|
||||||
|
state: 'DENIED',
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
amount: expect.decimalEqual(166),
|
||||||
|
firstName: 'Räuber',
|
||||||
|
id: expect.any(Number),
|
||||||
|
lastName: 'Hotzenplotz',
|
||||||
|
memo: 'Whatever contribution',
|
||||||
|
messagesCount: 0,
|
||||||
|
state: 'CONFIRMED',
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
amount: expect.decimalEqual(100),
|
||||||
|
firstName: 'Bibi',
|
||||||
|
id: expect.any(Number),
|
||||||
|
lastName: 'Bloxberg',
|
||||||
|
memo: 'Test IN_PROGRESS contribution',
|
||||||
|
messagesCount: 0,
|
||||||
|
state: 'IN_PROGRESS',
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
amount: expect.decimalEqual(100),
|
||||||
|
firstName: 'Bibi',
|
||||||
|
id: expect.any(Number),
|
||||||
|
lastName: 'Bloxberg',
|
||||||
|
memo: 'Test contribution to confirm',
|
||||||
|
messagesCount: 0,
|
||||||
|
state: 'CONFIRMED',
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
amount: expect.decimalEqual(100),
|
||||||
|
firstName: 'Bibi',
|
||||||
|
id: expect.any(Number),
|
||||||
|
lastName: 'Bloxberg',
|
||||||
|
memo: 'Test contribution to deny',
|
||||||
|
messagesCount: 0,
|
||||||
|
state: 'DENIED',
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
amount: expect.decimalEqual(100),
|
||||||
|
firstName: 'Bibi',
|
||||||
|
id: expect.any(Number),
|
||||||
|
lastName: 'Bloxberg',
|
||||||
|
memo: 'Test contribution to delete',
|
||||||
|
messagesCount: 0,
|
||||||
|
state: 'DELETED',
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
amount: expect.decimalEqual(1000),
|
||||||
|
firstName: 'Bibi',
|
||||||
|
id: expect.any(Number),
|
||||||
|
lastName: 'Bloxberg',
|
||||||
|
memo: 'Herzlich Willkommen bei Gradido!',
|
||||||
|
messagesCount: 0,
|
||||||
|
state: 'CONFIRMED',
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns five pending creations with page size set to 5', async () => {
|
||||||
|
const {
|
||||||
|
data: { adminListAllContributions: contributionListObject },
|
||||||
|
}: { data: { adminListAllContributions: ContributionListResult } } = await query({
|
||||||
|
query: adminListAllContributions,
|
||||||
|
variables: {
|
||||||
|
currentPage: 1,
|
||||||
|
pageSize: 5,
|
||||||
|
order: Order.DESC,
|
||||||
|
statusFilter: ['PENDING'],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
expect(contributionListObject.contributionList).toHaveLength(5)
|
||||||
|
expect(contributionListObject).toMatchObject({
|
||||||
|
contributionCount: 6,
|
||||||
|
contributionList: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
amount: '400',
|
||||||
|
firstName: 'Peter',
|
||||||
|
id: expect.any(Number),
|
||||||
|
lastName: 'Lustig',
|
||||||
|
memo: 'Herzlich Willkommen bei Gradido!',
|
||||||
|
messagesCount: 0,
|
||||||
|
state: 'PENDING',
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
amount: '200',
|
||||||
|
firstName: 'Bibi',
|
||||||
|
id: expect.any(Number),
|
||||||
|
lastName: 'Bloxberg',
|
||||||
|
memo: 'Aktives Grundeinkommen',
|
||||||
|
messagesCount: 0,
|
||||||
|
state: 'PENDING',
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
amount: '500',
|
||||||
|
firstName: 'Bibi',
|
||||||
|
id: expect.any(Number),
|
||||||
|
lastName: 'Bloxberg',
|
||||||
|
memo: 'Grundeinkommen',
|
||||||
|
messagesCount: 0,
|
||||||
|
state: 'PENDING',
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
amount: '500',
|
||||||
|
firstName: 'Peter',
|
||||||
|
id: expect.any(Number),
|
||||||
|
lastName: 'Lustig',
|
||||||
|
memo: 'Grundeinkommen',
|
||||||
|
messagesCount: 0,
|
||||||
|
state: 'PENDING',
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
amount: '100',
|
||||||
|
firstName: 'Peter',
|
||||||
|
id: expect.any(Number),
|
||||||
|
lastName: 'Lustig',
|
||||||
|
memo: 'Test env contribution',
|
||||||
|
messagesCount: 0,
|
||||||
|
state: 'PENDING',
|
||||||
|
}),
|
||||||
|
expect.not.objectContaining({
|
||||||
|
state: 'DENIED',
|
||||||
|
}),
|
||||||
|
expect.not.objectContaining({
|
||||||
|
state: 'DELETED',
|
||||||
|
}),
|
||||||
|
expect.not.objectContaining({
|
||||||
|
state: 'CONFIRMED',
|
||||||
|
}),
|
||||||
|
expect.not.objectContaining({
|
||||||
|
state: 'IN_PROGRESS',
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import Decimal from 'decimal.js-light'
|
import Decimal from 'decimal.js-light'
|
||||||
import { Arg, Args, Authorized, Ctx, Int, Mutation, Query, Resolver } from 'type-graphql'
|
import { Arg, Args, Authorized, Ctx, Int, Mutation, Query, Resolver } from 'type-graphql'
|
||||||
import { FindOperator, IsNull, In, getConnection } from '@dbTools/typeorm'
|
import { FindOperator, IsNull, getConnection } from '@dbTools/typeorm'
|
||||||
|
|
||||||
import { Contribution as DbContribution } from '@entity/Contribution'
|
import { Contribution as DbContribution } from '@entity/Contribution'
|
||||||
import { ContributionMessage } from '@entity/ContributionMessage'
|
import { ContributionMessage } from '@entity/ContributionMessage'
|
||||||
@ -29,12 +29,11 @@ import { backendLogger as logger } from '@/server/logger'
|
|||||||
import {
|
import {
|
||||||
getCreationDates,
|
getCreationDates,
|
||||||
getUserCreation,
|
getUserCreation,
|
||||||
getUserCreations,
|
|
||||||
validateContribution,
|
validateContribution,
|
||||||
updateCreations,
|
updateCreations,
|
||||||
isValidDateString,
|
isValidDateString,
|
||||||
} from './util/creations'
|
} from './util/creations'
|
||||||
import { MEMO_MAX_CHARS, MEMO_MIN_CHARS, FULL_CREATION_AVAILABLE } from './const/const'
|
import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const'
|
||||||
import {
|
import {
|
||||||
EVENT_CONTRIBUTION_CREATE,
|
EVENT_CONTRIBUTION_CREATE,
|
||||||
EVENT_CONTRIBUTION_DELETE,
|
EVENT_CONTRIBUTION_DELETE,
|
||||||
@ -55,6 +54,7 @@ import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK'
|
|||||||
import LogError from '@/server/LogError'
|
import LogError from '@/server/LogError'
|
||||||
|
|
||||||
import { getLastTransaction } from './util/getLastTransaction'
|
import { getLastTransaction } from './util/getLastTransaction'
|
||||||
|
import { findContributions } from './util/findContributions'
|
||||||
|
|
||||||
@Resolver()
|
@Resolver()
|
||||||
export class ContributionResolver {
|
export class ContributionResolver {
|
||||||
@ -167,25 +167,14 @@ export class ContributionResolver {
|
|||||||
@Arg('statusFilter', () => [ContributionStatus], { nullable: true })
|
@Arg('statusFilter', () => [ContributionStatus], { nullable: true })
|
||||||
statusFilter?: ContributionStatus[],
|
statusFilter?: ContributionStatus[],
|
||||||
): Promise<ContributionListResult> {
|
): Promise<ContributionListResult> {
|
||||||
const where: {
|
const [dbContributions, count] = await findContributions(
|
||||||
contributionStatus?: FindOperator<string> | null
|
order,
|
||||||
} = {}
|
currentPage,
|
||||||
|
pageSize,
|
||||||
|
false,
|
||||||
|
statusFilter,
|
||||||
|
)
|
||||||
|
|
||||||
if (statusFilter && statusFilter.length) {
|
|
||||||
where.contributionStatus = In(statusFilter)
|
|
||||||
}
|
|
||||||
|
|
||||||
const [dbContributions, count] = await getConnection()
|
|
||||||
.createQueryBuilder()
|
|
||||||
.select('c')
|
|
||||||
.from(DbContribution, 'c')
|
|
||||||
.innerJoinAndSelect('c.user', 'u')
|
|
||||||
.leftJoinAndSelect('c.messages', 'm')
|
|
||||||
.where(where)
|
|
||||||
.orderBy('c.createdAt', order)
|
|
||||||
.limit(pageSize)
|
|
||||||
.offset((currentPage - 1) * pageSize)
|
|
||||||
.getManyAndCount()
|
|
||||||
return new ContributionListResult(
|
return new ContributionListResult(
|
||||||
count,
|
count,
|
||||||
dbContributions.map((contribution) => new Contribution(contribution, contribution.user)),
|
dbContributions.map((contribution) => new Contribution(contribution, contribution.user)),
|
||||||
@ -397,40 +386,25 @@ export class ContributionResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Authorized([RIGHTS.LIST_UNCONFIRMED_CONTRIBUTIONS])
|
@Authorized([RIGHTS.LIST_UNCONFIRMED_CONTRIBUTIONS])
|
||||||
@Query(() => [UnconfirmedContribution])
|
@Query(() => ContributionListResult) // [UnconfirmedContribution]
|
||||||
async listUnconfirmedContributions(@Ctx() context: Context): Promise<UnconfirmedContribution[]> {
|
async adminListAllContributions(
|
||||||
const clientTimezoneOffset = getClientTimezoneOffset(context)
|
@Args()
|
||||||
const contributions = await getConnection()
|
{ currentPage = 1, pageSize = 3, order = Order.DESC }: Paginated,
|
||||||
.createQueryBuilder()
|
@Arg('statusFilter', () => [ContributionStatus], { nullable: true })
|
||||||
.select('c')
|
statusFilter?: ContributionStatus[],
|
||||||
.from(DbContribution, 'c')
|
): Promise<ContributionListResult> {
|
||||||
.leftJoinAndSelect('c.messages', 'm')
|
const [dbContributions, count] = await findContributions(
|
||||||
.where({ confirmedAt: IsNull() })
|
order,
|
||||||
.andWhere({ deniedAt: IsNull() })
|
currentPage,
|
||||||
.getMany()
|
pageSize,
|
||||||
|
true,
|
||||||
|
statusFilter,
|
||||||
|
)
|
||||||
|
|
||||||
if (contributions.length === 0) {
|
return new ContributionListResult(
|
||||||
return []
|
count,
|
||||||
}
|
dbContributions.map((contribution) => new Contribution(contribution, contribution.user)),
|
||||||
|
)
|
||||||
const userIds = contributions.map((p) => p.userId)
|
|
||||||
const userCreations = await getUserCreations(userIds, clientTimezoneOffset)
|
|
||||||
const users = await DbUser.find({
|
|
||||||
where: { id: In(userIds) },
|
|
||||||
withDeleted: true,
|
|
||||||
relations: ['emailContact'],
|
|
||||||
})
|
|
||||||
|
|
||||||
return contributions.map((contribution) => {
|
|
||||||
const user = users.find((u) => u.id === contribution.userId)
|
|
||||||
const creation = userCreations.find((c) => c.id === contribution.userId)
|
|
||||||
|
|
||||||
return new UnconfirmedContribution(
|
|
||||||
contribution,
|
|
||||||
user,
|
|
||||||
creation ? creation.creations : FULL_CREATION_AVAILABLE,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Authorized([RIGHTS.ADMIN_DELETE_CONTRIBUTION])
|
@Authorized([RIGHTS.ADMIN_DELETE_CONTRIBUTION])
|
||||||
|
|||||||
24
backend/src/graphql/resolver/util/findContributions.ts
Normal file
24
backend/src/graphql/resolver/util/findContributions.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { ContributionStatus } from '@enum/ContributionStatus'
|
||||||
|
import { Order } from '@enum/Order'
|
||||||
|
import { Contribution as DbContribution } from '@entity/Contribution'
|
||||||
|
import { In } from '@dbTools/typeorm'
|
||||||
|
|
||||||
|
export const findContributions = async (
|
||||||
|
order: Order,
|
||||||
|
currentPage: number,
|
||||||
|
pageSize: number,
|
||||||
|
withDeleted: boolean,
|
||||||
|
statusFilter?: ContributionStatus[],
|
||||||
|
): Promise<[DbContribution[], number]> =>
|
||||||
|
DbContribution.findAndCount({
|
||||||
|
where: {
|
||||||
|
...(statusFilter && statusFilter.length && { contributionStatus: In(statusFilter) }),
|
||||||
|
},
|
||||||
|
withDeleted: withDeleted,
|
||||||
|
order: {
|
||||||
|
createdAt: order,
|
||||||
|
},
|
||||||
|
relations: ['user'],
|
||||||
|
skip: (currentPage - 1) * pageSize,
|
||||||
|
take: pageSize,
|
||||||
|
})
|
||||||
@ -186,6 +186,40 @@ query ($currentPage: Int = 1, $pageSize: Int = 5, $order: Order = DESC, $statusF
|
|||||||
contributionCount
|
contributionCount
|
||||||
contributionList {
|
contributionList {
|
||||||
id
|
id
|
||||||
|
firstName
|
||||||
|
lastName
|
||||||
|
amount
|
||||||
|
memo
|
||||||
|
createdAt
|
||||||
|
confirmedAt
|
||||||
|
confirmedBy
|
||||||
|
contributionDate
|
||||||
|
state
|
||||||
|
messagesCount
|
||||||
|
deniedAt
|
||||||
|
deniedBy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
// from admin interface
|
||||||
|
|
||||||
|
export const adminListAllContributions = gql`
|
||||||
|
query (
|
||||||
|
$currentPage: Int = 1
|
||||||
|
$pageSize: Int = 25
|
||||||
|
$order: Order = DESC
|
||||||
|
$statusFilter: [ContributionStatus!]
|
||||||
|
) {
|
||||||
|
adminListAllContributions(
|
||||||
|
currentPage: $currentPage
|
||||||
|
pageSize: $pageSize
|
||||||
|
order: $order
|
||||||
|
statusFilter: $statusFilter
|
||||||
|
) {
|
||||||
|
contributionCount
|
||||||
|
contributionList {
|
||||||
|
id
|
||||||
firstName
|
firstName
|
||||||
lastName
|
lastName
|
||||||
amount
|
amount
|
||||||
@ -198,24 +232,7 @@ query ($currentPage: Int = 1, $pageSize: Int = 5, $order: Order = DESC, $statusF
|
|||||||
messagesCount
|
messagesCount
|
||||||
deniedAt
|
deniedAt
|
||||||
deniedBy
|
deniedBy
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
// from admin interface
|
|
||||||
|
|
||||||
export const listUnconfirmedContributions = gql`
|
|
||||||
query {
|
|
||||||
listUnconfirmedContributions {
|
|
||||||
id
|
|
||||||
firstName
|
|
||||||
lastName
|
|
||||||
email
|
|
||||||
amount
|
|
||||||
memo
|
|
||||||
date
|
|
||||||
moderator
|
|
||||||
creation
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user