mirror of
https://github.com/IT4Change/gradido.git
synced 2025-12-13 07:45:54 +00:00
extract transaction process in function
This commit is contained in:
parent
81cd858eb4
commit
13fe4300d2
@ -1,4 +1,4 @@
|
||||
import { ArgsType, Field, Int } from 'type-graphql'
|
||||
import { ArgsType, Field } from 'type-graphql'
|
||||
import Decimal from 'decimal.js-light'
|
||||
|
||||
@ArgsType()
|
||||
@ -11,7 +11,4 @@ export default class TransactionSendArgs {
|
||||
|
||||
@Field(() => String)
|
||||
memo: string
|
||||
|
||||
@Field(() => Int, { nullable: true })
|
||||
senderId?: number
|
||||
}
|
||||
|
||||
@ -13,7 +13,8 @@ import { RIGHTS } from '@/auth/RIGHTS'
|
||||
import { randomBytes } from 'crypto'
|
||||
import { User } from '@model/User'
|
||||
import { calculateDecay } from '@/util/decay'
|
||||
import { TransactionResolver } from './TransactionResolver'
|
||||
import { executeTransaction } from './TransactionResolver'
|
||||
import { User as dbUser } from '@entity/User'
|
||||
|
||||
// TODO: do not export, test it inside the resolver
|
||||
export const transactionLinkCode = (date: Date): string => {
|
||||
@ -130,10 +131,11 @@ export class TransactionLinkResolver {
|
||||
const userRepository = getCustomRepository(UserRepository)
|
||||
const user = await userRepository.findByPubkeyHex(context.pubKey)
|
||||
const transactionLink = await dbTransactionLink.findOneOrFail({ id })
|
||||
const linkedUser = await dbUser.findOneOrFail({ id: transactionLink.userId })
|
||||
|
||||
const now = new Date()
|
||||
|
||||
if (user.id === transactionLink.userId) {
|
||||
if (user.id === linkedUser.id) {
|
||||
throw new Error('Cannot redeem own transaction link.')
|
||||
}
|
||||
|
||||
@ -145,16 +147,8 @@ export class TransactionLinkResolver {
|
||||
throw new Error('Transaction Link already redeemed.')
|
||||
}
|
||||
|
||||
const transactionResolver = new TransactionResolver()
|
||||
transactionResolver.sendCoins(
|
||||
{
|
||||
email: user.email,
|
||||
amount: transactionLink.amount,
|
||||
memo: transactionLink.memo,
|
||||
senderId: transactionLink.userId,
|
||||
},
|
||||
context,
|
||||
)
|
||||
await executeTransaction(transactionLink.amount, transactionLink.memo, linkedUser, user)
|
||||
|
||||
transactionLink.redeemedAt = now
|
||||
transactionLink.redeemedBy = user.id
|
||||
transactionLink.save().catch(() => {
|
||||
|
||||
@ -34,6 +34,83 @@ import { virtualDecayTransaction } from '@/util/virtualDecayTransaction'
|
||||
import Decimal from 'decimal.js-light'
|
||||
import { calculateDecay } from '@/util/decay'
|
||||
|
||||
export const executeTransaction = async (
|
||||
amount: Decimal,
|
||||
memo: string,
|
||||
sender: dbUser,
|
||||
recipient: dbUser,
|
||||
): Promise<boolean> => {
|
||||
if (sender.id === recipient.id) {
|
||||
throw new Error('Sender and Recipient are the same.')
|
||||
}
|
||||
|
||||
// validate amount
|
||||
const receivedCallDate = new Date()
|
||||
const sendBalance = await calculateBalance(sender.id, amount.mul(-1), receivedCallDate)
|
||||
if (!sendBalance) {
|
||||
throw new Error("user hasn't enough GDD or amount is < 0")
|
||||
}
|
||||
|
||||
const queryRunner = getConnection().createQueryRunner()
|
||||
await queryRunner.connect()
|
||||
await queryRunner.startTransaction('READ UNCOMMITTED')
|
||||
try {
|
||||
// transaction
|
||||
const transactionSend = new dbTransaction()
|
||||
transactionSend.typeId = TransactionTypeId.SEND
|
||||
transactionSend.memo = memo
|
||||
transactionSend.userId = sender.id
|
||||
transactionSend.linkedUserId = recipient.id
|
||||
transactionSend.amount = amount.mul(-1)
|
||||
transactionSend.balance = sendBalance.balance
|
||||
transactionSend.balanceDate = receivedCallDate
|
||||
transactionSend.decay = sendBalance.decay.decay
|
||||
transactionSend.decayStart = sendBalance.decay.start
|
||||
transactionSend.previous = sendBalance.lastTransactionId
|
||||
await queryRunner.manager.insert(dbTransaction, transactionSend)
|
||||
|
||||
const transactionReceive = new dbTransaction()
|
||||
transactionReceive.typeId = TransactionTypeId.RECEIVE
|
||||
transactionReceive.memo = memo
|
||||
transactionReceive.userId = recipient.id
|
||||
transactionReceive.linkedUserId = sender.id
|
||||
transactionReceive.amount = amount
|
||||
const receiveBalance = await calculateBalance(recipient.id, amount, receivedCallDate)
|
||||
transactionReceive.balance = receiveBalance ? receiveBalance.balance : amount
|
||||
transactionReceive.balanceDate = receivedCallDate
|
||||
transactionReceive.decay = receiveBalance ? receiveBalance.decay.decay : new Decimal(0)
|
||||
transactionReceive.decayStart = receiveBalance ? receiveBalance.decay.start : null
|
||||
transactionReceive.previous = receiveBalance ? receiveBalance.lastTransactionId : null
|
||||
transactionReceive.linkedTransactionId = transactionSend.id
|
||||
await queryRunner.manager.insert(dbTransaction, transactionReceive)
|
||||
|
||||
// Save linked transaction id for send
|
||||
transactionSend.linkedTransactionId = transactionReceive.id
|
||||
await queryRunner.manager.update(dbTransaction, { id: transactionSend.id }, transactionSend)
|
||||
|
||||
await queryRunner.commitTransaction()
|
||||
} catch (e) {
|
||||
await queryRunner.rollbackTransaction()
|
||||
throw new Error(`Transaction was not successful: ${e}`)
|
||||
} finally {
|
||||
await queryRunner.release()
|
||||
}
|
||||
|
||||
// send notification email
|
||||
// TODO: translate
|
||||
await sendTransactionReceivedEmail({
|
||||
senderFirstName: sender.firstName,
|
||||
senderLastName: sender.lastName,
|
||||
recipientFirstName: recipient.firstName,
|
||||
recipientLastName: recipient.lastName,
|
||||
email: recipient.email,
|
||||
amount,
|
||||
memo,
|
||||
})
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@Resolver()
|
||||
export class TransactionResolver {
|
||||
@Authorized([RIGHTS.TRANSACTION_LIST])
|
||||
@ -145,23 +222,15 @@ export class TransactionResolver {
|
||||
@Authorized([RIGHTS.SEND_COINS])
|
||||
@Mutation(() => String)
|
||||
async sendCoins(
|
||||
@Args() { email, amount, memo, senderId = 0 }: TransactionSendArgs,
|
||||
@Args() { email, amount, memo }: TransactionSendArgs,
|
||||
@Ctx() context: any,
|
||||
): Promise<boolean> {
|
||||
// TODO this is subject to replay attacks
|
||||
const userRepository = getCustomRepository(UserRepository)
|
||||
const senderUser = senderId
|
||||
? await dbUser.findOneOrFail({ id: senderId })
|
||||
: await userRepository.findByPubkeyHex(context.pubKey)
|
||||
const senderUser = await userRepository.findByPubkeyHex(context.pubKey)
|
||||
if (senderUser.pubKey.length !== 32) {
|
||||
throw new Error('invalid sender public key')
|
||||
}
|
||||
// validate amount
|
||||
const receivedCallDate = new Date()
|
||||
const sendBalance = await calculateBalance(senderUser.id, amount.mul(-1), receivedCallDate)
|
||||
if (!sendBalance) {
|
||||
throw new Error("user hasn't enough GDD or amount is < 0")
|
||||
}
|
||||
|
||||
// validate recipient user
|
||||
const recipientUser = await dbUser.findOne({ email: email }, { withDeleted: true })
|
||||
@ -175,62 +244,7 @@ export class TransactionResolver {
|
||||
throw new Error('invalid recipient public key')
|
||||
}
|
||||
|
||||
const queryRunner = getConnection().createQueryRunner()
|
||||
await queryRunner.connect()
|
||||
await queryRunner.startTransaction('READ UNCOMMITTED')
|
||||
try {
|
||||
// transaction
|
||||
const transactionSend = new dbTransaction()
|
||||
transactionSend.typeId = TransactionTypeId.SEND
|
||||
transactionSend.memo = memo
|
||||
transactionSend.userId = senderUser.id
|
||||
transactionSend.linkedUserId = recipientUser.id
|
||||
transactionSend.amount = amount.mul(-1)
|
||||
transactionSend.balance = sendBalance.balance
|
||||
transactionSend.balanceDate = receivedCallDate
|
||||
transactionSend.decay = sendBalance.decay.decay
|
||||
transactionSend.decayStart = sendBalance.decay.start
|
||||
transactionSend.previous = sendBalance.lastTransactionId
|
||||
await queryRunner.manager.insert(dbTransaction, transactionSend)
|
||||
|
||||
const transactionReceive = new dbTransaction()
|
||||
transactionReceive.typeId = TransactionTypeId.RECEIVE
|
||||
transactionReceive.memo = memo
|
||||
transactionReceive.userId = recipientUser.id
|
||||
transactionReceive.linkedUserId = senderUser.id
|
||||
transactionReceive.amount = amount
|
||||
const receiveBalance = await calculateBalance(recipientUser.id, amount, receivedCallDate)
|
||||
transactionReceive.balance = receiveBalance ? receiveBalance.balance : amount
|
||||
transactionReceive.balanceDate = receivedCallDate
|
||||
transactionReceive.decay = receiveBalance ? receiveBalance.decay.decay : new Decimal(0)
|
||||
transactionReceive.decayStart = receiveBalance ? receiveBalance.decay.start : null
|
||||
transactionReceive.previous = receiveBalance ? receiveBalance.lastTransactionId : null
|
||||
transactionReceive.linkedTransactionId = transactionSend.id
|
||||
await queryRunner.manager.insert(dbTransaction, transactionReceive)
|
||||
|
||||
// Save linked transaction id for send
|
||||
transactionSend.linkedTransactionId = transactionReceive.id
|
||||
await queryRunner.manager.update(dbTransaction, { id: transactionSend.id }, transactionSend)
|
||||
|
||||
await queryRunner.commitTransaction()
|
||||
} catch (e) {
|
||||
await queryRunner.rollbackTransaction()
|
||||
throw new Error(`Transaction was not successful: ${e}`)
|
||||
} finally {
|
||||
await queryRunner.release()
|
||||
}
|
||||
|
||||
// send notification email
|
||||
// TODO: translate
|
||||
await sendTransactionReceivedEmail({
|
||||
senderFirstName: senderUser.firstName,
|
||||
senderLastName: senderUser.lastName,
|
||||
recipientFirstName: recipientUser.firstName,
|
||||
recipientLastName: recipientUser.lastName,
|
||||
email: recipientUser.email,
|
||||
amount,
|
||||
memo,
|
||||
})
|
||||
await executeTransaction(amount, memo, senderUser, recipientUser)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user