mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
Merge pull request #2031 from gradido/2000-contribution-list
feat: implement contribution list query
This commit is contained in:
commit
f852c97995
@ -26,6 +26,7 @@ export enum RIGHTS {
|
|||||||
LIST_TRANSACTION_LINKS = 'LIST_TRANSACTION_LINKS',
|
LIST_TRANSACTION_LINKS = 'LIST_TRANSACTION_LINKS',
|
||||||
GDT_BALANCE = 'GDT_BALANCE',
|
GDT_BALANCE = 'GDT_BALANCE',
|
||||||
CREATE_CONTRIBUTION = 'CREATE_CONTRIBUTION',
|
CREATE_CONTRIBUTION = 'CREATE_CONTRIBUTION',
|
||||||
|
LIST_CONTRIBUTIONS = 'LIST_CONTRIBUTIONS',
|
||||||
// Admin
|
// Admin
|
||||||
SEARCH_USERS = 'SEARCH_USERS',
|
SEARCH_USERS = 'SEARCH_USERS',
|
||||||
SET_USER_ROLE = 'SET_USER_ROLE',
|
SET_USER_ROLE = 'SET_USER_ROLE',
|
||||||
|
|||||||
@ -24,6 +24,7 @@ export const ROLE_USER = new Role('user', [
|
|||||||
RIGHTS.LIST_TRANSACTION_LINKS,
|
RIGHTS.LIST_TRANSACTION_LINKS,
|
||||||
RIGHTS.GDT_BALANCE,
|
RIGHTS.GDT_BALANCE,
|
||||||
RIGHTS.CREATE_CONTRIBUTION,
|
RIGHTS.CREATE_CONTRIBUTION,
|
||||||
|
RIGHTS.LIST_CONTRIBUTIONS,
|
||||||
])
|
])
|
||||||
export const ROLE_ADMIN = new Role('admin', Object.values(RIGHTS)) // all rights
|
export const ROLE_ADMIN = new Role('admin', Object.values(RIGHTS)) // all rights
|
||||||
|
|
||||||
|
|||||||
43
backend/src/graphql/model/Contribution.ts
Normal file
43
backend/src/graphql/model/Contribution.ts
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import { ObjectType, Field, Int } from 'type-graphql'
|
||||||
|
import Decimal from 'decimal.js-light'
|
||||||
|
import { Contribution as dbContribution } from '@entity/Contribution'
|
||||||
|
import { User } from './User'
|
||||||
|
|
||||||
|
@ObjectType()
|
||||||
|
export class Contribution {
|
||||||
|
constructor(contribution: dbContribution, user: User) {
|
||||||
|
this.id = contribution.id
|
||||||
|
this.user = user
|
||||||
|
this.amount = contribution.amount
|
||||||
|
this.memo = contribution.memo
|
||||||
|
this.createdAt = contribution.createdAt
|
||||||
|
this.deletedAt = contribution.deletedAt
|
||||||
|
}
|
||||||
|
|
||||||
|
@Field(() => Number)
|
||||||
|
id: number
|
||||||
|
|
||||||
|
@Field(() => User)
|
||||||
|
user: User
|
||||||
|
|
||||||
|
@Field(() => Decimal)
|
||||||
|
amount: Decimal
|
||||||
|
|
||||||
|
@Field(() => String)
|
||||||
|
memo: string
|
||||||
|
|
||||||
|
@Field(() => Date)
|
||||||
|
createdAt: Date
|
||||||
|
|
||||||
|
@Field(() => Date, { nullable: true })
|
||||||
|
deletedAt: Date | null
|
||||||
|
}
|
||||||
|
|
||||||
|
@ObjectType()
|
||||||
|
export class ContributionListResult {
|
||||||
|
@Field(() => Int)
|
||||||
|
linkCount: number
|
||||||
|
|
||||||
|
@Field(() => [Contribution])
|
||||||
|
linkList: Contribution[]
|
||||||
|
}
|
||||||
@ -3,10 +3,13 @@
|
|||||||
|
|
||||||
import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg'
|
import { bibiBloxberg } from '@/seeds/users/bibi-bloxberg'
|
||||||
import { createContribution } from '@/seeds/graphql/mutations'
|
import { createContribution } from '@/seeds/graphql/mutations'
|
||||||
import { login } from '@/seeds/graphql/queries'
|
import { listContributions, login } from '@/seeds/graphql/queries'
|
||||||
import { cleanDB, resetToken, testEnvironment } from '@test/helpers'
|
import { cleanDB, resetToken, testEnvironment } from '@test/helpers'
|
||||||
import { GraphQLError } from 'graphql'
|
import { GraphQLError } from 'graphql'
|
||||||
import { userFactory } from '@/seeds/factory/user'
|
import { userFactory } from '@/seeds/factory/user'
|
||||||
|
import { creationFactory } from '@/seeds/factory/creation'
|
||||||
|
import { creations } from '@/seeds/creation/index'
|
||||||
|
import { peterLustig } from '@/seeds/users/peter-lustig'
|
||||||
|
|
||||||
let mutate: any, query: any, con: any
|
let mutate: any, query: any, con: any
|
||||||
let testEnv: any
|
let testEnv: any
|
||||||
@ -111,6 +114,7 @@ describe('ContributionResolver', () => {
|
|||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
data: {
|
data: {
|
||||||
createContribution: {
|
createContribution: {
|
||||||
|
id: expect.any(Number),
|
||||||
amount: '100',
|
amount: '100',
|
||||||
memo: 'Test env contribution',
|
memo: 'Test env contribution',
|
||||||
},
|
},
|
||||||
@ -121,4 +125,109 @@ describe('ContributionResolver', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('listContributions', () => {
|
||||||
|
describe('unauthenticated', () => {
|
||||||
|
it('returns an error', async () => {
|
||||||
|
await expect(
|
||||||
|
query({
|
||||||
|
query: listContributions,
|
||||||
|
variables: {
|
||||||
|
currentPage: 1,
|
||||||
|
pageSize: 25,
|
||||||
|
order: 'DESC',
|
||||||
|
filterConfirmed: false,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
errors: [new GraphQLError('401 Unauthorized')],
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('authenticated', () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
await userFactory(testEnv, bibiBloxberg)
|
||||||
|
await userFactory(testEnv, peterLustig)
|
||||||
|
const bibisCreation = creations.find((creation) => creation.email === 'bibi@bloxberg.de')
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||||
|
await creationFactory(testEnv, bibisCreation!)
|
||||||
|
await query({
|
||||||
|
query: login,
|
||||||
|
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
|
||||||
|
})
|
||||||
|
await mutate({
|
||||||
|
mutation: createContribution,
|
||||||
|
variables: {
|
||||||
|
amount: 100.0,
|
||||||
|
memo: 'Test env contribution',
|
||||||
|
creationDate: new Date().toString(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('filter confirmed is false', () => {
|
||||||
|
it('returns creations', async () => {
|
||||||
|
await expect(
|
||||||
|
query({
|
||||||
|
query: listContributions,
|
||||||
|
variables: {
|
||||||
|
currentPage: 1,
|
||||||
|
pageSize: 25,
|
||||||
|
order: 'DESC',
|
||||||
|
filterConfirmed: false,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
data: {
|
||||||
|
listContributions: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.any(Number),
|
||||||
|
memo: 'Herzlich Willkommen bei Gradido!',
|
||||||
|
amount: '1000',
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.any(Number),
|
||||||
|
memo: 'Test env contribution',
|
||||||
|
amount: '100',
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('filter confirmed is true', () => {
|
||||||
|
it('returns only unconfirmed creations', async () => {
|
||||||
|
await expect(
|
||||||
|
query({
|
||||||
|
query: listContributions,
|
||||||
|
variables: {
|
||||||
|
currentPage: 1,
|
||||||
|
pageSize: 25,
|
||||||
|
order: 'DESC',
|
||||||
|
filterConfirmed: true,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
).resolves.toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
data: {
|
||||||
|
listContributions: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.any(Number),
|
||||||
|
memo: 'Test env contribution',
|
||||||
|
amount: '100',
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -1,10 +1,15 @@
|
|||||||
import { RIGHTS } from '@/auth/RIGHTS'
|
import { RIGHTS } from '@/auth/RIGHTS'
|
||||||
import { Context, getUser } from '@/server/context'
|
import { Context, getUser } from '@/server/context'
|
||||||
import { backendLogger as logger } from '@/server/logger'
|
import { backendLogger as logger } from '@/server/logger'
|
||||||
import { Contribution } from '@entity/Contribution'
|
import { Contribution as dbContribution } from '@entity/Contribution'
|
||||||
import { Args, Authorized, Ctx, Mutation, Resolver } from 'type-graphql'
|
import { Arg, Args, Authorized, Ctx, Mutation, Query, Resolver } from 'type-graphql'
|
||||||
import ContributionArgs from '../arg/ContributionArgs'
|
import { FindOperator, IsNull } from '@dbTools/typeorm'
|
||||||
import { UnconfirmedContribution } from '../model/UnconfirmedContribution'
|
import ContributionArgs from '@arg/ContributionArgs'
|
||||||
|
import Paginated from '@arg/Paginated'
|
||||||
|
import { Order } from '@enum/Order'
|
||||||
|
import { Contribution } from '@model/Contribution'
|
||||||
|
import { UnconfirmedContribution } from '@model/UnconfirmedContribution'
|
||||||
|
import { User } from '@model/User'
|
||||||
import { validateContribution, getUserCreation } from './util/creations'
|
import { validateContribution, getUserCreation } from './util/creations'
|
||||||
|
|
||||||
@Resolver()
|
@Resolver()
|
||||||
@ -21,7 +26,7 @@ export class ContributionResolver {
|
|||||||
const creationDateObj = new Date(creationDate)
|
const creationDateObj = new Date(creationDate)
|
||||||
validateContribution(creations, amount, creationDateObj)
|
validateContribution(creations, amount, creationDateObj)
|
||||||
|
|
||||||
const contribution = Contribution.create()
|
const contribution = dbContribution.create()
|
||||||
contribution.userId = user.id
|
contribution.userId = user.id
|
||||||
contribution.amount = amount
|
contribution.amount = amount
|
||||||
contribution.createdAt = new Date()
|
contribution.createdAt = new Date()
|
||||||
@ -29,7 +34,33 @@ export class ContributionResolver {
|
|||||||
contribution.memo = memo
|
contribution.memo = memo
|
||||||
|
|
||||||
logger.trace('contribution to save', contribution)
|
logger.trace('contribution to save', contribution)
|
||||||
await Contribution.save(contribution)
|
await dbContribution.save(contribution)
|
||||||
return new UnconfirmedContribution(contribution, user, creations)
|
return new UnconfirmedContribution(contribution, user, creations)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Authorized([RIGHTS.LIST_CONTRIBUTIONS])
|
||||||
|
@Query(() => [Contribution])
|
||||||
|
async listContributions(
|
||||||
|
@Args()
|
||||||
|
{ currentPage = 1, pageSize = 5, order = Order.DESC }: Paginated,
|
||||||
|
@Arg('filterConfirmed', () => Boolean)
|
||||||
|
filterConfirmed: boolean | null,
|
||||||
|
@Ctx() context: Context,
|
||||||
|
): Promise<Contribution[]> {
|
||||||
|
const user = getUser(context)
|
||||||
|
const where: {
|
||||||
|
userId: number
|
||||||
|
confirmedBy?: FindOperator<number> | null
|
||||||
|
} = { userId: user.id }
|
||||||
|
if (filterConfirmed) where.confirmedBy = IsNull()
|
||||||
|
const contributions = await dbContribution.find({
|
||||||
|
where,
|
||||||
|
order: {
|
||||||
|
createdAt: order,
|
||||||
|
},
|
||||||
|
skip: (currentPage - 1) * pageSize,
|
||||||
|
take: pageSize,
|
||||||
|
})
|
||||||
|
return contributions.map((contribution) => new Contribution(contribution, new User(user)))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -234,6 +234,7 @@ export const deleteContributionLink = gql`
|
|||||||
export const createContribution = gql`
|
export const createContribution = gql`
|
||||||
mutation ($amount: Decimal!, $memo: String!, $creationDate: String!) {
|
mutation ($amount: Decimal!, $memo: String!, $creationDate: String!) {
|
||||||
createContribution(amount: $amount, memo: $memo, creationDate: $creationDate) {
|
createContribution(amount: $amount, memo: $memo, creationDate: $creationDate) {
|
||||||
|
id
|
||||||
amount
|
amount
|
||||||
memo
|
memo
|
||||||
}
|
}
|
||||||
|
|||||||
@ -172,6 +172,25 @@ export const queryTransactionLink = gql`
|
|||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
|
||||||
|
export const listContributions = gql`
|
||||||
|
query (
|
||||||
|
$currentPage: Int = 1
|
||||||
|
$pageSize: Int = 5
|
||||||
|
$order: Order
|
||||||
|
$filterConfirmed: Boolean = false
|
||||||
|
) {
|
||||||
|
listContributions(
|
||||||
|
currentPage: $currentPage
|
||||||
|
pageSize: $pageSize
|
||||||
|
order: $order
|
||||||
|
filterConfirmed: $filterConfirmed
|
||||||
|
) {
|
||||||
|
id
|
||||||
|
amount
|
||||||
|
memo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
// from admin interface
|
// from admin interface
|
||||||
|
|
||||||
export const listUnconfirmedContributions = gql`
|
export const listUnconfirmedContributions = gql`
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user