diff --git a/admin/package.json b/admin/package.json index 8270c4da6..5bb3d1cd3 100644 --- a/admin/package.json +++ b/admin/package.json @@ -86,5 +86,10 @@ "> 1%", "last 2 versions", "not ie <= 10" - ] + ], + "nodemonConfig": { + "ignore": [ + "**/*.spec.js" + ] + } } diff --git a/backend/.env.dist b/backend/.env.dist index ba5b89fa9..3e54b0566 100644 --- a/backend/.env.dist +++ b/backend/.env.dist @@ -55,9 +55,6 @@ EMAIL_CODE_REQUEST_TIME=10 # Webhook WEBHOOK_ELOPAGE_SECRET=secret -# EventProtocol -EVENT_PROTOCOL_DISABLED=false - # SET LOG LEVEL AS NEEDED IN YOUR .ENV # POSSIBLE VALUES: all | trace | debug | info | warn | error | fatal # LOG_LEVEL=info diff --git a/backend/.env.template b/backend/.env.template index f73b87353..e75798325 100644 --- a/backend/.env.template +++ b/backend/.env.template @@ -54,9 +54,6 @@ EMAIL_CODE_REQUEST_TIME=$EMAIL_CODE_REQUEST_TIME # Webhook WEBHOOK_ELOPAGE_SECRET=$WEBHOOK_ELOPAGE_SECRET -# EventProtocol -EVENT_PROTOCOL_DISABLED=$EVENT_PROTOCOL_DISABLED - # Federation FEDERATION_DHT_TOPIC=$FEDERATION_DHT_TOPIC FEDERATION_DHT_SEED=$FEDERATION_DHT_SEED diff --git a/backend/package.json b/backend/package.json index bfcd61d5b..9a36c2ff8 100644 --- a/backend/package.json +++ b/backend/package.json @@ -72,5 +72,8 @@ "ts-node": "^10.0.0", "tsconfig-paths": "^3.14.0", "typescript": "^4.3.4" + }, + "nodemonConfig": { + "ignore": ["**/*.test.ts"] } } diff --git a/backend/src/config/index.ts b/backend/src/config/index.ts index d010b4ab0..4cca9e0e2 100644 --- a/backend/src/config/index.ts +++ b/backend/src/config/index.ts @@ -17,7 +17,7 @@ const constants = { LOG_LEVEL: process.env.LOG_LEVEL || 'info', CONFIG_VERSION: { DEFAULT: 'DEFAULT', - EXPECTED: 'v14.2022-12-22', + EXPECTED: 'v15.2023-02-07', CURRENT: '', }, } @@ -99,11 +99,6 @@ const webhook = { WEBHOOK_ELOPAGE_SECRET: process.env.WEBHOOK_ELOPAGE_SECRET || 'secret', } -const eventProtocol = { - // global switch to enable writing of EventProtocol-Entries - EVENT_PROTOCOL_DISABLED: process.env.EVENT_PROTOCOL_DISABLED === 'true' || false, -} - // This is needed by graphql-directive-auth process.env.APP_SECRET = server.JWT_SECRET @@ -139,7 +134,6 @@ const CONFIG = { ...email, ...loginServer, ...webhook, - ...eventProtocol, ...federation, } diff --git a/backend/src/event/Event.ts b/backend/src/event/Event.ts index 09a31d4e0..6a1233224 100644 --- a/backend/src/event/Event.ts +++ b/backend/src/event/Event.ts @@ -1,4 +1,3 @@ -import { EventProtocol } from '@entity/EventProtocol' import decimal from 'decimal.js-light' import { EventProtocolType } from './EventProtocolType' @@ -87,21 +86,6 @@ export class EventDeleteContributionLink extends EventBasicCt {} export class EventUpdateContributionLink extends EventBasicCt {} export class Event { - constructor() - constructor(event?: EventProtocol) { - if (event) { - this.id = event.id - this.type = event.type - this.createdAt = event.createdAt - this.userId = event.userId - this.xUserId = event.xUserId - this.xCommunityId = event.xCommunityId - this.transactionId = event.transactionId - this.contributionId = event.contributionId - this.amount = event.amount - } - } - public setEventBasic(): Event { this.type = EventProtocolType.BASIC this.createdAt = new Date() diff --git a/backend/src/event/EventProtocolEmitter.ts b/backend/src/event/EventProtocolEmitter.ts index b4b22bce1..a87e8a256 100644 --- a/backend/src/event/EventProtocolEmitter.ts +++ b/backend/src/event/EventProtocolEmitter.ts @@ -1,41 +1,17 @@ import { Event } from '@/event/Event' import { backendLogger as logger } from '@/server/logger' import { EventProtocol } from '@entity/EventProtocol' -import CONFIG from '@/config' -class EventProtocolEmitter { - /* }extends EventEmitter { */ - private events: Event[] - - /* - public addEvent(event: Event) { - this.events.push(event) - } - - public getEvents(): Event[] { - return this.events - } - */ - - public isDisabled() { - logger.info(`EventProtocol - isDisabled=${CONFIG.EVENT_PROTOCOL_DISABLED}`) - return CONFIG.EVENT_PROTOCOL_DISABLED === true - } - - public async writeEvent(event: Event): Promise { - if (!eventProtocol.isDisabled()) { - logger.info(`writeEvent(${JSON.stringify(event)})`) - const dbEvent = new EventProtocol() - dbEvent.type = event.type - dbEvent.createdAt = event.createdAt - dbEvent.userId = event.userId - if (event.xUserId) dbEvent.xUserId = event.xUserId - if (event.xCommunityId) dbEvent.xCommunityId = event.xCommunityId - if (event.contributionId) dbEvent.contributionId = event.contributionId - if (event.transactionId) dbEvent.transactionId = event.transactionId - if (event.amount) dbEvent.amount = event.amount - await dbEvent.save() - } - } +export const writeEvent = async (event: Event): Promise => { + logger.info('writeEvent', event) + const dbEvent = new EventProtocol() + dbEvent.type = event.type + dbEvent.createdAt = event.createdAt + dbEvent.userId = event.userId + dbEvent.xUserId = event.xUserId || null + dbEvent.xCommunityId = event.xCommunityId || null + dbEvent.contributionId = event.contributionId || null + dbEvent.transactionId = event.transactionId || null + dbEvent.amount = event.amount || null + return dbEvent.save() } -export const eventProtocol = new EventProtocolEmitter() diff --git a/backend/src/graphql/resolver/BalanceResolver.ts b/backend/src/graphql/resolver/BalanceResolver.ts index 26f9cd656..65cccf4d4 100644 --- a/backend/src/graphql/resolver/BalanceResolver.ts +++ b/backend/src/graphql/resolver/BalanceResolver.ts @@ -15,6 +15,8 @@ import { calculateDecay } from '@/util/decay' import { RIGHTS } from '@/auth/RIGHTS' import { GdtResolver } from './GdtResolver' +import { getLastTransaction } from './util/getLastTransaction' + @Resolver() export class BalanceResolver { @Authorized([RIGHTS.BALANCE]) @@ -32,7 +34,7 @@ export class BalanceResolver { const lastTransaction = context.lastTransaction ? context.lastTransaction - : await dbTransaction.findOne({ userId: user.id }, { order: { id: 'DESC' } }) + : await getLastTransaction(user.id) logger.debug(`lastTransaction=${lastTransaction}`) diff --git a/backend/src/graphql/resolver/ContributionLinkResolver.test.ts b/backend/src/graphql/resolver/ContributionLinkResolver.test.ts index 46296e009..49bca2c42 100644 --- a/backend/src/graphql/resolver/ContributionLinkResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionLinkResolver.test.ts @@ -319,27 +319,6 @@ describe('Contribution Links', () => { ) }) - it('returns an error if name is an empty string', async () => { - jest.clearAllMocks() - await expect( - mutate({ - mutation: createContributionLink, - variables: { - ...variables, - name: '', - }, - }), - ).resolves.toEqual( - expect.objectContaining({ - errors: [new GraphQLError('The name must be initialized')], - }), - ) - }) - - 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 () => { jest.clearAllMocks() await expect( @@ -382,27 +361,6 @@ describe('Contribution Links', () => { expect(logger.error).toBeCalledWith('The value of name is too long', 101) }) - it('returns an error if memo is an empty string', async () => { - jest.clearAllMocks() - await expect( - mutate({ - mutation: createContributionLink, - variables: { - ...variables, - memo: '', - }, - }), - ).resolves.toEqual( - expect.objectContaining({ - errors: [new GraphQLError('The memo must be initialized')], - }), - ) - }) - - 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 () => { jest.clearAllMocks() await expect( diff --git a/backend/src/graphql/resolver/ContributionLinkResolver.ts b/backend/src/graphql/resolver/ContributionLinkResolver.ts index 6a7a71391..39f202848 100644 --- a/backend/src/graphql/resolver/ContributionLinkResolver.ts +++ b/backend/src/graphql/resolver/ContributionLinkResolver.ts @@ -40,20 +40,12 @@ export class ContributionLinkResolver { }: ContributionLinkArgs, ): Promise { isStartEndDateValid(validFrom, validTo) - // TODO: this should be enforced by the schema. - if (!name) { - throw new LogError('The name must be initialized') - } if (name.length < CONTRIBUTIONLINK_NAME_MIN_CHARS) { throw new LogError('The value of name is too short', name.length) } if (name.length > CONTRIBUTIONLINK_NAME_MAX_CHARS) { throw new LogError('The value of name is too long', name.length) } - // TODO: this should be enforced by the schema. - if (!memo) { - throw new LogError('The memo must be initialized') - } if (memo.length < MEMO_MIN_CHARS) { throw new LogError('The value of memo is too short', memo.length) } diff --git a/backend/src/graphql/resolver/ContributionMessageResolver.test.ts b/backend/src/graphql/resolver/ContributionMessageResolver.test.ts index 36d78c382..f3e5e865d 100644 --- a/backend/src/graphql/resolver/ContributionMessageResolver.test.ts +++ b/backend/src/graphql/resolver/ContributionMessageResolver.test.ts @@ -99,14 +99,18 @@ describe('ContributionMessageResolver', () => { }), ).resolves.toEqual( expect.objectContaining({ - errors: [new GraphQLError('ContributionMessage was not sent successfully')], + errors: [ + new GraphQLError( + 'ContributionMessage was not sent successfully: Error: Contribution not found', + ), + ], }), ) }) it('logs the error thrown', () => { expect(logger.error).toBeCalledWith( - 'ContributionMessage was not sent successfully', + 'ContributionMessage was not sent successfully: Error: Contribution not found', new Error('Contribution not found'), ) }) @@ -135,14 +139,18 @@ describe('ContributionMessageResolver', () => { }), ).resolves.toEqual( expect.objectContaining({ - errors: [new GraphQLError('ContributionMessage was not sent successfully')], + errors: [ + new GraphQLError( + 'ContributionMessage was not sent successfully: Error: Admin can not answer on his own contribution', + ), + ], }), ) }) it('logs the error thrown', () => { expect(logger.error).toBeCalledWith( - 'ContributionMessage was not sent successfully', + 'ContributionMessage was not sent successfully: Error: Admin can not answer on his own contribution', new Error('Admin can not answer on his own contribution'), ) }) @@ -229,14 +237,18 @@ describe('ContributionMessageResolver', () => { }), ).resolves.toEqual( expect.objectContaining({ - errors: [new GraphQLError('ContributionMessage was not sent successfully')], + errors: [ + new GraphQLError( + 'ContributionMessage was not sent successfully: Error: Contribution not found', + ), + ], }), ) }) it('logs the error thrown', () => { expect(logger.error).toBeCalledWith( - 'ContributionMessage was not sent successfully', + 'ContributionMessage was not sent successfully: Error: Contribution not found', new Error('Contribution not found'), ) }) @@ -257,14 +269,18 @@ describe('ContributionMessageResolver', () => { }), ).resolves.toEqual( expect.objectContaining({ - errors: [new GraphQLError('ContributionMessage was not sent successfully')], + errors: [ + new GraphQLError( + 'ContributionMessage was not sent successfully: Error: Can not send message to contribution of another user', + ), + ], }), ) }) it('logs the error thrown', () => { expect(logger.error).toBeCalledWith( - 'ContributionMessage was not sent successfully', + 'ContributionMessage was not sent successfully: Error: Can not send message to contribution of another user', new Error('Can not send message to contribution of another user'), ) }) diff --git a/backend/src/graphql/resolver/ContributionMessageResolver.ts b/backend/src/graphql/resolver/ContributionMessageResolver.ts index 3e6f86e53..4248946b1 100644 --- a/backend/src/graphql/resolver/ContributionMessageResolver.ts +++ b/backend/src/graphql/resolver/ContributionMessageResolver.ts @@ -54,7 +54,7 @@ export class ContributionMessageResolver { await queryRunner.commitTransaction() } catch (e) { await queryRunner.rollbackTransaction() - throw new LogError('ContributionMessage was not sent successfully', e) + throw new LogError(`ContributionMessage was not sent successfully: ${e}`, e) } finally { await queryRunner.release() } @@ -144,7 +144,7 @@ export class ContributionMessageResolver { await queryRunner.commitTransaction() } catch (e) { await queryRunner.rollbackTransaction() - throw new LogError('ContributionMessage was not sent successfully', e) + throw new LogError(`ContributionMessage was not sent successfully: ${e}`, e) } finally { await queryRunner.release() } diff --git a/backend/src/graphql/resolver/ContributionResolver.ts b/backend/src/graphql/resolver/ContributionResolver.ts index c68c34f99..5fde598c0 100644 --- a/backend/src/graphql/resolver/ContributionResolver.ts +++ b/backend/src/graphql/resolver/ContributionResolver.ts @@ -46,7 +46,7 @@ import { EventAdminContributionDelete, EventAdminContributionUpdate, } from '@/event/Event' -import { eventProtocol } from '@/event/EventProtocolEmitter' +import { writeEvent } from '@/event/EventProtocolEmitter' import { calculateDecay } from '@/util/decay' import { sendContributionConfirmedEmail, @@ -55,6 +55,8 @@ import { import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK' import LogError from '@/server/LogError' +import { getLastTransaction } from './util/getLastTransaction' + @Resolver() export class ContributionResolver { @Authorized([RIGHTS.CREATE_CONTRIBUTION]) @@ -95,7 +97,7 @@ export class ContributionResolver { eventCreateContribution.userId = user.id eventCreateContribution.amount = amount eventCreateContribution.contributionId = contribution.id - await eventProtocol.writeEvent(event.setEventContributionCreate(eventCreateContribution)) + await writeEvent(event.setEventContributionCreate(eventCreateContribution)) return new UnconfirmedContribution(contribution, user, creations) } @@ -128,7 +130,7 @@ export class ContributionResolver { eventDeleteContribution.userId = user.id eventDeleteContribution.contributionId = contribution.id eventDeleteContribution.amount = contribution.amount - await eventProtocol.writeEvent(event.setEventContributionDelete(eventDeleteContribution)) + await writeEvent(event.setEventContributionDelete(eventDeleteContribution)) const res = await contribution.softRemove() return !!res @@ -281,7 +283,7 @@ export class ContributionResolver { eventUpdateContribution.userId = user.id eventUpdateContribution.contributionId = contributionId eventUpdateContribution.amount = amount - await eventProtocol.writeEvent(event.setEventContributionUpdate(eventUpdateContribution)) + await writeEvent(event.setEventContributionUpdate(eventUpdateContribution)) return new UnconfirmedContribution(contributionToUpdate, user, creations) } @@ -343,9 +345,7 @@ export class ContributionResolver { eventAdminCreateContribution.userId = moderator.id eventAdminCreateContribution.amount = amount eventAdminCreateContribution.contributionId = contribution.id - await eventProtocol.writeEvent( - event.setEventAdminContributionCreate(eventAdminCreateContribution), - ) + await writeEvent(event.setEventAdminContributionCreate(eventAdminCreateContribution)) return getUserCreation(emailContact.userId, clientTimezoneOffset) } @@ -445,9 +445,7 @@ export class ContributionResolver { eventAdminContributionUpdate.userId = emailContact.user.id eventAdminContributionUpdate.amount = amount eventAdminContributionUpdate.contributionId = contributionToUpdate.id - await eventProtocol.writeEvent( - event.setEventAdminContributionUpdate(eventAdminContributionUpdate), - ) + await writeEvent(event.setEventAdminContributionUpdate(eventAdminContributionUpdate)) return result } @@ -523,9 +521,7 @@ export class ContributionResolver { eventAdminContributionDelete.userId = contribution.userId eventAdminContributionDelete.amount = contribution.amount eventAdminContributionDelete.contributionId = contribution.id - await eventProtocol.writeEvent( - event.setEventAdminContributionDelete(eventAdminContributionDelete), - ) + await writeEvent(event.setEventAdminContributionDelete(eventAdminContributionDelete)) sendContributionDeniedEmail({ firstName: user.firstName, lastName: user.lastName, @@ -582,16 +578,11 @@ export class ContributionResolver { const queryRunner = getConnection().createQueryRunner() await queryRunner.connect() await queryRunner.startTransaction('REPEATABLE READ') // 'READ COMMITTED') - try { - const lastTransaction = await queryRunner.manager - .createQueryBuilder() - .select('transaction') - .from(DbTransaction, 'transaction') - .where('transaction.userId = :id', { id: contribution.userId }) - .orderBy('transaction.id', 'DESC') - .getOne() - logger.info('lastTransaction ID', lastTransaction ? lastTransaction.id : 'undefined') + const lastTransaction = await getLastTransaction(contribution.userId) + logger.info('lastTransaction ID', lastTransaction ? lastTransaction.id : 'undefined') + + try { let newBalance = new Decimal(0) let decay: Decay | null = null if (lastTransaction) { @@ -647,7 +638,7 @@ export class ContributionResolver { eventContributionConfirm.userId = user.id eventContributionConfirm.amount = contribution.amount eventContributionConfirm.contributionId = contribution.id - await eventProtocol.writeEvent(event.setEventContributionConfirm(eventContributionConfirm)) + await writeEvent(event.setEventContributionConfirm(eventContributionConfirm)) } finally { releaseLock() } diff --git a/backend/src/graphql/resolver/TransactionLinkResolver.ts b/backend/src/graphql/resolver/TransactionLinkResolver.ts index df70b4bc9..b3376c65f 100644 --- a/backend/src/graphql/resolver/TransactionLinkResolver.ts +++ b/backend/src/graphql/resolver/TransactionLinkResolver.ts @@ -33,6 +33,8 @@ import { executeTransaction } from './TransactionResolver' import QueryLinkResult from '@union/QueryLinkResult' import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK' +import { getLastTransaction } from './util/getLastTransaction' + // TODO: do not export, test it inside the resolver export const transactionLinkCode = (date: Date): string => { const time = date.getTime().toString(16) @@ -275,13 +277,7 @@ export class TransactionLinkResolver { await queryRunner.manager.insert(DbContribution, contribution) - const lastTransaction = await queryRunner.manager - .createQueryBuilder() - .select('transaction') - .from(DbTransaction, 'transaction') - .where('transaction.userId = :id', { id: user.id }) - .orderBy('transaction.id', 'DESC') - .getOne() + const lastTransaction = await getLastTransaction(user.id) let newBalance = new Decimal(0) let decay: Decay | null = null diff --git a/backend/src/graphql/resolver/TransactionResolver.ts b/backend/src/graphql/resolver/TransactionResolver.ts index 2f97596b2..bedf8c533 100644 --- a/backend/src/graphql/resolver/TransactionResolver.ts +++ b/backend/src/graphql/resolver/TransactionResolver.ts @@ -30,7 +30,7 @@ import { sendTransactionReceivedEmail, } from '@/emails/sendEmailVariants' import { Event, EventTransactionReceive, EventTransactionSend } from '@/event/Event' -import { eventProtocol } from '@/event/EventProtocolEmitter' +import { writeEvent } from '@/event/EventProtocolEmitter' import { BalanceResolver } from './BalanceResolver' import { MEMO_MAX_CHARS, MEMO_MIN_CHARS } from './const/const' @@ -38,6 +38,8 @@ import { findUserByEmail } from './UserResolver' import { TRANSACTIONS_LOCK } from '@/util/TRANSACTIONS_LOCK' +import { getLastTransaction } from './util/getLastTransaction' + export const executeTransaction = async ( amount: Decimal, memo: string, @@ -144,16 +146,14 @@ export const executeTransaction = async ( eventTransactionSend.xUserId = transactionSend.linkedUserId eventTransactionSend.transactionId = transactionSend.id eventTransactionSend.amount = transactionSend.amount.mul(-1) - await eventProtocol.writeEvent(new Event().setEventTransactionSend(eventTransactionSend)) + await writeEvent(new Event().setEventTransactionSend(eventTransactionSend)) const eventTransactionReceive = new EventTransactionReceive() eventTransactionReceive.userId = transactionReceive.userId eventTransactionReceive.xUserId = transactionReceive.linkedUserId eventTransactionReceive.transactionId = transactionReceive.id eventTransactionReceive.amount = transactionReceive.amount - await eventProtocol.writeEvent( - new Event().setEventTransactionReceive(eventTransactionReceive), - ) + await writeEvent(new Event().setEventTransactionReceive(eventTransactionReceive)) } catch (e) { await queryRunner.rollbackTransaction() logger.error(`Transaction was not successful: ${e}`) @@ -208,10 +208,7 @@ export class TransactionResolver { logger.info(`transactionList(user=${user.firstName}.${user.lastName}, ${user.emailId})`) // find current balance - const lastTransaction = await dbTransaction.findOne( - { userId: user.id }, - { order: { id: 'DESC' }, relations: ['contribution'] }, - ) + const lastTransaction = await getLastTransaction(user.id, ['contribution']) logger.debug(`lastTransaction=${lastTransaction}`) const balanceResolver = new BalanceResolver() diff --git a/backend/src/graphql/resolver/UserResolver.ts b/backend/src/graphql/resolver/UserResolver.ts index d92958009..5ebf5b445 100644 --- a/backend/src/graphql/resolver/UserResolver.ts +++ b/backend/src/graphql/resolver/UserResolver.ts @@ -48,7 +48,7 @@ import { klicktippNewsletterStateMiddleware } from '@/middleware/klicktippMiddle import { klicktippSignIn } from '@/apis/KlicktippController' import { RIGHTS } from '@/auth/RIGHTS' import { hasElopageBuys } from '@/util/hasElopageBuys' -import { eventProtocol } from '@/event/EventProtocolEmitter' +import { writeEvent } from '@/event/EventProtocolEmitter' import { Event, EventLogin, @@ -179,7 +179,7 @@ export class UserResolver { }) const ev = new EventLogin() ev.userId = user.id - eventProtocol.writeEvent(new Event().setEventLogin(ev)) + writeEvent(new Event().setEventLogin(ev)) logger.info(`successful Login: ${JSON.stringify(user, null, 2)}`) return user } @@ -251,9 +251,7 @@ export class UserResolver { }) const eventSendAccountMultiRegistrationEmail = new EventSendAccountMultiRegistrationEmail() eventSendAccountMultiRegistrationEmail.userId = foundUser.id - eventProtocol.writeEvent( - event.setEventSendConfirmationEmail(eventSendAccountMultiRegistrationEmail), - ) + writeEvent(event.setEventSendConfirmationEmail(eventSendAccountMultiRegistrationEmail)) logger.info( `sendAccountMultiRegistrationEmail by ${firstName} ${lastName} to ${foundUser.firstName} ${foundUser.lastName} <${email}>`, ) @@ -336,7 +334,7 @@ export class UserResolver { }) logger.info(`sendAccountActivationEmail of ${firstName}.${lastName} to ${email}`) eventSendConfirmEmail.userId = dbUser.id - eventProtocol.writeEvent(event.setEventSendConfirmationEmail(eventSendConfirmEmail)) + writeEvent(event.setEventSendConfirmationEmail(eventSendConfirmEmail)) if (!emailSent) { logger.debug(`Account confirmation link: ${activationLink}`) @@ -354,10 +352,10 @@ export class UserResolver { if (redeemCode) { eventRedeemRegister.userId = dbUser.id - await eventProtocol.writeEvent(event.setEventRedeemRegister(eventRedeemRegister)) + await writeEvent(event.setEventRedeemRegister(eventRedeemRegister)) } else { eventRegister.userId = dbUser.id - await eventProtocol.writeEvent(event.setEventRegister(eventRegister)) + await writeEvent(event.setEventRegister(eventRegister)) } return new User(dbUser) @@ -477,7 +475,7 @@ export class UserResolver { const eventActivateAccount = new EventActivateAccount() eventActivateAccount.userId = user.id - eventProtocol.writeEvent(event.setEventActivateAccount(eventActivateAccount)) + writeEvent(event.setEventActivateAccount(eventActivateAccount)) } catch (e) { await queryRunner.rollbackTransaction() throw new LogError('Error on writing User and User Contact data', e) @@ -824,9 +822,7 @@ export class UserResolver { const event = new Event() const eventSendConfirmationEmail = new EventSendConfirmationEmail() eventSendConfirmationEmail.userId = user.id - await eventProtocol.writeEvent( - event.setEventSendConfirmationEmail(eventSendConfirmationEmail), - ) + await writeEvent(event.setEventSendConfirmationEmail(eventSendConfirmationEmail)) } return true diff --git a/backend/src/graphql/resolver/util/getLastTransaction.ts b/backend/src/graphql/resolver/util/getLastTransaction.ts new file mode 100644 index 000000000..5b3e862c2 --- /dev/null +++ b/backend/src/graphql/resolver/util/getLastTransaction.ts @@ -0,0 +1,14 @@ +import { Transaction as DbTransaction } from '@entity/Transaction' + +export const getLastTransaction = async ( + userId: number, + relations?: string[], +): Promise => { + return DbTransaction.findOne( + { userId }, + { + order: { balanceDate: 'DESC', id: 'DESC' }, + relations, + }, + ) +} diff --git a/backend/src/util/validate.ts b/backend/src/util/validate.ts index 397a38730..482e9eb50 100644 --- a/backend/src/util/validate.ts +++ b/backend/src/util/validate.ts @@ -1,10 +1,10 @@ import { calculateDecay } from './decay' import Decimal from 'decimal.js-light' -import { Transaction } from '@entity/Transaction' import { Decay } from '@model/Decay' import { getCustomRepository } from '@dbTools/typeorm' import { TransactionLinkRepository } from '@repository/TransactionLink' import { TransactionLink as dbTransactionLink } from '@entity/TransactionLink' +import { getLastTransaction } from '../graphql/resolver/util/getLastTransaction' function isStringBoolean(value: string): boolean { const lowerValue = value.toLowerCase() @@ -20,7 +20,7 @@ async function calculateBalance( time: Date, transactionLink?: dbTransactionLink | null, ): Promise<{ balance: Decimal; decay: Decay; lastTransactionId: number } | null> { - const lastTransaction = await Transaction.findOne({ userId }, { order: { id: 'DESC' } }) + const lastTransaction = await getLastTransaction(userId) if (!lastTransaction) return null const decay = calculateDecay(lastTransaction.balance, lastTransaction.balanceDate, time) diff --git a/database/entity/0050-add_messageId_to_event_protocol/EventProtocol.ts b/database/entity/0050-add_messageId_to_event_protocol/EventProtocol.ts index d4dbc526f..e457cc0a3 100644 --- a/database/entity/0050-add_messageId_to_event_protocol/EventProtocol.ts +++ b/database/entity/0050-add_messageId_to_event_protocol/EventProtocol.ts @@ -16,17 +16,17 @@ export class EventProtocol extends BaseEntity { @Column({ name: 'user_id', unsigned: true, nullable: false }) userId: number - @Column({ name: 'x_user_id', unsigned: true, nullable: true }) - xUserId: number + @Column({ name: 'x_user_id', type: 'int', unsigned: true, nullable: true }) + xUserId: number | null - @Column({ name: 'x_community_id', unsigned: true, nullable: true }) - xCommunityId: number + @Column({ name: 'x_community_id', type: 'int', unsigned: true, nullable: true }) + xCommunityId: number | null - @Column({ name: 'transaction_id', unsigned: true, nullable: true }) - transactionId: number + @Column({ name: 'transaction_id', type: 'int', unsigned: true, nullable: true }) + transactionId: number | null - @Column({ name: 'contribution_id', unsigned: true, nullable: true }) - contributionId: number + @Column({ name: 'contribution_id', type: 'int', unsigned: true, nullable: true }) + contributionId: number | null @Column({ type: 'decimal', @@ -35,8 +35,8 @@ export class EventProtocol extends BaseEntity { nullable: true, transformer: DecimalTransformer, }) - amount: Decimal + amount: Decimal | null - @Column({ name: 'message_id', unsigned: true, nullable: true }) - messageId: number + @Column({ name: 'message_id', type: 'int', unsigned: true, nullable: true }) + messageId: number | null } diff --git a/deployment/bare_metal/.env.dist b/deployment/bare_metal/.env.dist index e816c9236..9c9c7ac82 100644 --- a/deployment/bare_metal/.env.dist +++ b/deployment/bare_metal/.env.dist @@ -27,7 +27,7 @@ COMMUNITY_DESCRIPTION="Gradido Development Stage1 Test Community" COMMUNITY_SUPPORT_MAIL=support@supportmail.com # backend -BACKEND_CONFIG_VERSION=v14.2022-12-22 +BACKEND_CONFIG_VERSION=v15.2023-02-07 JWT_EXPIRES_IN=10m GDT_API_URL=https://gdt.gradido.net @@ -56,9 +56,6 @@ EMAIL_CODE_REQUEST_TIME=10 WEBHOOK_ELOPAGE_SECRET=secret -# EventProtocol -EVENT_PROTOCOL_DISABLED=false - # Federation # if you set the value of FEDERATION_DHT_TOPIC, the DHT hyperswarm will start to announce and listen # on an hash created from this topic diff --git a/dht-node/.env.dist b/dht-node/.env.dist index c1641ea98..09e25ccb6 100644 --- a/dht-node/.env.dist +++ b/dht-node/.env.dist @@ -8,9 +8,6 @@ DB_PASSWORD= DB_DATABASE=gradido_community TYPEORM_LOGGING_RELATIVE_PATH=typeorm.dht-node.log -# EventProtocol -EVENT_PROTOCOL_DISABLED=false - # SET LOG LEVEL AS NEEDED IN YOUR .ENV # POSSIBLE VALUES: all | trace | debug | info | warn | error | fatal # LOG_LEVEL=info diff --git a/dht-node/.env.template b/dht-node/.env.template index eca7cb277..b31667fdb 100644 --- a/dht-node/.env.template +++ b/dht-node/.env.template @@ -8,9 +8,6 @@ DB_PASSWORD=$DB_PASSWORD DB_DATABASE=gradido_community TYPEORM_LOGGING_RELATIVE_PATH=$TYPEORM_LOGGING_RELATIVE_PATH -# EventProtocol -EVENT_PROTOCOL_DISABLED=$EVENT_PROTOCOL_DISABLED - # Federation FEDERATION_DHT_TOPIC=$FEDERATION_DHT_TOPIC FEDERATION_DHT_SEED=$FEDERATION_DHT_SEED diff --git a/dht-node/src/config/index.ts b/dht-node/src/config/index.ts index 02cbb20e9..795925ee3 100644 --- a/dht-node/src/config/index.ts +++ b/dht-node/src/config/index.ts @@ -9,7 +9,7 @@ const constants = { LOG_LEVEL: process.env.LOG_LEVEL || 'info', CONFIG_VERSION: { DEFAULT: 'DEFAULT', - EXPECTED: 'v1.2023-01-01', + EXPECTED: 'v2.2023-02-07', CURRENT: '', }, } @@ -28,11 +28,6 @@ const database = { process.env.TYPEORM_LOGGING_RELATIVE_PATH || 'typeorm.dht-node.log', } -const eventProtocol = { - // global switch to enable writing of EventProtocol-Entries - EVENT_PROTOCOL_DISABLED: process.env.EVENT_PROTOCOL_DISABLED === 'true' || false, -} - const federation = { FEDERATION_DHT_TOPIC: process.env.FEDERATION_DHT_TOPIC || 'GRADIDO_HUB', FEDERATION_DHT_SEED: process.env.FEDERATION_DHT_SEED || null, @@ -55,7 +50,6 @@ const CONFIG = { ...constants, ...server, ...database, - ...eventProtocol, ...federation, } diff --git a/federation/src/config/index.ts b/federation/src/config/index.ts index c2d81d2c8..588f52c60 100644 --- a/federation/src/config/index.ts +++ b/federation/src/config/index.ts @@ -52,10 +52,6 @@ const community = { process.env.COMMUNITY_DESCRIPTION || 'Die lokale Entwicklungsumgebung von Gradido.', } */ -// const eventProtocol = { -// global switch to enable writing of EventProtocol-Entries -// EVENT_PROTOCOL_DISABLED: process.env.EVENT_PROTOCOL_DISABLED === 'true' || false, -// } // This is needed by graphql-directive-auth // process.env.APP_SECRET = server.JWT_SECRET diff --git a/frontend/package.json b/frontend/package.json index 29c440988..bf26c7529 100755 --- a/frontend/package.json +++ b/frontend/package.json @@ -104,5 +104,10 @@ ], "author": "Gradido-Akademie - https://www.gradido.net/", "license": "Apache-2.0", - "description": "Gradido, the Natural Economy of Life, is a way to worldwide prosperity and peace in harmony with nature. - Gradido, die Natürliche Ökonomie des lebens, ist ein Weg zu weltweitem Wohlstand und Frieden in Harmonie mit der Natur." + "description": "Gradido, the Natural Economy of Life, is a way to worldwide prosperity and peace in harmony with nature. - Gradido, die Natürliche Ökonomie des lebens, ist ein Weg zu weltweitem Wohlstand und Frieden in Harmonie mit der Natur.", + "nodemonConfig": { + "ignore": [ + "**/*.spec.js" + ] + } }