Merge branch 'crud-contribution-link' into merge-1979-with-1923

This commit is contained in:
ogerly 2022-06-14 13:17:51 +02:00
commit b8f6d24991
6 changed files with 202 additions and 5 deletions

View File

@ -38,4 +38,6 @@ export enum RIGHTS {
CREATION_TRANSACTION_LIST = 'CREATION_TRANSACTION_LIST',
LIST_TRANSACTION_LINKS_ADMIN = 'LIST_TRANSACTION_LINKS_ADMIN',
CREATE_CONTRIBUTION_LINK = 'CREATE_CONTRIBUTION_LINK',
LIST_CONTRIBUTION_LINKS = 'LIST_CONTRIBUTION_LINKS',
DELETE_CONTRIBUTION_LINK = 'DELETE_CONTRIBUTION_LINK',
}

View File

@ -0,0 +1,11 @@
import { ObjectType, Field } from 'type-graphql'
import { ContributionLink } from '@model/ContributionLink'
@ObjectType()
export class ContributionLinkList {
@Field(() => [ContributionLink])
links: ContributionLink[]
@Field(() => Number)
count: number
}

View File

@ -21,12 +21,14 @@ import {
deletePendingCreation,
confirmPendingCreation,
createContributionLink,
deleteContributionLink,
} from '@/seeds/graphql/mutations'
import {
getPendingCreations,
login,
searchUsers,
listTransactionLinksAdmin,
listContributionLinks,
} from '@/seeds/graphql/queries'
import { GraphQLError } from 'graphql'
import { User } from '@entity/User'
@ -1610,7 +1612,7 @@ describe('AdminResolver', () => {
describe('unauthenticated', () => {
describe('createContributionLink', () => {
it.only('returns an error', async () => {
it('returns an error', async () => {
await expect(mutate({ mutation: createContributionLink, variables })).resolves.toEqual(
expect.objectContaining({
errors: [new GraphQLError('401 Unauthorized')],
@ -1618,6 +1620,28 @@ describe('AdminResolver', () => {
)
})
})
describe('listContributionLinks', () => {
it('returns an error', async () => {
await expect(query({ query: listContributionLinks })).resolves.toEqual(
expect.objectContaining({
errors: [new GraphQLError('401 Unauthorized')],
}),
)
})
})
describe('deleteContributionLink', () => {
it('returns an error', async () => {
await expect(
mutate({ mutation: deleteContributionLink, variables: { id: -1 } }),
).resolves.toEqual(
expect.objectContaining({
errors: [new GraphQLError('401 Unauthorized')],
}),
)
})
})
})
describe('authenticated', () => {
@ -1636,7 +1660,7 @@ describe('AdminResolver', () => {
})
describe('createContributionLink', () => {
it.only('returns an error', async () => {
it('returns an error', async () => {
await expect(mutate({ mutation: createContributionLink, variables })).resolves.toEqual(
expect.objectContaining({
errors: [new GraphQLError('401 Unauthorized')],
@ -1644,6 +1668,28 @@ describe('AdminResolver', () => {
)
})
})
describe('listContributionLinks', () => {
it('returns an error', async () => {
await expect(query({ query: listContributionLinks })).resolves.toEqual(
expect.objectContaining({
errors: [new GraphQLError('401 Unauthorized')],
}),
)
})
})
describe('deleteContributionLink', () => {
it('returns an error', async () => {
await expect(
mutate({ mutation: deleteContributionLink, variables: { id: -1 } }),
).resolves.toEqual(
expect.objectContaining({
errors: [new GraphQLError('401 Unauthorized')],
}),
)
})
})
})
describe('with admin rights', () => {
@ -1661,7 +1707,7 @@ describe('AdminResolver', () => {
})
describe('createContributionLink', () => {
it.only('returns a contribution link object', async () => {
it('returns a contribution link object', async () => {
await expect(mutate({ mutation: createContributionLink, variables })).resolves.toEqual(
expect.objectContaining({
data: {
@ -1683,7 +1729,7 @@ describe('AdminResolver', () => {
)
})
it.only('has a contribution link stored in db', async () => {
it('has a contribution link stored in db', async () => {
const cls = await DbContributionLink.find()
expect(cls).toHaveLength(1)
expect(cls[0]).toEqual(
@ -1708,6 +1754,84 @@ describe('AdminResolver', () => {
)
})
})
describe('listContributionLinks', () => {
describe('one link in DB', () => {
it('returns the link and count 1', async () => {
await expect(query({ query: listContributionLinks })).resolves.toEqual(
expect.objectContaining({
data: {
listContributionLinks: {
links: expect.arrayContaining([
expect.objectContaining({
amount: '200',
code: expect.stringMatching(/^CL-[0-9a-f]{24,24}$/),
link: expect.any(String),
createdAt: expect.any(String),
name: 'Dokumenta 2022',
memo: 'Danke für deine Teilnahme an der Dokumenta 2022',
validFrom: expect.any(String),
validTo: expect.any(String),
maxAmountPerMonth: '200',
cycle: 'once',
maxPerCycle: 1,
}),
]),
count: 1,
},
},
}),
)
})
})
})
describe('deleteContributionLink', () => {
describe('no valid id', () => {
it('returns an error', async () => {
await expect(
mutate({ mutation: deleteContributionLink, variables: { id: -1 } }),
).resolves.toEqual(
expect.objectContaining({
errors: [new GraphQLError('Contribution Link not found to given id.')],
}),
)
})
})
describe('valid id', () => {
let linkId: number
beforeAll(async () => {
const links = await query({ query: listContributionLinks })
linkId = links.data.listContributionLinks.links[0].id
})
it('returns a date string', async () => {
await expect(
mutate({ mutation: deleteContributionLink, variables: { id: linkId } }),
).resolves.toEqual(
expect.objectContaining({
data: {
deleteContributionLink: expect.any(String),
},
}),
)
})
it('does not list this contribution link anymore', async () => {
await expect(query({ query: listContributionLinks })).resolves.toEqual(
expect.objectContaining({
data: {
listContributionLinks: {
links: [],
count: 0,
},
},
}),
)
})
})
})
})
})
})

View File

@ -1,4 +1,5 @@
import { Context, getUser } from '@/server/context'
import { backendLogger as logger } from '@/server/logger'
import { Resolver, Query, Arg, Args, Authorized, Mutation, Ctx, Int } from 'type-graphql'
import {
getCustomRepository,
@ -15,6 +16,7 @@ import { PendingCreation } from '@model/PendingCreation'
import { CreatePendingCreations } from '@model/CreatePendingCreations'
import { UpdatePendingCreation } from '@model/UpdatePendingCreation'
import { ContributionLink } from '@model/ContributionLink'
import { ContributionLinkList } from '@model/ContributionLinkList'
import { RIGHTS } from '@/auth/RIGHTS'
import { UserRepository } from '@repository/User'
import CreatePendingCreationArgs from '@arg/CreatePendingCreationArgs'
@ -491,9 +493,39 @@ export class AdminResolver {
if (validTo) dbContributionLink.validTo = new Date(validTo)
dbContributionLink.maxAmountPerMonth = maxAmountPerMonth
dbContributionLink.maxPerCycle = maxPerCycle
dbContributionLink.save()
await dbContributionLink.save()
return new ContributionLink(dbContributionLink)
}
@Authorized([RIGHTS.LIST_CONTRIBUTION_LINKS])
@Query(() => ContributionLinkList)
async listContributionLinks(
@Args()
{ currentPage = 1, pageSize = 5, order = Order.DESC }: Paginated,
): Promise<ContributionLinkList> {
const [links, count] = await DbContributionLink.findAndCount({
order: { createdAt: order },
skip: (currentPage - 1) * pageSize,
take: pageSize,
})
return {
links: links.map((link: DbContributionLink) => new ContributionLink(link)),
count,
}
}
@Authorized([RIGHTS.DELETE_CONTRIBUTION_LINK])
@Mutation(() => Date, { nullable: true })
async deleteContributionLink(@Arg('id', () => Int) id: number): Promise<Date | null> {
const contributionLink = await DbContributionLink.findOne(id)
if (!contributionLink) {
logger.error(`Contribution Link not found to given id: ${id}`)
throw new Error('Contribution Link not found to given id.')
}
await contributionLink.softRemove()
const newContributionLink = await DbContributionLink.findOne({ id }, { withDeleted: true })
return newContributionLink ? newContributionLink.deletedAt : null
}
}
interface CreationMap {

View File

@ -173,3 +173,9 @@ export const createContributionLink = gql`
}
}
`
export const deleteContributionLink = gql`
mutation ($id: Int!) {
deleteContributionLink(id: $id)
}
`

View File

@ -217,3 +217,25 @@ export const listTransactionLinksAdmin = gql`
}
}
`
export const listContributionLinks = gql`
query ($pageSize: Int = 25, $currentPage: Int = 1, $order: Order) {
listContributionLinks(pageSize: $pageSize, currentPage: $currentPage, order: $order) {
links {
id
amount
name
memo
code
link
createdAt
validFrom
validTo
maxAmountPerMonth
cycle
maxPerCycle
}
count
}
}
`