Merge remote-tracking branch 'origin/master' into 2650-feature-federation-harmonize-and-sync-modules-of-federation

This commit is contained in:
Claus-Peter Hübner 2023-02-13 20:54:17 +01:00
commit b0cd39c53a
2 changed files with 203 additions and 172 deletions

View File

@ -42,6 +42,7 @@ 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' import { UserInputError } from 'apollo-server-express'
import { ContributionStatus } from '../enum/ContributionStatus'
// mock account activation email to avoid console spam // mock account activation email to avoid console spam
jest.mock('@/emails/sendEmailVariants', () => { jest.mock('@/emails/sendEmailVariants', () => {
@ -127,13 +128,13 @@ describe('ContributionResolver', () => {
}), }),
).resolves.toEqual( ).resolves.toEqual(
expect.objectContaining({ expect.objectContaining({
errors: [new GraphQLError('memo text is too short (5 characters minimum)')], errors: [new GraphQLError('Memo text is too short')],
}), }),
) )
}) })
it('logs the error found', () => { 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', 4)
}) })
it('throws error when memo length greater than 255 chars', async () => { it('throws error when memo length greater than 255 chars', async () => {
@ -150,13 +151,13 @@ describe('ContributionResolver', () => {
}), }),
).resolves.toEqual( ).resolves.toEqual(
expect.objectContaining({ expect.objectContaining({
errors: [new GraphQLError('memo text is too long (255 characters maximum)')], errors: [new GraphQLError('Memo text is too long')],
}), }),
) )
}) })
it('logs the error found', () => { 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', 259)
}) })
it('throws error when creationDate not-valid', async () => { it('throws error when creationDate not-valid', async () => {
@ -417,31 +418,6 @@ describe('ContributionResolver', () => {
resetToken() resetToken()
}) })
describe('wrong contribution id', () => {
it('throws an error', async () => {
jest.clearAllMocks()
await expect(
mutate({
mutation: updateContribution,
variables: {
contributionId: -1,
amount: 100.0,
memo: 'Test env contribution',
creationDate: new Date().toString(),
},
}),
).resolves.toEqual(
expect.objectContaining({
errors: [new GraphQLError('No contribution found to given id.')],
}),
)
})
it('logs the error found', () => {
expect(logger.error).toBeCalledWith('No contribution found to given id')
})
})
describe('Memo length smaller than 5 chars', () => { describe('Memo length smaller than 5 chars', () => {
it('throws error', async () => { it('throws error', async () => {
jest.clearAllMocks() jest.clearAllMocks()
@ -458,13 +434,13 @@ describe('ContributionResolver', () => {
}), }),
).resolves.toEqual( ).resolves.toEqual(
expect.objectContaining({ expect.objectContaining({
errors: [new GraphQLError('memo text is too short (5 characters minimum)')], errors: [new GraphQLError('Memo text is too short')],
}), }),
) )
}) })
it('logs the error found', () => { 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', 4)
}) })
}) })
@ -484,13 +460,38 @@ describe('ContributionResolver', () => {
}), }),
).resolves.toEqual( ).resolves.toEqual(
expect.objectContaining({ expect.objectContaining({
errors: [new GraphQLError('memo text is too long (255 characters maximum)')], errors: [new GraphQLError('Memo text is too long')],
}), }),
) )
}) })
it('logs the error found', () => { 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', 259)
})
})
describe('wrong contribution id', () => {
it('throws an error', async () => {
jest.clearAllMocks()
await expect(
mutate({
mutation: updateContribution,
variables: {
contributionId: -1,
amount: 100.0,
memo: 'Test env contribution',
creationDate: new Date().toString(),
},
}),
).resolves.toEqual(
expect.objectContaining({
errors: [new GraphQLError('Contribution not found')],
}),
)
})
it('logs the error found', () => {
expect(logger.error).toBeCalledWith('Contribution not found', -1)
}) })
}) })
@ -516,18 +517,16 @@ describe('ContributionResolver', () => {
}), }),
).resolves.toEqual( ).resolves.toEqual(
expect.objectContaining({ expect.objectContaining({
errors: [ errors: [new GraphQLError('Can not update contribution of another user')],
new GraphQLError(
'user of the pending contribution and send user does not correspond',
),
],
}), }),
) )
}) })
it('logs the error found', () => { it('logs the error found', () => {
expect(logger.error).toBeCalledWith( expect(logger.error).toBeCalledWith(
'user of the pending contribution and send user does not correspond', 'Can not update contribution of another user',
expect.any(Object),
expect.any(Number),
) )
}) })
}) })
@ -548,12 +547,64 @@ describe('ContributionResolver', () => {
}), }),
).resolves.toEqual( ).resolves.toEqual(
expect.objectContaining({ expect.objectContaining({
errors: [new GraphQLError('An admin is not allowed to update a user contribution.')], errors: [new GraphQLError('An admin is not allowed to update an user contribution')],
}), }),
) )
}) })
// TODO check that the error is logged (need to modify AdminResolver, avoid conflicts) it('logs the error found', () => {
expect(logger.error).toBeCalledWith(
'An admin is not allowed to update an user contribution',
)
})
})
describe('contribution has wrong status', () => {
beforeAll(async () => {
const contribution = await Contribution.findOneOrFail({
id: result.data.createContribution.id,
})
contribution.contributionStatus = ContributionStatus.DELETED
contribution.save()
await mutate({
mutation: login,
variables: { email: 'bibi@bloxberg.de', password: 'Aa12345_' },
})
})
afterAll(async () => {
const contribution = await Contribution.findOneOrFail({
id: result.data.createContribution.id,
})
contribution.contributionStatus = ContributionStatus.PENDING
contribution.save()
})
it('throws an error', async () => {
jest.clearAllMocks()
await expect(
mutate({
mutation: updateContribution,
variables: {
contributionId: result.data.createContribution.id,
amount: 10.0,
memo: 'Test env contribution',
creationDate: new Date().toString(),
},
}),
).resolves.toEqual(
expect.objectContaining({
errors: [new GraphQLError('Contribution can not be updated due to status')],
}),
)
})
it('logs the error found', () => {
expect(logger.error).toBeCalledWith(
'Contribution can not be updated due to status',
ContributionStatus.DELETED,
)
})
}) })
describe('update too much so that the limit is exceeded', () => { describe('update too much so that the limit is exceeded', () => {
@ -610,16 +661,13 @@ describe('ContributionResolver', () => {
}), }),
).resolves.toEqual( ).resolves.toEqual(
expect.objectContaining({ expect.objectContaining({
errors: [new GraphQLError('Currently the month of the contribution cannot change.')], errors: [new GraphQLError('Month of contribution can not be changed')],
}), }),
) )
}) })
it.skip('logs the error found', () => { it('logs the error found', () => {
expect(logger.error).toBeCalledWith( expect(logger.error).toBeCalledWith('Month of contribution can not be changed')
'No information for available creations with the given creationDate=',
'Invalid Date',
)
}) })
}) })
@ -1153,6 +1201,7 @@ describe('ContributionResolver', () => {
describe('wrong contribution id', () => { describe('wrong contribution id', () => {
it('returns an error', async () => { it('returns an error', async () => {
jest.clearAllMocks()
await expect( await expect(
mutate({ mutate({
mutation: deleteContribution, mutation: deleteContribution,
@ -1162,18 +1211,19 @@ describe('ContributionResolver', () => {
}), }),
).resolves.toEqual( ).resolves.toEqual(
expect.objectContaining({ expect.objectContaining({
errors: [new GraphQLError('Contribution not found for given id.')], errors: [new GraphQLError('Contribution not found')],
}), }),
) )
}) })
it('logs the error found', () => { it('logs the error found', () => {
expect(logger.error).toBeCalledWith('Contribution not found for given id') expect(logger.error).toBeCalledWith('Contribution not found', -1)
}) })
}) })
describe('other user sends a deleteContribution', () => { describe('other user sends a deleteContribution', () => {
it('returns an error', async () => { it('returns an error', 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_' },
@ -1193,7 +1243,11 @@ describe('ContributionResolver', () => {
}) })
it('logs the error found', () => { it('logs the error found', () => {
expect(logger.error).toBeCalledWith('Can not delete contribution of another user') expect(logger.error).toBeCalledWith(
'Can not delete contribution of another user',
expect.any(Object),
expect.any(Number),
)
}) })
}) })
@ -1269,7 +1323,10 @@ describe('ContributionResolver', () => {
}) })
it('logs the error found', () => { it('logs the error found', () => {
expect(logger.error).toBeCalledWith('A confirmed contribution can not be deleted') expect(logger.error).toBeCalledWith(
'A confirmed contribution can not be deleted',
expect.objectContaining({ contributionStatus: 'CONFIRMED' }),
)
}) })
}) })
}) })
@ -1535,15 +1592,13 @@ describe('ContributionResolver', () => {
mutate({ mutation: adminCreateContribution, variables }), mutate({ mutation: adminCreateContribution, variables }),
).resolves.toEqual( ).resolves.toEqual(
expect.objectContaining({ expect.objectContaining({
errors: [new GraphQLError('Could not find user with email: bibi@bloxberg.de')], errors: [new GraphQLError('Could not find user')],
}), }),
) )
}) })
it('logs the error thrown', () => { it('logs the error thrown', () => {
expect(logger.error).toBeCalledWith( expect(logger.error).toBeCalledWith('Could not find user', 'bibi@bloxberg.de')
'Could not find user with email: bibi@bloxberg.de',
)
}) })
}) })
@ -1563,7 +1618,7 @@ describe('ContributionResolver', () => {
).resolves.toEqual( ).resolves.toEqual(
expect.objectContaining({ expect.objectContaining({
errors: [ errors: [
new GraphQLError('This user was deleted. Cannot create a contribution.'), new GraphQLError('Cannot create contribution since the user was deleted'),
], ],
}), }),
) )
@ -1571,7 +1626,12 @@ describe('ContributionResolver', () => {
it('logs the error thrown', () => { it('logs the error thrown', () => {
expect(logger.error).toBeCalledWith( expect(logger.error).toBeCalledWith(
'This user was deleted. Cannot create a contribution.', 'Cannot create contribution since the user was deleted',
expect.objectContaining({
user: expect.objectContaining({
deletedAt: new Date('2018-03-14T09:17:52.000Z'),
}),
}),
) )
}) })
}) })
@ -1592,7 +1652,9 @@ describe('ContributionResolver', () => {
).resolves.toEqual( ).resolves.toEqual(
expect.objectContaining({ expect.objectContaining({
errors: [ errors: [
new GraphQLError('Contribution could not be saved, Email is not activated'), new GraphQLError(
'Cannot create contribution since the users email is not activated',
),
], ],
}), }),
) )
@ -1600,7 +1662,8 @@ describe('ContributionResolver', () => {
it('logs the error thrown', () => { it('logs the error thrown', () => {
expect(logger.error).toBeCalledWith( expect(logger.error).toBeCalledWith(
'Contribution could not be saved, Email is not activated', 'Cannot create contribution since the users email is not activated',
expect.objectContaining({ emailChecked: false }),
) )
}) })
}) })
@ -1619,13 +1682,13 @@ describe('ContributionResolver', () => {
mutate({ mutation: adminCreateContribution, variables }), mutate({ mutation: adminCreateContribution, variables }),
).resolves.toEqual( ).resolves.toEqual(
expect.objectContaining({ expect.objectContaining({
errors: [new GraphQLError(`invalid Date for creationDate=invalid-date`)], errors: [new GraphQLError('CreationDate is invalid')],
}), }),
) )
}) })
it('logs the error thrown', () => { it('logs the error thrown', () => {
expect(logger.error).toBeCalledWith(`invalid Date for creationDate=invalid-date`) expect(logger.error).toBeCalledWith('CreationDate is invalid', 'invalid-date')
}) })
}) })
@ -1821,17 +1884,13 @@ describe('ContributionResolver', () => {
}), }),
).resolves.toEqual( ).resolves.toEqual(
expect.objectContaining({ expect.objectContaining({
errors: [ errors: [new GraphQLError('Could not find User')],
new GraphQLError('Could not find UserContact with email: bob@baumeister.de'),
],
}), }),
) )
}) })
it('logs the error thrown', () => { it('logs the error thrown', () => {
expect(logger.error).toBeCalledWith( expect(logger.error).toBeCalledWith('Could not find User', 'bob@baumeister.de')
'Could not find UserContact with email: bob@baumeister.de',
)
}) })
}) })
@ -1851,13 +1910,13 @@ describe('ContributionResolver', () => {
}), }),
).resolves.toEqual( ).resolves.toEqual(
expect.objectContaining({ expect.objectContaining({
errors: [new GraphQLError('User was deleted (stephen@hawking.uk)')], errors: [new GraphQLError('User was deleted')],
}), }),
) )
}) })
it('logs the error thrown', () => { it('logs the error thrown', () => {
expect(logger.error).toBeCalledWith('User was deleted (stephen@hawking.uk)') expect(logger.error).toBeCalledWith('User was deleted', 'stephen@hawking.uk')
}) })
}) })
@ -1877,13 +1936,13 @@ describe('ContributionResolver', () => {
}), }),
).resolves.toEqual( ).resolves.toEqual(
expect.objectContaining({ expect.objectContaining({
errors: [new GraphQLError('No contribution found to given id.')], errors: [new GraphQLError('Contribution not found')],
}), }),
) )
}) })
it('logs the error thrown', () => { it('logs the error thrown', () => {
expect(logger.error).toBeCalledWith('No contribution found to given id.') expect(logger.error).toBeCalledWith('Contribution not found', -1)
}) })
}) })
@ -1907,7 +1966,7 @@ describe('ContributionResolver', () => {
expect.objectContaining({ expect.objectContaining({
errors: [ errors: [
new GraphQLError( new GraphQLError(
'user of the pending contribution and send user does not correspond', 'User of the pending contribution and send user does not correspond',
), ),
], ],
}), }),
@ -1916,7 +1975,7 @@ describe('ContributionResolver', () => {
it('logs the error thrown', () => { it('logs the error thrown', () => {
expect(logger.error).toBeCalledWith( expect(logger.error).toBeCalledWith(
'user of the pending contribution and send user does not correspond', 'User of the pending contribution and send user does not correspond',
) )
}) })
}) })
@ -2111,13 +2170,13 @@ describe('ContributionResolver', () => {
}), }),
).resolves.toEqual( ).resolves.toEqual(
expect.objectContaining({ expect.objectContaining({
errors: [new GraphQLError('Contribution not found for given id.')], errors: [new GraphQLError('Contribution not found')],
}), }),
) )
}) })
it('logs the error thrown', () => { it('logs the error thrown', () => {
expect(logger.error).toBeCalledWith('Contribution not found for given id: -1') expect(logger.error).toBeCalledWith('Contribution not found', -1)
}) })
}) })
@ -2237,13 +2296,13 @@ describe('ContributionResolver', () => {
}), }),
).resolves.toEqual( ).resolves.toEqual(
expect.objectContaining({ expect.objectContaining({
errors: [new GraphQLError('Contribution not found to given id.')], errors: [new GraphQLError('Contribution not found')],
}), }),
) )
}) })
it('logs the error thrown', () => { it('logs the error thrown', () => {
expect(logger.error).toBeCalledWith('Contribution not found for given id: -1') expect(logger.error).toBeCalledWith('Contribution not found', -1)
}) })
}) })
@ -2354,6 +2413,7 @@ describe('ContributionResolver', () => {
describe('confirm same contribution again', () => { describe('confirm same contribution again', () => {
it('throws an error', async () => { it('throws an error', async () => {
jest.clearAllMocks()
await expect( await expect(
mutate({ mutate({
mutation: confirmContribution, mutation: confirmContribution,
@ -2363,11 +2423,18 @@ describe('ContributionResolver', () => {
}), }),
).resolves.toEqual( ).resolves.toEqual(
expect.objectContaining({ expect.objectContaining({
errors: [new GraphQLError('Contribution already confirmd.')], errors: [new GraphQLError('Contribution already confirmed')],
}), }),
) )
}) })
}) })
it('logs the error thrown', () => {
expect(logger.error).toBeCalledWith(
'Contribution already confirmed',
expect.any(Number),
)
})
}) })
describe('confirm two creations one after the other quickly', () => { describe('confirm two creations one after the other quickly', () => {

View File

@ -55,6 +55,7 @@ import {
sendContributionDeniedEmail, sendContributionDeniedEmail,
} from '@/emails/sendEmailVariants' } from '@/emails/sendEmailVariants'
import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK' import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK'
import LogError from '@/server/LogError'
import { getLastTransaction } from './util/getLastTransaction' import { getLastTransaction } from './util/getLastTransaction'
@ -67,14 +68,11 @@ export class ContributionResolver {
@Ctx() context: Context, @Ctx() context: Context,
): Promise<UnconfirmedContribution> { ): Promise<UnconfirmedContribution> {
const clientTimezoneOffset = getClientTimezoneOffset(context) const clientTimezoneOffset = getClientTimezoneOffset(context)
if (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) { if (memo.length < MEMO_MIN_CHARS) {
logger.error(`memo text is too short: memo.length=${memo.length} < ${MEMO_MIN_CHARS}`) throw new LogError('Memo text is too short', memo.length)
throw new Error(`memo text is too short (${MEMO_MIN_CHARS} characters minimum)`) }
if (memo.length > MEMO_MAX_CHARS) {
throw new LogError('Memo text is too long', memo.length)
} }
const event = new Event() const event = new Event()
@ -116,16 +114,13 @@ export class ContributionResolver {
const user = getUser(context) const user = getUser(context)
const contribution = await DbContribution.findOne(id) const contribution = await DbContribution.findOne(id)
if (!contribution) { if (!contribution) {
logger.error('Contribution not found for given id') throw new LogError('Contribution not found', id)
throw new Error('Contribution not found for given id.')
} }
if (contribution.userId !== user.id) { if (contribution.userId !== user.id) {
logger.error('Can not delete contribution of another user') throw new LogError('Can not delete contribution of another user', contribution, user.id)
throw new Error('Can not delete contribution of another user')
} }
if (contribution.confirmedAt) { if (contribution.confirmedAt) {
logger.error('A confirmed contribution can not be deleted') throw new LogError('A confirmed contribution can not be deleted', contribution)
throw new Error('A confirmed contribution can not be deleted')
} }
contribution.contributionStatus = ContributionStatus.DELETED contribution.contributionStatus = ContributionStatus.DELETED
@ -219,14 +214,11 @@ export class ContributionResolver {
@Ctx() context: Context, @Ctx() context: Context,
): Promise<UnconfirmedContribution> { ): Promise<UnconfirmedContribution> {
const clientTimezoneOffset = getClientTimezoneOffset(context) const clientTimezoneOffset = getClientTimezoneOffset(context)
if (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) { if (memo.length < MEMO_MIN_CHARS) {
logger.error(`memo text is too short: memo.length=${memo.length} < ${MEMO_MIN_CHARS}`) throw new LogError('Memo text is too short', memo.length)
throw new Error(`memo text is too short (${MEMO_MIN_CHARS} characters minimum)`) }
if (memo.length > MEMO_MAX_CHARS) {
throw new LogError('Memo text is too long', memo.length)
} }
const user = getUser(context) const user = getUser(context)
@ -235,22 +227,22 @@ export class ContributionResolver {
where: { id: contributionId, confirmedAt: IsNull(), deniedAt: IsNull() }, where: { id: contributionId, confirmedAt: IsNull(), deniedAt: IsNull() },
}) })
if (!contributionToUpdate) { if (!contributionToUpdate) {
logger.error('No contribution found to given id') throw new LogError('Contribution not found', contributionId)
throw new Error('No contribution found to given id.')
} }
if (contributionToUpdate.userId !== user.id) { if (contributionToUpdate.userId !== user.id) {
logger.error('user of the pending contribution and send user does not correspond') throw new LogError(
throw new Error('user of the pending contribution and send user does not correspond') 'Can not update contribution of another user',
contributionToUpdate,
user.id,
)
} }
if ( if (
contributionToUpdate.contributionStatus !== ContributionStatus.IN_PROGRESS && contributionToUpdate.contributionStatus !== ContributionStatus.IN_PROGRESS &&
contributionToUpdate.contributionStatus !== ContributionStatus.PENDING contributionToUpdate.contributionStatus !== ContributionStatus.PENDING
) { ) {
logger.error( throw new LogError(
`Contribution can not be updated since the state is ${contributionToUpdate.contributionStatus}`, 'Contribution can not be updated due to status',
) contributionToUpdate.contributionStatus,
throw new Error(
`Contribution can not be updated since the state is ${contributionToUpdate.contributionStatus}`,
) )
} }
const creationDateObj = new Date(creationDate) const creationDateObj = new Date(creationDate)
@ -258,8 +250,7 @@ export class ContributionResolver {
if (contributionToUpdate.contributionDate.getMonth() === creationDateObj.getMonth()) { if (contributionToUpdate.contributionDate.getMonth() === creationDateObj.getMonth()) {
creations = updateCreations(creations, contributionToUpdate, clientTimezoneOffset) creations = updateCreations(creations, contributionToUpdate, clientTimezoneOffset)
} else { } else {
logger.error('Currently the month of the contribution cannot change.') throw new LogError('Month of contribution can not be changed')
throw new Error('Currently the month of the contribution cannot change.')
} }
// all possible cases not to be true are thrown in this function // all possible cases not to be true are thrown in this function
@ -310,29 +301,24 @@ export class ContributionResolver {
) )
const clientTimezoneOffset = getClientTimezoneOffset(context) const clientTimezoneOffset = getClientTimezoneOffset(context)
if (!isValidDateString(creationDate)) { if (!isValidDateString(creationDate)) {
logger.error(`invalid Date for creationDate=${creationDate}`) throw new LogError('CreationDate is invalid', creationDate)
throw new Error(`invalid Date for creationDate=${creationDate}`)
} }
const emailContact = await UserContact.findOne({ const emailContact = await UserContact.findOne({
where: { email }, where: { email },
withDeleted: true, withDeleted: true,
relations: ['user'], relations: ['user'],
}) })
if (!emailContact) { if (!emailContact || !emailContact.user) {
logger.error(`Could not find user with email: ${email}`) throw new LogError('Could not find user', email)
throw new Error(`Could not find user with email: ${email}`)
} }
if (emailContact.deletedAt) { if (emailContact.deletedAt || emailContact.user.deletedAt) {
logger.error('This emailContact was deleted. Cannot create a contribution.') throw new LogError('Cannot create contribution since the user was deleted', emailContact)
throw new Error('This emailContact was deleted. Cannot create a contribution.')
}
if (emailContact.user.deletedAt) {
logger.error('This user was deleted. Cannot create a contribution.')
throw new Error('This user was deleted. Cannot create a contribution.')
} }
if (!emailContact.emailChecked) { if (!emailContact.emailChecked) {
logger.error('Contribution could not be saved, Email is not activated') throw new LogError(
throw new Error('Contribution could not be saved, Email is not activated') 'Cannot create contribution since the users email is not activated',
emailContact,
)
} }
const event = new Event() const event = new Event()
@ -405,18 +391,11 @@ export class ContributionResolver {
withDeleted: true, withDeleted: true,
relations: ['user'], relations: ['user'],
}) })
if (!emailContact) { if (!emailContact || !emailContact.user) {
logger.error(`Could not find UserContact with email: ${email}`) throw new LogError('Could not find User', email)
throw new Error(`Could not find UserContact with email: ${email}`)
} }
const user = emailContact.user if (emailContact.deletedAt || emailContact.user.deletedAt) {
if (!user) { throw new LogError('User was deleted', email)
logger.error(`Could not find User to emailContact: ${email}`)
throw new Error(`Could not find User to emailContact: ${email}`)
}
if (user.deletedAt) {
logger.error(`User was deleted (${email})`)
throw new Error(`User was deleted (${email})`)
} }
const moderator = getUser(context) const moderator = getUser(context)
@ -425,28 +404,25 @@ export class ContributionResolver {
where: { id, confirmedAt: IsNull(), deniedAt: IsNull() }, where: { id, confirmedAt: IsNull(), deniedAt: IsNull() },
}) })
if (!contributionToUpdate) { if (!contributionToUpdate) {
logger.error('No contribution found to given id.') throw new LogError('Contribution not found', id)
throw new Error('No contribution found to given id.')
} }
if (contributionToUpdate.userId !== user.id) { if (contributionToUpdate.userId !== emailContact.user.id) {
logger.error('user of the pending contribution and send user does not correspond') throw new LogError('User of the pending contribution and send user does not correspond')
throw new Error('user of the pending contribution and send user does not correspond')
} }
if (contributionToUpdate.moderatorId === null) { if (contributionToUpdate.moderatorId === null) {
logger.error('An admin is not allowed to update a user contribution.') throw new LogError('An admin is not allowed to update an user contribution')
throw new Error('An admin is not allowed to update a user contribution.')
} }
const creationDateObj = new Date(creationDate) const creationDateObj = new Date(creationDate)
let creations = await getUserCreation(user.id, clientTimezoneOffset) let creations = await getUserCreation(emailContact.user.id, clientTimezoneOffset)
// TODO: remove this restriction
if (contributionToUpdate.contributionDate.getMonth() === creationDateObj.getMonth()) { if (contributionToUpdate.contributionDate.getMonth() === creationDateObj.getMonth()) {
creations = updateCreations(creations, contributionToUpdate, clientTimezoneOffset) creations = updateCreations(creations, contributionToUpdate, clientTimezoneOffset)
} else { } else {
logger.error('Currently the month of the contribution cannot change.') throw new LogError('Month of contribution can not be changed')
throw new Error('Currently the month of the contribution cannot change.')
} }
// all possible cases not to be true are thrown in this function // all possible cases not to be true are thrown in this function
@ -464,11 +440,11 @@ export class ContributionResolver {
result.memo = contributionToUpdate.memo result.memo = contributionToUpdate.memo
result.date = contributionToUpdate.contributionDate result.date = contributionToUpdate.contributionDate
result.creation = await getUserCreation(user.id, clientTimezoneOffset) result.creation = await getUserCreation(emailContact.user.id, clientTimezoneOffset)
const event = new Event() const event = new Event()
const eventAdminContributionUpdate = new EventAdminContributionUpdate() const eventAdminContributionUpdate = new EventAdminContributionUpdate()
eventAdminContributionUpdate.userId = user.id eventAdminContributionUpdate.userId = emailContact.user.id
eventAdminContributionUpdate.amount = amount eventAdminContributionUpdate.amount = amount
eventAdminContributionUpdate.contributionId = contributionToUpdate.id eventAdminContributionUpdate.contributionId = contributionToUpdate.id
await writeEvent(event.setEventAdminContributionUpdate(eventAdminContributionUpdate)) await writeEvent(event.setEventAdminContributionUpdate(eventAdminContributionUpdate))
@ -521,19 +497,17 @@ export class ContributionResolver {
): Promise<boolean> { ): Promise<boolean> {
const contribution = await DbContribution.findOne(id) const contribution = await DbContribution.findOne(id)
if (!contribution) { if (!contribution) {
logger.error(`Contribution not found for given id: ${id}`) throw new LogError('Contribution not found', id)
throw new Error('Contribution not found for given id.')
} }
if (contribution.confirmedAt) { if (contribution.confirmedAt) {
logger.error('A confirmed contribution can not be deleted') throw new LogError('A confirmed contribution can not be deleted')
throw new Error('A confirmed contribution can not be deleted')
} }
const moderator = getUser(context) const moderator = getUser(context)
if ( if (
contribution.contributionType === ContributionType.USER && contribution.contributionType === ContributionType.USER &&
contribution.userId === moderator.id contribution.userId === moderator.id
) { ) {
throw new Error('Own contribution can not be deleted as admin') throw new LogError('Own contribution can not be deleted as admin')
} }
const user = await DbUser.findOneOrFail( const user = await DbUser.findOneOrFail(
{ id: contribution.userId }, { id: contribution.userId },
@ -575,29 +549,24 @@ export class ContributionResolver {
const clientTimezoneOffset = getClientTimezoneOffset(context) const clientTimezoneOffset = getClientTimezoneOffset(context)
const contribution = await DbContribution.findOne(id) const contribution = await DbContribution.findOne(id)
if (!contribution) { if (!contribution) {
logger.error(`Contribution not found for given id: ${id}`) throw new LogError('Contribution not found', id)
throw new Error('Contribution not found to given id.')
} }
if (contribution.confirmedAt) { if (contribution.confirmedAt) {
logger.error(`Contribution already confirmd: ${id}`) throw new LogError('Contribution already confirmed', id)
throw new Error('Contribution already confirmd.')
} }
if (contribution.contributionStatus === 'DENIED') { if (contribution.contributionStatus === 'DENIED') {
logger.error(`Contribution already denied: ${id}`) throw new LogError('Contribution already denied', id)
throw new Error('Contribution already denied.')
} }
const moderatorUser = getUser(context) const moderatorUser = getUser(context)
if (moderatorUser.id === contribution.userId) { if (moderatorUser.id === contribution.userId) {
logger.error('Moderator can not confirm own contribution') throw new LogError('Moderator can not confirm own contribution')
throw new Error('Moderator can not confirm own contribution')
} }
const user = await DbUser.findOneOrFail( const user = await DbUser.findOneOrFail(
{ id: contribution.userId }, { id: contribution.userId },
{ withDeleted: true, relations: ['emailContact'] }, { withDeleted: true, relations: ['emailContact'] },
) )
if (user.deletedAt) { if (user.deletedAt) {
logger.error('This user was deleted. Cannot confirm a contribution.') throw new LogError('Can not confirm contribution since the user was deleted')
throw new Error('This user was deleted. Cannot confirm a contribution.')
} }
const creations = await getUserCreation(contribution.userId, clientTimezoneOffset, false) const creations = await getUserCreation(contribution.userId, clientTimezoneOffset, false)
validateContribution( validateContribution(
@ -661,8 +630,7 @@ export class ContributionResolver {
}) })
} catch (e) { } catch (e) {
await queryRunner.rollbackTransaction() await queryRunner.rollbackTransaction()
logger.error('Creation was not successful', e) throw new LogError('Creation was not successful', e)
throw new Error('Creation was not successful.')
} finally { } finally {
await queryRunner.release() await queryRunner.release()
} }
@ -737,17 +705,16 @@ export class ContributionResolver {
deniedBy: IsNull(), deniedBy: IsNull(),
}) })
if (!contributionToUpdate) { if (!contributionToUpdate) {
logger.error(`Contribution not found for given id: ${id}`) throw new LogError('Contribution not found', id)
throw new Error(`Contribution not found for given id.`)
} }
if ( if (
contributionToUpdate.contributionStatus !== ContributionStatus.IN_PROGRESS && contributionToUpdate.contributionStatus !== ContributionStatus.IN_PROGRESS &&
contributionToUpdate.contributionStatus !== ContributionStatus.PENDING contributionToUpdate.contributionStatus !== ContributionStatus.PENDING
) { ) {
logger.error( throw new LogError(
`Contribution state (${contributionToUpdate.contributionStatus}) is not allowed.`, 'Status of the contribution is not allowed',
contributionToUpdate.contributionStatus,
) )
throw new Error(`State of the contribution is not allowed.`)
} }
const moderator = getUser(context) const moderator = getUser(context)
const user = await DbUser.findOne( const user = await DbUser.findOne(
@ -755,10 +722,7 @@ export class ContributionResolver {
{ relations: ['emailContact'] }, { relations: ['emailContact'] },
) )
if (!user) { if (!user) {
logger.error( throw new LogError('Could not find User of the Contribution', contributionToUpdate.userId)
`Could not find User for the Contribution (userId: ${contributionToUpdate.userId}).`,
)
throw new Error('Could not find User for the Contribution.')
} }
contributionToUpdate.contributionStatus = ContributionStatus.DENIED contributionToUpdate.contributionStatus = ContributionStatus.DENIED