gradido/federation/src/graphql/api/1_0/resolver/SendCoinsResolver.ts
2023-10-04 19:09:13 +02:00

328 lines
12 KiB
TypeScript

// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { Arg, Args, Mutation, Resolver } from 'type-graphql'
import { federationLogger as logger } from '@/server/logger'
import { Community as DbCommunity } from '@entity/Community'
import { PendingTransaction as DbPendingTransaction } from '@entity/PendingTransaction'
import { SendCoinsArgs } from '../model/SendCoinsArgs'
import { LogError } from '@/server/LogError'
import { PendingTransactionState } from '../enum/PendingTransactionState'
import { TransactionTypeId } from '../enum/TransactionTypeId'
import { calculateRecipientBalance } from '../util/calculateRecipientBalance'
import { fullName } from '@/graphql/util/fullName'
import { settlePendingReceiveTransaction } from '../util/settlePendingReceiveTransaction'
// import { checkTradingLevel } from '@/graphql/util/checkTradingLevel'
import { revertSettledReceiveTransaction } from '../util/revertSettledReceiveTransaction'
import { findUserByIdentifier } from '@/graphql/util/findUserByIdentifier'
import { SendCoinsResult } from '../model/SendCoinsResult'
import Decimal from 'decimal.js-light'
@Resolver()
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export class SendCoinsResolver {
@Mutation(() => SendCoinsResult)
async voteForSendCoins(
@Arg('data')
args: SendCoinsArgs,
): Promise<SendCoinsResult> {
logger.debug(
`voteForSendCoins() via apiVersion=1_0 ...`,
args.recipientCommunityUuid,
args.recipientUserIdentifier,
args.creationDate,
args.amount.toString(),
args.memo,
args.senderCommunityUuid,
args.senderUserUuid,
args.senderUserName,
)
const result = new SendCoinsResult()
// first check if receiver community is correct
const homeCom = await DbCommunity.findOneBy({
communityUuid: args.recipientCommunityUuid,
})
if (!homeCom) {
throw new LogError(
`voteForSendCoins with wrong recipientCommunityUuid`,
args.recipientCommunityUuid,
)
}
let receiverUser
try {
// second check if receiver user exists in this community
receiverUser = await findUserByIdentifier(args.recipientUserIdentifier)
} catch (err) {
logger.error('Error in findUserByIdentifier:', err)
throw new LogError(
`voteForSendCoins with unknown recipientUserIdentifier in the community=`,
homeCom.name,
)
}
const openSenderPendingTx = await DbPendingTransaction.count({
where: [
{ userGradidoID: args.senderUserUuid, state: PendingTransactionState.NEW },
{ linkedUserGradidoID: args.senderUserUuid, state: PendingTransactionState.NEW },
],
})
const openReceiverPendingTx = await DbPendingTransaction.count({
where: [
{ userGradidoID: receiverUser.gradidoID, state: PendingTransactionState.NEW },
{ linkedUserGradidoID: receiverUser.gradidoID, state: PendingTransactionState.NEW },
],
})
if (openSenderPendingTx > 0 || openReceiverPendingTx > 0) {
throw new LogError(
`There exist still ongoing 'Pending-Transactions' for the involved users on receiver-side!`,
)
}
try {
const txDate = new Date(args.creationDate)
const receiveBalance = await calculateRecipientBalance(receiverUser.id, args.amount, txDate)
const pendingTx = DbPendingTransaction.create()
pendingTx.amount = args.amount
pendingTx.balance = receiveBalance ? receiveBalance.balance : args.amount
pendingTx.balanceDate = txDate
pendingTx.decay = receiveBalance ? receiveBalance.decay.decay : new Decimal(0)
pendingTx.decayStart = receiveBalance ? receiveBalance.decay.start : null
pendingTx.creationDate = new Date()
pendingTx.linkedUserCommunityUuid = args.senderCommunityUuid
pendingTx.linkedUserGradidoID = args.senderUserUuid
pendingTx.linkedUserName = args.senderUserName
pendingTx.memo = args.memo
pendingTx.previous = receiveBalance ? receiveBalance.lastTransactionId : null
pendingTx.state = PendingTransactionState.NEW
pendingTx.typeId = TransactionTypeId.RECEIVE
pendingTx.userId = receiverUser.id
pendingTx.userCommunityUuid = args.recipientCommunityUuid
pendingTx.userGradidoID = receiverUser.gradidoID
pendingTx.userName = fullName(receiverUser.firstName, receiverUser.lastName)
await DbPendingTransaction.insert(pendingTx)
result.vote = true
result.recipFirstName = receiverUser.firstName
result.recipLastName = receiverUser.lastName
result.recipAlias = receiverUser.alias
result.recipGradidoID = receiverUser.gradidoID
logger.debug(`voteForSendCoins()-1_0... successfull`)
} catch (err) {
throw new LogError(`Error in voteForSendCoins: `, err)
}
return result
}
@Mutation(() => Boolean)
async revertSendCoins(
@Arg('data')
args: SendCoinsArgs,
): Promise<boolean> {
logger.debug(`revertSendCoins() via apiVersion=1_0 ...`)
// first check if receiver community is correct
const homeCom = await DbCommunity.findOneBy({
communityUuid: args.recipientCommunityUuid,
})
if (!homeCom) {
throw new LogError(
`revertSendCoins with wrong recipientCommunityUuid`,
args.recipientCommunityUuid,
)
}
let receiverUser
try {
// second check if receiver user exists in this community
receiverUser = await findUserByIdentifier(args.recipientUserIdentifier)
} catch (err) {
logger.error('Error in findUserByIdentifier:', err)
throw new LogError(
`revertSendCoins with unknown recipientUserIdentifier in the community=`,
homeCom.name,
)
}
try {
const pendingTx = await DbPendingTransaction.findOneBy({
userCommunityUuid: args.recipientCommunityUuid,
userGradidoID: receiverUser.gradidoID,
state: PendingTransactionState.NEW,
typeId: TransactionTypeId.RECEIVE,
balanceDate: new Date(args.creationDate),
linkedUserCommunityUuid: args.senderCommunityUuid,
linkedUserGradidoID: args.senderUserUuid,
})
logger.debug('XCom: revertSendCoins found pendingTX=', pendingTx)
if (pendingTx && pendingTx.amount.toString() === args.amount.toString()) {
logger.debug('XCom: revertSendCoins matching pendingTX for remove...')
try {
await pendingTx.remove()
logger.debug('XCom: revertSendCoins pendingTX for remove successfully')
} catch (err) {
throw new LogError('Error in revertSendCoins on removing pendingTx of receiver: ', err)
}
} else {
logger.debug(
'XCom: revertSendCoins NOT matching pendingTX for remove:',
pendingTx?.amount.toString(),
args.amount.toString(),
)
throw new LogError(
`Can't find in revertSendCoins the pending receiver TX for args=`,
args.recipientCommunityUuid,
args.recipientUserIdentifier,
PendingTransactionState.NEW,
TransactionTypeId.RECEIVE,
args.creationDate,
args.amount,
args.memo,
args.senderCommunityUuid,
args.senderUserUuid,
args.senderUserName,
)
}
logger.debug(`revertSendCoins()-1_0... successfull`)
return true
} catch (err) {
throw new LogError(`Error in revertSendCoins: `, err)
}
}
@Mutation(() => Boolean)
async settleSendCoins(
@Arg('data')
args: SendCoinsArgs,
): Promise<boolean> {
logger.debug(
`settleSendCoins() via apiVersion=1_0 ...userCommunityUuid=${
args.recipientCommunityUuid
}, userGradidoID=${args.recipientUserIdentifier}, balanceDate=${
args.creationDate
},amount=${args.amount.valueOf()}, memo=${args.memo}, linkedUserCommunityUuid = ${
args.senderCommunityUuid
}, userSenderIdentifier=${args.senderUserUuid}, userSenderName=${args.senderUserName}`,
)
// first check if receiver community is correct
const homeCom = await DbCommunity.findOneBy({
communityUuid: args.recipientCommunityUuid,
})
if (!homeCom) {
throw new LogError(
`settleSendCoins with wrong recipientCommunityUuid`,
args.recipientCommunityUuid,
)
}
let receiverUser
try {
// second check if receiver user exists in this community
receiverUser = await findUserByIdentifier(args.recipientUserIdentifier)
} catch (err) {
logger.error('Error in findUserByIdentifier:', err)
throw new LogError(
`settleSendCoins with unknown recipientUserIdentifier in the community=`,
homeCom.name,
)
}
const pendingTx = await DbPendingTransaction.findOneBy({
userCommunityUuid: args.recipientCommunityUuid,
userGradidoID: receiverUser.gradidoID,
state: PendingTransactionState.NEW,
typeId: TransactionTypeId.RECEIVE,
balanceDate: new Date(args.creationDate),
linkedUserCommunityUuid: args.senderCommunityUuid,
linkedUserGradidoID: args.senderUserUuid,
})
logger.debug('XCom: settleSendCoins found pendingTX=', pendingTx?.toString())
if (
pendingTx &&
pendingTx.amount.toString() === args.amount.toString() &&
pendingTx.memo === args.memo
) {
logger.debug('XCom: settleSendCoins matching pendingTX for settlement...')
await settlePendingReceiveTransaction(homeCom, receiverUser, pendingTx)
logger.debug(`XCom: settlePendingReceiveTransaction()-1_0... successfull`)
return true
} else {
logger.debug('XCom: settlePendingReceiveTransaction NOT matching pendingTX for settlement...')
throw new LogError(
`Can't find in settlePendingReceiveTransaction the pending receiver TX for args=`,
args.recipientCommunityUuid,
args.recipientUserIdentifier,
PendingTransactionState.NEW,
TransactionTypeId.RECEIVE,
args.creationDate,
args.amount,
args.memo,
args.senderCommunityUuid,
args.senderUserUuid,
args.senderUserName,
)
}
}
@Mutation(() => Boolean)
async revertSettledSendCoins(
@Arg('data')
args: SendCoinsArgs,
): Promise<boolean> {
logger.debug(`revertSettledSendCoins() via apiVersion=1_0 ...`)
// first check if receiver community is correct
const homeCom = await DbCommunity.findOneBy({
communityUuid: args.recipientCommunityUuid,
})
if (!homeCom) {
throw new LogError(
`revertSettledSendCoins with wrong recipientCommunityUuid`,
args.recipientCommunityUuid,
)
}
let receiverUser
try {
// second check if receiver user exists in this community
receiverUser = await findUserByIdentifier(args.recipientUserIdentifier)
} catch (err) {
logger.error('Error in findUserByIdentifier:', err)
throw new LogError(
`revertSettledSendCoins with unknown recipientUserIdentifier in the community=`,
homeCom.name,
)
}
const pendingTx = await DbPendingTransaction.findOneBy({
userCommunityUuid: args.recipientCommunityUuid,
userGradidoID: args.recipientUserIdentifier,
state: PendingTransactionState.SETTLED,
typeId: TransactionTypeId.RECEIVE,
balanceDate: new Date(args.creationDate),
linkedUserCommunityUuid: args.senderCommunityUuid,
linkedUserGradidoID: args.senderUserUuid,
})
logger.debug('XCom: revertSettledSendCoins found pendingTX=', pendingTx)
if (
pendingTx &&
pendingTx.amount.toString() === args.amount.toString() &&
pendingTx.memo === args.memo
) {
logger.debug('XCom: revertSettledSendCoins matching pendingTX for remove...')
try {
await revertSettledReceiveTransaction(homeCom, receiverUser, pendingTx)
logger.debug('XCom: revertSettledSendCoins pendingTX successfully')
} catch (err) {
throw new LogError('Error in revertSettledSendCoins of receiver: ', err)
}
} else {
logger.debug('XCom: revertSettledSendCoins NOT matching pendingTX...')
throw new LogError(
`Can't find in revertSettledSendCoins the pending receiver TX for args=`,
args.recipientCommunityUuid,
args.recipientUserIdentifier,
PendingTransactionState.SETTLED,
TransactionTypeId.RECEIVE,
args.creationDate,
args.amount,
args.memo,
args.senderCommunityUuid,
args.senderUserUuid,
args.senderUserName,
)
}
logger.debug(`revertSendCoins()-1_0... successfull`)
return true
}
}