diff --git a/backend/src/event/Event.ts b/backend/src/event/Event.ts index d86ddf15f..09a31d4e0 100644 --- a/backend/src/event/Event.ts +++ b/backend/src/event/Event.ts @@ -66,6 +66,9 @@ export class EventTransactionCreation extends EventBasicTx {} export class EventTransactionReceive extends EventBasicTxX {} export class EventTransactionReceiveRedeem extends EventBasicTxX {} export class EventContributionCreate extends EventBasicCt {} +export class EventAdminContributionCreate extends EventBasicCt {} +export class EventAdminContributionDelete extends EventBasicCt {} +export class EventAdminContributionUpdate extends EventBasicCt {} export class EventUserCreateContributionMessage extends EventBasicCtMsg {} export class EventAdminCreateContributionMessage extends EventBasicCtMsg {} export class EventContributionDelete extends EventBasicCt {} @@ -74,6 +77,14 @@ export class EventContributionConfirm extends EventBasicCtX {} export class EventContributionDeny extends EventBasicCtX {} export class EventContributionLinkDefine extends EventBasicCt {} export class EventContributionLinkActivateRedeem extends EventBasicCt {} +export class EventDeleteUser extends EventBasicUserId {} +export class EventUndeleteUser extends EventBasicUserId {} +export class EventChangeUserRole extends EventBasicUserId {} +export class EventAdminUpdateContribution extends EventBasicCt {} +export class EventAdminDeleteContribution extends EventBasicCt {} +export class EventCreateContributionLink extends EventBasicCt {} +export class EventDeleteContributionLink extends EventBasicCt {} +export class EventUpdateContributionLink extends EventBasicCt {} export class Event { constructor() @@ -289,6 +300,27 @@ export class Event { return this } + public setEventAdminContributionCreate(ev: EventAdminContributionCreate): Event { + this.setByBasicCt(ev.userId, ev.contributionId, ev.amount) + this.type = EventProtocolType.ADMIN_CONTRIBUTION_CREATE + + return this + } + + public setEventAdminContributionDelete(ev: EventAdminContributionDelete): Event { + this.setByBasicCt(ev.userId, ev.contributionId, ev.amount) + this.type = EventProtocolType.ADMIN_CONTRIBUTION_DELETE + + return this + } + + public setEventAdminContributionUpdate(ev: EventAdminContributionUpdate): Event { + this.setByBasicCt(ev.userId, ev.contributionId, ev.amount) + this.type = EventProtocolType.ADMIN_CONTRIBUTION_UPDATE + + return this + } + public setEventUserCreateContributionMessage(ev: EventUserCreateContributionMessage): Event { this.setByBasicCtMsg(ev.userId, ev.contributionId, ev.amount, ev.messageId) this.type = EventProtocolType.USER_CREATE_CONTRIBUTION_MESSAGE @@ -345,6 +377,62 @@ export class Event { return this } + public setEventDeleteUser(ev: EventDeleteUser): Event { + this.setByBasicUser(ev.userId) + this.type = EventProtocolType.DELETE_USER + + return this + } + + public setEventUndeleteUser(ev: EventUndeleteUser): Event { + this.setByBasicUser(ev.userId) + this.type = EventProtocolType.UNDELETE_USER + + return this + } + + public setEventChangeUserRole(ev: EventChangeUserRole): Event { + this.setByBasicUser(ev.userId) + this.type = EventProtocolType.CHANGE_USER_ROLE + + return this + } + + public setEventAdminUpdateContribution(ev: EventAdminUpdateContribution): Event { + this.setByBasicCt(ev.userId, ev.contributionId, ev.amount) + this.type = EventProtocolType.ADMIN_UPDATE_CONTRIBUTION + + return this + } + + public setEventAdminDeleteContribution(ev: EventAdminDeleteContribution): Event { + this.setByBasicCt(ev.userId, ev.contributionId, ev.amount) + this.type = EventProtocolType.ADMIN_DELETE_CONTRIBUTION + + return this + } + + public setEventCreateContributionLink(ev: EventCreateContributionLink): Event { + this.setByBasicCt(ev.userId, ev.contributionId, ev.amount) + this.type = EventProtocolType.CREATE_CONTRIBUTION_LINK + + return this + } + + public setEventDeleteContributionLink(ev: EventDeleteContributionLink): Event { + this.setByBasicCt(ev.userId, ev.contributionId, ev.amount) + this.type = EventProtocolType.DELETE_CONTRIBUTION_LINK + + return this + } + + public setEventUpdateContributionLink(ev: EventUpdateContributionLink): Event { + this.setByBasicCt(ev.userId, ev.contributionId, ev.amount) + this.type = EventProtocolType.UPDATE_CONTRIBUTION_LINK + + return this + } + setByBasicUser(userId: number): Event { this.setEventBasic() this.userId = userId diff --git a/backend/src/event/EventProtocolType.ts b/backend/src/event/EventProtocolType.ts index d53eb6961..b7c2f0151 100644 --- a/backend/src/event/EventProtocolType.ts +++ b/backend/src/event/EventProtocolType.ts @@ -33,6 +33,17 @@ export enum EventProtocolType { CONTRIBUTION_LINK_ACTIVATE_REDEEM = 'CONTRIBUTION_LINK_ACTIVATE_REDEEM', CONTRIBUTION_DELETE = 'CONTRIBUTION_DELETE', CONTRIBUTION_UPDATE = 'CONTRIBUTION_UPDATE', + ADMIN_CONTRIBUTION_CREATE = 'ADMIN_CONTRIBUTION_CREATE', + ADMIN_CONTRIBUTION_DELETE = 'ADMIN_CONTRIBUTION_DELETE', + ADMIN_CONTRIBUTION_UPDATE = 'ADMIN_CONTRIBUTION_UPDATE', USER_CREATE_CONTRIBUTION_MESSAGE = 'USER_CREATE_CONTRIBUTION_MESSAGE', ADMIN_CREATE_CONTRIBUTION_MESSAGE = 'ADMIN_CREATE_CONTRIBUTION_MESSAGE', + DELETE_USER = 'DELETE_USER', + UNDELETE_USER = 'UNDELETE_USER', + CHANGE_USER_ROLE = 'CHANGE_USER_ROLE', + ADMIN_UPDATE_CONTRIBUTION = 'ADMIN_UPDATE_CONTRIBUTION', + ADMIN_DELETE_CONTRIBUTION = 'ADMIN_DELETE_CONTRIBUTION', + CREATE_CONTRIBUTION_LINK = 'CREATE_CONTRIBUTION_LINK', + DELETE_CONTRIBUTION_LINK = 'DELETE_CONTRIBUTION_LINK', + UPDATE_CONTRIBUTION_LINK = 'UPDATE_CONTRIBUTION_LINK', } diff --git a/backend/src/graphql/resolver/AdminResolver.test.ts b/backend/src/graphql/resolver/AdminResolver.test.ts index 281f2b99b..b5711cd57 100644 --- a/backend/src/graphql/resolver/AdminResolver.test.ts +++ b/backend/src/graphql/resolver/AdminResolver.test.ts @@ -42,6 +42,9 @@ import { Contribution } from '@entity/Contribution' import { Transaction as DbTransaction } from '@entity/Transaction' import { ContributionLink as DbContributionLink } from '@entity/ContributionLink' import { sendContributionConfirmedEmail } from '@/mailer/sendContributionConfirmedEmail' +import { EventProtocol } from '@entity/EventProtocol' +import { EventProtocolType } from '@/event/EventProtocolType' +import { logger } from '@test/testSetup' // mock account activation email to avoid console spam jest.mock('@/mailer/sendAccountActivationEmail', () => { @@ -144,6 +147,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith(`Could not find user with userId: ${admin.id + 1}`) + }) }) describe('change role with success', () => { @@ -196,6 +203,9 @@ describe('AdminResolver', () => { }), ) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('Administrator can not change his own role!') + }) }) describe('user has already role to be set', () => { @@ -213,6 +223,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('User is already admin!') + }) }) describe('to usual user', () => { @@ -229,6 +243,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('User is already a usual user!') + }) }) }) }) @@ -297,6 +315,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith(`Could not find user with userId: ${admin.id + 1}`) + }) }) describe('delete self', () => { @@ -309,6 +331,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('Moderator can not delete his own account!') + }) }) describe('delete with success', () => { @@ -338,6 +364,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith(`Could not find user with userId: ${user.id}`) + }) }) }) }) @@ -405,6 +435,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith(`Could not find user with userId: ${admin.id + 1}`) + }) }) describe('user to undelete is not deleted', () => { @@ -422,6 +456,10 @@ describe('AdminResolver', () => { ) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('User is not deleted') + }) + describe('undelete deleted user', () => { beforeAll(async () => { await mutate({ mutation: deleteUser, variables: { userId: user.id } }) @@ -909,6 +947,12 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'Could not find user with email: bibi@bloxberg.de', + ) + }) }) describe('user to create for is deleted', () => { @@ -928,6 +972,12 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'This user was deleted. Cannot create a contribution.', + ) + }) }) describe('user to create for has email not confirmed', () => { @@ -947,6 +997,12 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'Contribution could not be saved, Email is not activated', + ) + }) }) describe('valid user to create for', () => { @@ -967,6 +1023,13 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'No information for available creations with the given creationDate=', + 'Invalid Date', + ) + }) }) describe('date of creation is four months ago', () => { @@ -987,6 +1050,13 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'No information for available creations with the given creationDate=', + variables.creationDate, + ) + }) }) describe('date of creation is in the future', () => { @@ -1007,6 +1077,13 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'No information for available creations with the given creationDate=', + variables.creationDate, + ) + }) }) describe('amount of creation is too high', () => { @@ -1024,6 +1101,12 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'The amount (2000 GDD) to be created exceeds the amount (1000 GDD) still available for this month.', + ) + }) }) describe('creation is valid', () => { @@ -1039,6 +1122,15 @@ describe('AdminResolver', () => { }), ) }) + + it('stores the admin create contribution event in the database', async () => { + await expect(EventProtocol.find()).resolves.toContainEqual( + expect.objectContaining({ + type: EventProtocolType.ADMIN_CONTRIBUTION_CREATE, + userId: admin.id, + }), + ) + }) }) describe('second creation surpasses the available amount ', () => { @@ -1056,6 +1148,12 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'The amount (1000 GDD) to be created exceeds the amount (800 GDD) still available for this month.', + ) + }) }) }) }) @@ -1134,6 +1232,12 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'Could not find UserContact with email: bob@baumeister.de', + ) + }) }) describe('user for creation to update is deleted', () => { @@ -1155,6 +1259,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('User was deleted (stephen@hawking.uk)') + }) }) describe('creation does not exist', () => { @@ -1176,6 +1284,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('No contribution found to given id.') + }) }) describe('user email does not match creation user', () => { @@ -1188,7 +1300,9 @@ describe('AdminResolver', () => { email: 'bibi@bloxberg.de', amount: new Decimal(300), memo: 'Danke Bibi!', - creationDate: new Date().toString(), + creationDate: creation + ? creation.contributionDate.toString() + : new Date().toString(), }, }), ).resolves.toEqual( @@ -1201,11 +1315,17 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'user of the pending contribution and send user does not correspond', + ) + }) }) describe('creation update is not valid', () => { // as this test has not clearly defined that date, it is a false positive - it.skip('throws an error', async () => { + it('throws an error', async () => { await expect( mutate({ mutation: adminUpdateContribution, @@ -1214,24 +1334,32 @@ describe('AdminResolver', () => { email: 'peter@lustig.de', amount: new Decimal(1900), memo: 'Danke Peter!', - creationDate: new Date().toString(), + creationDate: creation + ? creation.contributionDate.toString() + : new Date().toString(), }, }), ).resolves.toEqual( expect.objectContaining({ errors: [ new GraphQLError( - 'The amount (1900 GDD) to be created exceeds the amount (500 GDD) still available for this month.', + 'The amount (1900 GDD) to be created exceeds the amount (1000 GDD) still available for this month.', ), ], }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'The amount (1900 GDD) to be created exceeds the amount (1000 GDD) still available for this month.', + ) + }) }) - describe('creation update is successful changing month', () => { + describe.skip('creation update is successful changing month', () => { // skipped as changing the month is currently disable - it.skip('returns update creation object', async () => { + it('returns update creation object', async () => { await expect( mutate({ mutation: adminUpdateContribution, @@ -1240,7 +1368,9 @@ describe('AdminResolver', () => { email: 'peter@lustig.de', amount: new Decimal(300), memo: 'Danke Peter!', - creationDate: new Date().toString(), + creationDate: creation + ? creation.contributionDate.toString() + : new Date().toString(), }, }), ).resolves.toEqual( @@ -1250,17 +1380,26 @@ describe('AdminResolver', () => { date: expect.any(String), memo: 'Danke Peter!', amount: '300', - creation: ['1000', '1000', '200'], + creation: ['1000', '700', '500'], }, }, }), ) }) + + it('stores the admin update contribution event in the database', async () => { + await expect(EventProtocol.find()).resolves.toContainEqual( + expect.objectContaining({ + type: EventProtocolType.ADMIN_CONTRIBUTION_UPDATE, + userId: admin.id, + }), + ) + }) }) describe('creation update is successful without changing month', () => { // actually this mutation IS changing the month - it.skip('returns update creation object', async () => { + it('returns update creation object', async () => { await expect( mutate({ mutation: adminUpdateContribution, @@ -1269,7 +1408,9 @@ describe('AdminResolver', () => { email: 'peter@lustig.de', amount: new Decimal(200), memo: 'Das war leider zu Viel!', - creationDate: new Date().toString(), + creationDate: creation + ? creation.contributionDate.toString() + : new Date().toString(), }, }), ).resolves.toEqual( @@ -1279,12 +1420,21 @@ describe('AdminResolver', () => { date: expect.any(String), memo: 'Das war leider zu Viel!', amount: '200', - creation: ['1000', '1000', '300'], + creation: ['1000', '800', '500'], }, }, }), ) }) + + it('stores the admin update contribution event in the database', async () => { + await expect(EventProtocol.find()).resolves.toContainEqual( + expect.objectContaining({ + type: EventProtocolType.ADMIN_CONTRIBUTION_UPDATE, + userId: admin.id, + }), + ) + }) }) }) @@ -1304,10 +1454,10 @@ describe('AdminResolver', () => { lastName: 'Lustig', email: 'peter@lustig.de', date: expect.any(String), - memo: 'Herzlich Willkommen bei Gradido!', - amount: '400', + memo: 'Das war leider zu Viel!', + amount: '200', moderator: admin.id, - creation: ['1000', '600', '500'], + creation: ['1000', '800', '500'], }, { id: expect.any(Number), @@ -1318,7 +1468,7 @@ describe('AdminResolver', () => { memo: 'Grundeinkommen', amount: '500', moderator: admin.id, - creation: ['1000', '600', '500'], + creation: ['1000', '800', '500'], }, { id: expect.any(Number), @@ -1365,6 +1515,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('Contribution not found for given id: -1') + }) }) describe('admin deletes own user contribution', () => { @@ -1414,6 +1568,15 @@ describe('AdminResolver', () => { }), ) }) + + it('stores the admin delete contribution event in the database', async () => { + await expect(EventProtocol.find()).resolves.toContainEqual( + expect.objectContaining({ + type: EventProtocolType.ADMIN_CONTRIBUTION_DELETE, + userId: admin.id, + }), + ) + }) }) }) @@ -1433,6 +1596,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('Contribution not found for given id: -1') + }) }) describe('confirm own creation', () => { @@ -1460,6 +1627,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('Moderator can not confirm own contribution') + }) }) describe('confirm creation for other user', () => { @@ -1488,6 +1659,14 @@ describe('AdminResolver', () => { ) }) + it('stores the contribution confirm event in the database', async () => { + await expect(EventProtocol.find()).resolves.toContainEqual( + expect.objectContaining({ + type: EventProtocolType.CONTRIBUTION_CONFIRM, + }), + ) + }) + it('creates a transaction', async () => { const transaction = await DbTransaction.find() expect(transaction[0].amount.toString()).toBe('450') @@ -1512,6 +1691,14 @@ describe('AdminResolver', () => { }), ) }) + + it('stores the send confirmation email event in the database', async () => { + await expect(EventProtocol.find()).resolves.toContainEqual( + expect.objectContaining({ + type: EventProtocolType.SEND_CONFIRMATION_EMAIL, + }), + ) + }) }) describe('confirm two creations one after the other quickly', () => { @@ -2052,6 +2239,12 @@ describe('AdminResolver', () => { ) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'Start-Date is not initialized. A Start-Date must be set!', + ) + }) + it('returns an error if missing endDate', async () => { await expect( mutate({ @@ -2068,6 +2261,12 @@ describe('AdminResolver', () => { ) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'End-Date is not initialized. An End-Date must be set!', + ) + }) + it('returns an error if endDate is before startDate', async () => { await expect( mutate({ @@ -2087,6 +2286,12 @@ describe('AdminResolver', () => { ) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + `The value of validFrom must before or equals the validTo!`, + ) + }) + it('returns an error if name is an empty string', async () => { await expect( mutate({ @@ -2103,6 +2308,10 @@ describe('AdminResolver', () => { ) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('The name must be initialized!') + }) + it('returns an error if name is shorter than 5 characters', async () => { await expect( mutate({ @@ -2123,6 +2332,12 @@ describe('AdminResolver', () => { ) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + `The value of 'name' with a length of 3 did not fulfill the requested bounderies min=5 and max=100`, + ) + }) + it('returns an error if name is longer than 100 characters', async () => { await expect( mutate({ @@ -2143,6 +2358,12 @@ describe('AdminResolver', () => { ) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + `The value of 'name' with a length of 101 did not fulfill the requested bounderies min=5 and max=100`, + ) + }) + it('returns an error if memo is an empty string', async () => { await expect( mutate({ @@ -2159,6 +2380,10 @@ describe('AdminResolver', () => { ) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('The memo must be initialized!') + }) + it('returns an error if memo is shorter than 5 characters', async () => { await expect( mutate({ @@ -2179,6 +2404,12 @@ describe('AdminResolver', () => { ) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + `The value of 'memo' with a length of 3 did not fulfill the requested bounderies min=5 and max=255`, + ) + }) + it('returns an error if memo is longer than 255 characters', async () => { await expect( mutate({ @@ -2199,6 +2430,12 @@ describe('AdminResolver', () => { ) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + `The value of 'memo' with a length of 256 did not fulfill the requested bounderies min=5 and max=255`, + ) + }) + it('returns an error if amount is not positive', async () => { await expect( mutate({ @@ -2216,6 +2453,12 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith( + 'The amount=0 must be initialized with a positiv value!', + ) + }) }) describe('listContributionLinks', () => { @@ -2271,6 +2514,10 @@ describe('AdminResolver', () => { }) }) + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('Contribution Link not found to given id: -1') + }) + describe('valid id', () => { let linkId: number beforeAll(async () => { @@ -2336,6 +2583,10 @@ describe('AdminResolver', () => { }), ) }) + + it('logs the error thrown', () => { + expect(logger.error).toBeCalledWith('Contribution Link not found to given id: -1') + }) }) describe('valid id', () => { diff --git a/backend/src/graphql/resolver/AdminResolver.ts b/backend/src/graphql/resolver/AdminResolver.ts index 4fd85dc0f..aab84e911 100644 --- a/backend/src/graphql/resolver/AdminResolver.ts +++ b/backend/src/graphql/resolver/AdminResolver.ts @@ -64,6 +64,15 @@ import { ContributionMessageType } from '@enum/MessageType' import { ContributionMessage } from '@model/ContributionMessage' import { sendContributionConfirmedEmail } from '@/mailer/sendContributionConfirmedEmail' import { sendAddedContributionMessageEmail } from '@/mailer/sendAddedContributionMessageEmail' +import { eventProtocol } from '@/event/EventProtocolEmitter' +import { + Event, + EventAdminContributionCreate, + EventAdminContributionDelete, + EventAdminContributionUpdate, + EventContributionConfirm, + EventSendConfirmationEmail, +} from '@/event/Event' import { ContributionListResult } from '../model/Contribution' // const EMAIL_OPT_IN_REGISTER = 1 @@ -145,11 +154,13 @@ export class AdminResolver { const user = await dbUser.findOne({ id: userId }) // user exists ? if (!user) { + logger.error(`Could not find user with userId: ${userId}`) throw new Error(`Could not find user with userId: ${userId}`) } // administrator user changes own role? const moderatorUser = getUser(context) if (moderatorUser.id === userId) { + logger.error('Administrator can not change his own role!') throw new Error('Administrator can not change his own role!') } // change isAdmin @@ -158,6 +169,7 @@ export class AdminResolver { if (isAdmin === true) { user.isAdmin = new Date() } else { + logger.error('User is already a usual user!') throw new Error('User is already a usual user!') } break @@ -165,6 +177,7 @@ export class AdminResolver { if (isAdmin === false) { user.isAdmin = null } else { + logger.error('User is already admin!') throw new Error('User is already admin!') } break @@ -183,11 +196,13 @@ export class AdminResolver { const user = await dbUser.findOne({ id: userId }) // user exists ? if (!user) { + logger.error(`Could not find user with userId: ${userId}`) throw new Error(`Could not find user with userId: ${userId}`) } // moderator user disabled own account? const moderatorUser = getUser(context) if (moderatorUser.id === userId) { + logger.error('Moderator can not delete his own account!') throw new Error('Moderator can not delete his own account!') } // soft-delete user @@ -201,9 +216,11 @@ export class AdminResolver { async unDeleteUser(@Arg('userId', () => Int) userId: number): Promise { const user = await dbUser.findOne({ id: userId }, { withDeleted: true }) if (!user) { + logger.error(`Could not find user with userId: ${userId}`) throw new Error(`Could not find user with userId: ${userId}`) } if (!user.deletedAt) { + logger.error('User is not deleted') throw new Error('User is not deleted') } await user.recover() @@ -240,6 +257,8 @@ export class AdminResolver { logger.error('Contribution could not be saved, Email is not activated') throw new Error('Contribution could not be saved, Email is not activated') } + + const event = new Event() const moderator = getUser(context) logger.trace('moderator: ', moderator.id) const creations = await getUserCreation(emailContact.userId) @@ -258,7 +277,17 @@ export class AdminResolver { contribution.contributionStatus = ContributionStatus.PENDING logger.trace('contribution to save', contribution) + await DbContribution.save(contribution) + + const eventAdminCreateContribution = new EventAdminContributionCreate() + eventAdminCreateContribution.userId = moderator.id + eventAdminCreateContribution.amount = amount + eventAdminCreateContribution.contributionId = contribution.id + await eventProtocol.writeEvent( + event.setEventAdminContributionCreate(eventAdminCreateContribution), + ) + return getUserCreation(emailContact.userId) } @@ -319,7 +348,6 @@ export class AdminResolver { const contributionToUpdate = await DbContribution.findOne({ where: { id, confirmedAt: IsNull() }, }) - if (!contributionToUpdate) { logger.error('No contribution found to given id.') throw new Error('No contribution found to given id.') @@ -337,6 +365,7 @@ export class AdminResolver { const creationDateObj = new Date(creationDate) let creations = await getUserCreation(user.id) + if (contributionToUpdate.contributionDate.getMonth() === creationDateObj.getMonth()) { creations = updateCreations(creations, contributionToUpdate) } else { @@ -353,6 +382,7 @@ export class AdminResolver { contributionToUpdate.contributionStatus = ContributionStatus.PENDING await DbContribution.save(contributionToUpdate) + const result = new AdminUpdateContribution() result.amount = amount result.memo = contributionToUpdate.memo @@ -360,6 +390,15 @@ export class AdminResolver { result.creation = await getUserCreation(user.id) + const event = new Event() + const eventAdminContributionUpdate = new EventAdminContributionUpdate() + eventAdminContributionUpdate.userId = user.id + eventAdminContributionUpdate.amount = amount + eventAdminContributionUpdate.contributionId = contributionToUpdate.id + await eventProtocol.writeEvent( + event.setEventAdminContributionUpdate(eventAdminContributionUpdate), + ) + return result } @@ -420,6 +459,16 @@ export class AdminResolver { contribution.deletedBy = moderator.id await contribution.save() const res = await contribution.softRemove() + + const event = new Event() + const eventAdminContributionDelete = new EventAdminContributionDelete() + eventAdminContributionDelete.userId = contribution.userId + eventAdminContributionDelete.amount = contribution.amount + eventAdminContributionDelete.contributionId = contribution.id + await eventProtocol.writeEvent( + event.setEventAdminContributionDelete(eventAdminContributionDelete), + ) + return !!res } @@ -515,6 +564,13 @@ export class AdminResolver { } finally { await queryRunner.release() } + + const event = new Event() + const eventContributionConfirm = new EventContributionConfirm() + eventContributionConfirm.userId = user.id + eventContributionConfirm.amount = contribution.amount + eventContributionConfirm.contributionId = contribution.id + await eventProtocol.writeEvent(event.setEventContributionConfirm(eventContributionConfirm)) return true } @@ -576,6 +632,13 @@ export class AdminResolver { // In case EMails are disabled log the activation link for the user if (!emailSent) { logger.info(`Account confirmation link: ${activationLink}`) + } else { + const event = new Event() + const eventSendConfirmationEmail = new EventSendConfirmationEmail() + eventSendConfirmationEmail.userId = user.id + await eventProtocol.writeEvent( + event.setEventSendConfirmationEmail(eventSendConfirmationEmail), + ) } return true @@ -768,9 +831,11 @@ export class AdminResolver { relations: ['user'], }) if (!contribution) { + logger.error('Contribution not found') throw new Error('Contribution not found') } if (contribution.userId === user.id) { + logger.error('Admin can not answer on own contribution') throw new Error('Admin can not answer on own contribution') } if (!contribution.user.emailContact) {