tests for all sendCoins 2-Phase-Commit handshake requests

This commit is contained in:
Claus-Peter Huebner 2023-09-15 21:10:38 +02:00
parent 3745c6a8e7
commit a71877abed
15 changed files with 616 additions and 415 deletions

View File

@ -4,10 +4,10 @@ import { ArgsType, Field } from 'type-graphql'
@ArgsType()
export class SendCoinsArgs {
@Field(() => String)
communityReceiverIdentifier: string
recipientCommunityUuid: string
@Field(() => String)
userReceiverIdentifier: string
recipientUserIdentifier: string
@Field(() => String)
creationDate: string
@ -19,11 +19,11 @@ export class SendCoinsArgs {
memo: string
@Field(() => String)
communitySenderIdentifier: string
senderCommunityUuid: string
@Field(() => String)
userSenderIdentifier: string
senderUserUuid: string
@Field(() => String)
userSenderName: string
senderUserName: string
}

View File

@ -2,24 +2,24 @@ import { gql } from 'graphql-request'
export const revertSendCoins = gql`
mutation (
$communityReceiverIdentifier: String!
$userReceiverIdentifier: String!
$recipientCommunityUuid: String!
$recipientUserIdentifier: String!
$creationDate: String!
$amount: Decimal!
$memo: String!
$communitySenderIdentifier: String!
$userSenderIdentifier: String!
$userSenderName: String!
$senderCommunityUuid: String!
$senderUserUuid: String!
$senderUserName: String!
) {
revertSendCoins(
communityReceiverIdentifier: $communityReceiverIdentifier
userReceiverIdentifier: $userReceiverIdentifier
recipientCommunityUuid: $recipientCommunityUuid
recipientUserIdentifier: $recipientUserIdentifier
creationDate: $creationDate
amount: $amount
memo: $memo
communitySenderIdentifier: $communitySenderIdentifier
userSenderIdentifier: $userSenderIdentifier
userSenderName: $userSenderName
senderCommunityUuid: $senderCommunityUuid
senderUserUuid: $senderUserUuid
senderUserName: $senderUserName
)
}
`

View File

@ -2,24 +2,24 @@ import { gql } from 'graphql-request'
export const revertSettledSendCoins = gql`
mutation (
$communityReceiverIdentifier: String!
$userReceiverIdentifier: String!
$creationDate: Date!
$recipientCommunityUuid: String!
$recipientUserIdentifier: String!
$creationDate: String!
$amount: Decimal!
$memo: String!
$communitySenderIdentifier: String!
$userSenderIdentifier: String!
$userSenderName: String!
$senderCommunityUuid: String!
$senderUserUuid: String!
$senderUserName: String!
) {
revertSettledSendCoins(
communityReceiverIdentifier: $communityReceiverIdentifier
userReceiverIdentifier: $userReceiverIdentifier
recipientCommunityUuid: $recipientCommunityUuid
recipientUserIdentifier: $recipientUserIdentifier
creationDate: $creationDate
amount: $amount
memo: $memo
communitySenderIdentifier: $communitySenderIdentifier
userSenderIdentifier: $userSenderIdentifier
userSenderName: $userSenderName
senderCommunityUuid: $senderCommunityUuid
senderUserUuid: $senderUserUuid
senderUserName: $senderUserName
)
}
`

View File

@ -2,24 +2,24 @@ import { gql } from 'graphql-request'
export const settleSendCoins = gql`
mutation (
$communityReceiverIdentifier: String!
$userReceiverIdentifier: String!
$creationDate: Date!
$recipientCommunityUuid: String!
$recipientUserIdentifier: String!
$creationDate: String!
$amount: Decimal!
$memo: String!
$communitySenderIdentifier: String!
$userSenderIdentifier: String!
$userSenderName: String!
$senderCommunityUuid: String!
$senderUserUuid: String!
$senderUserName: String!
) {
settleSendCoins(
communityReceiverIdentifier: $communityReceiverIdentifier
userReceiverIdentifier: $userReceiverIdentifier
recipientCommunityUuid: $recipientCommunityUuid
recipientUserIdentifier: $recipientUserIdentifier
creationDate: $creationDate
amount: $amount
memo: $memo
communitySenderIdentifier: $communitySenderIdentifier
userSenderIdentifier: $userSenderIdentifier
userSenderName: $userSenderName
senderCommunityUuid: $senderCommunityUuid
senderUserUuid: $senderUserUuid
senderUserName: $senderUserName
)
}
`

View File

@ -2,24 +2,24 @@ import { gql } from 'graphql-request'
export const voteForSendCoins = gql`
mutation (
$communityReceiverIdentifier: String!
$userReceiverIdentifier: String!
$recipientCommunityUuid: String!
$recipientUserIdentifier: String!
$creationDate: String!
$amount: Decimal!
$memo: String!
$communitySenderIdentifier: String!
$userSenderIdentifier: String!
$userSenderName: String!
$senderCommunityUuid: String!
$senderUserUuid: String!
$senderUserName: String!
) {
voteForSendCoins(
communityReceiverIdentifier: $communityReceiverIdentifier
userReceiverIdentifier: $userReceiverIdentifier
recipientCommunityUuid: $recipientCommunityUuid
recipientUserIdentifier: $recipientUserIdentifier
creationDate: $creationDate
amount: $amount
memo: $memo
communitySenderIdentifier: $communitySenderIdentifier
userSenderIdentifier: $userSenderIdentifier
userSenderName: $userSenderName
senderCommunityUuid: $senderCommunityUuid
senderUserUuid: $senderUserUuid
senderUserName: $senderUserName
)
}
`

View File

@ -3,6 +3,7 @@ import { Decimal } from 'decimal.js-light'
import { BaseEntity, Entity, PrimaryGeneratedColumn, Column, OneToOne, JoinColumn } from 'typeorm'
import { DecimalTransformer } from '../../src/typeorm/DecimalTransformer'
import { Contribution } from '../Contribution'
import { DltTransaction } from '../DltTransaction'
@Entity('transactions')
export class Transaction extends BaseEntity {
@ -152,6 +153,10 @@ export class Transaction extends BaseEntity {
@JoinColumn({ name: 'id', referencedColumnName: 'transactionId' })
contribution?: Contribution | null
@OneToOne(() => DltTransaction, (dlt) => dlt.transactionId)
@JoinColumn({ name: 'id', referencedColumnName: 'transactionId' })
dltTransaction?: DltTransaction | null
@OneToOne(() => Transaction)
@JoinColumn({ name: 'previous' })
previousTransaction?: Transaction | null

View File

@ -16,6 +16,7 @@
"lint": "eslint --max-warnings=0 --ext .js,.ts ."
},
"dependencies": {
"@types/uuid": "8.3.4",
"apollo-server-express": "^2.25.2",
"await-semaphore": "0.1.3",
"class-validator": "^0.13.2",
@ -28,7 +29,8 @@
"lodash.clonedeep": "^4.5.0",
"log4js": "^6.7.1",
"reflect-metadata": "^0.1.13",
"type-graphql": "^1.1.1"
"type-graphql": "^1.1.1",
"uuid": "8.3.2"
},
"devDependencies": {
"@types/express": "4.17.12",

View File

@ -4,10 +4,10 @@ import { ArgsType, Field } from 'type-graphql'
@ArgsType()
export class SendCoinsArgs {
@Field(() => String)
communityReceiverIdentifier: string
recipientCommunityUuid: string
@Field(() => String)
userReceiverIdentifier: string
recipientUserIdentifier: string
@Field(() => String)
creationDate: string
@ -19,11 +19,11 @@ export class SendCoinsArgs {
memo: string
@Field(() => String)
communitySenderIdentifier: string
senderCommunityUuid: string
@Field(() => String)
userSenderIdentifier: string
senderUserUuid: string
@Field(() => String)
userSenderName: string
senderUserName: string
}

View File

@ -4,6 +4,7 @@ import { ApolloServerTestClient } from 'apollo-server-testing'
import { Community as DbCommunity } from '@entity/Community'
import CONFIG from '@/config'
import { User as DbUser } from '@entity/User'
import { UserContact as DbUserContact } from '@entity/UserContact'
import { fullName } from '@/graphql/util/fullName'
import { GraphQLError } from 'graphql'
import { cleanDB, testEnvironment } from '@test/helpers'
@ -11,9 +12,9 @@ import { logger } from '@test/testSetup'
import { Connection } from '@dbTools/typeorm'
import { PendingTransaction as DbPendingTransaction } from '@entity/PendingTransaction'
import Decimal from 'decimal.js-light'
import { calculateRecipientBalance } from '../util/calculateRecipientBalance'
import { PendingTransactionState } from '../enum/PendingTransactionState'
import { TransactionTypeId } from '../enum/TransactionTypeId'
import { Transaction as DbTransaction } from '@entity/Transaction'
let mutate: ApolloServerTestClient['mutate'], con: Connection
// let query: ApolloServerTestClient['query']
@ -26,18 +27,18 @@ let testEnv: {
CONFIG.FEDERATION_API = '1_0'
let homeCom: DbCommunity
let foreignCom: DbCommunity
let sendUser: DbUser
let sendContact: DbUserContact
let recipUser: DbUser
let recipContact: DbUserContact
beforeAll(async () => {
testEnv = await testEnvironment(logger)
mutate = testEnv.mutate
// query = testEnv.query
con = testEnv.con
// const server = await createServer()
// con = server.con
// query = createTestClient(server.apollo).query
// mutate = createTestClient(server.apollo).mutate
// DbCommunity.clear()
// DbUser.clear()
await cleanDB()
})
@ -48,118 +49,103 @@ afterAll(async () => {
describe('SendCoinsResolver', () => {
const voteForSendCoinsMutation = `
mutation (
$communityReceiverIdentifier: String!
$userReceiverIdentifier: String!
$creationDate: String!
$amount: Decimal!
$memo: String!
$communitySenderIdentifier: String!
$userSenderIdentifier: String!
$userSenderName: String!
) {
voteForSendCoins(
communityReceiverIdentifier: $communityReceiverIdentifier
userReceiverIdentifier: $userReceiverIdentifier
creationDate: $creationDate
amount: $amount
memo: $memo
communitySenderIdentifier: $communitySenderIdentifier
userSenderIdentifier: $userSenderIdentifier
userSenderName: $userSenderName
)
}
`
const revertSendCoinsMutation = `
mutation (
$communityReceiverIdentifier: String!
$userReceiverIdentifier: String!
$creationDate: String!
$amount: Decimal!
$memo: String!
$communitySenderIdentifier: String!
$userSenderIdentifier: String!
$userSenderName: String!
) {
revertSendCoins(
communityReceiverIdentifier: $communityReceiverIdentifier
userReceiverIdentifier: $userReceiverIdentifier
creationDate: $creationDate
amount: $amount
memo: $memo
communitySenderIdentifier: $communitySenderIdentifier
userSenderIdentifier: $userSenderIdentifier
userSenderName: $userSenderName
)
}
`
mutation (
$recipientCommunityUuid: String!
$recipientUserIdentifier: String!
$creationDate: String!
$amount: Decimal!
$memo: String!
$senderCommunityUuid: String!
$senderUserUuid: String!
$senderUserName: String!
) {
voteForSendCoins(
recipientCommunityUuid: $recipientCommunityUuid
recipientUserIdentifier: $recipientUserIdentifier
creationDate: $creationDate
amount: $amount
memo: $memo
senderCommunityUuid: $senderCommunityUuid
senderUserUuid: $senderUserUuid
senderUserName: $senderUserName
)
}`
const settleSendCoinsMutation = `
mutation (
$communityReceiverIdentifier: String!
$userReceiverIdentifier: String!
$recipientCommunityUuid: String!
$recipientUserIdentifier: String!
$creationDate: String!
$amount: Decimal!
$memo: String!
$communitySenderIdentifier: String!
$userSenderIdentifier: String!
$userSenderName: String!
$senderCommunityUuid: String!
$senderUserUuid: String!
$senderUserName: String!
) {
settleSendCoins(
communityReceiverIdentifier: $communityReceiverIdentifier
userReceiverIdentifier: $userReceiverIdentifier
recipientCommunityUuid: $recipientCommunityUuid
recipientUserIdentifier: $recipientUserIdentifier
creationDate: $creationDate
amount: $amount
memo: $memo
communitySenderIdentifier: $communitySenderIdentifier
userSenderIdentifier: $userSenderIdentifier
userSenderName: $userSenderName
senderCommunityUuid: $senderCommunityUuid
senderUserUuid: $senderUserUuid
senderUserName: $senderUserName
)
}
`
}`
beforeEach(async () => {
await cleanDB()
homeCom = DbCommunity.create()
homeCom.foreign = false
homeCom.url = 'homeCom-url'
homeCom.name = 'homeCom-Name'
homeCom.description = 'homeCom-Description'
homeCom.creationDate = new Date()
homeCom.publicKey = Buffer.from('homeCom-publicKey')
homeCom.communityUuid = '56a55482-909e-46a4-bfa2-cd025e894eba'
await DbCommunity.insert(homeCom)
foreignCom = DbCommunity.create()
foreignCom.foreign = true
foreignCom.url = 'foreignCom-url'
foreignCom.name = 'foreignCom-Name'
foreignCom.description = 'foreignCom-Description'
foreignCom.creationDate = new Date()
foreignCom.publicKey = Buffer.from('foreignCom-publicKey')
foreignCom.communityUuid = '56a55482-909e-46a4-bfa2-cd025e894ebb'
await DbCommunity.insert(foreignCom)
sendUser = DbUser.create()
sendUser.alias = 'sendUser-alias'
sendUser.firstName = 'sendUser-FirstName'
sendUser.gradidoID = '56a55482-909e-46a4-bfa2-cd025e894ebc'
sendUser.lastName = 'sendUser-LastName'
await DbUser.insert(sendUser)
sendContact = await newEmailContact('send.user@email.de', sendUser.id)
sendContact = await DbUserContact.save(sendContact)
sendUser.emailContact = sendContact
sendUser.emailId = sendContact.id
await DbUser.save(sendUser)
recipUser = DbUser.create()
recipUser.alias = 'recipUser-alias'
recipUser.firstName = 'recipUser-FirstName'
recipUser.gradidoID = '56a55482-909e-46a4-bfa2-cd025e894ebd'
recipUser.lastName = 'recipUser-LastName'
await DbUser.insert(recipUser)
recipContact = await newEmailContact('recip.user@email.de', recipUser.id)
recipContact = await DbUserContact.save(recipContact)
recipUser.emailContact = recipContact
recipUser.emailId = recipContact.id
await DbUser.save(recipUser)
})
describe('voteForSendCoins', () => {
let homeCom: DbCommunity
let foreignCom: DbCommunity
let sendUser: DbUser
let recipUser: DbUser
beforeEach(async () => {
await cleanDB()
homeCom = DbCommunity.create()
homeCom.foreign = false
homeCom.url = 'homeCom-url'
homeCom.name = 'homeCom-Name'
homeCom.description = 'homeCom-Description'
homeCom.creationDate = new Date()
homeCom.publicKey = Buffer.from('homeCom-publicKey')
homeCom.communityUuid = 'homeCom-UUID'
await DbCommunity.insert(homeCom)
foreignCom = DbCommunity.create()
foreignCom.foreign = true
foreignCom.url = 'foreignCom-url'
foreignCom.name = 'foreignCom-Name'
foreignCom.description = 'foreignCom-Description'
foreignCom.creationDate = new Date()
foreignCom.publicKey = Buffer.from('foreignCom-publicKey')
foreignCom.communityUuid = 'foreignCom-UUID'
await DbCommunity.insert(foreignCom)
sendUser = DbUser.create()
sendUser.alias = 'sendUser-alias'
sendUser.firstName = 'sendUser-FirstName'
sendUser.gradidoID = 'sendUser-GradidoID'
sendUser.lastName = 'sendUser-LastName'
await DbUser.insert(sendUser)
recipUser = DbUser.create()
recipUser.alias = 'recipUser-alias'
recipUser.firstName = 'recipUser-FirstName'
recipUser.gradidoID = 'recipUser-GradidoID'
recipUser.lastName = 'recipUser-LastName'
await DbUser.insert(recipUser)
})
describe('unknown recipient community', () => {
it('throws an error', async () => {
jest.clearAllMocks()
@ -167,19 +153,19 @@ describe('SendCoinsResolver', () => {
await mutate({
mutation: voteForSendCoinsMutation,
variables: {
communityReceiverIdentifier: 'invalid foreignCom',
userReceiverIdentifier: recipUser.gradidoID,
recipientCommunityUuid: 'invalid foreignCom',
recipientUserIdentifier: recipUser.gradidoID,
creationDate: new Date().toISOString(),
amount: 100,
memo: 'X-Com-TX memo',
communitySenderIdentifier: homeCom.communityUuid,
userSenderIdentifier: sendUser.gradidoID,
userSenderName: fullName(sendUser.firstName, sendUser.lastName),
senderCommunityUuid: homeCom.communityUuid,
senderUserUuid: sendUser.gradidoID,
senderUserName: fullName(sendUser.firstName, sendUser.lastName),
},
}),
).toEqual(
expect.objectContaining({
errors: [new GraphQLError('voteForSendCoins with wrong communityReceiverIdentifier')],
errors: [new GraphQLError('voteForSendCoins with wrong recipientCommunityUuid')],
}),
)
})
@ -192,21 +178,21 @@ describe('SendCoinsResolver', () => {
await mutate({
mutation: voteForSendCoinsMutation,
variables: {
communityReceiverIdentifier: foreignCom.communityUuid,
userReceiverIdentifier: 'invalid recipient',
recipientCommunityUuid: foreignCom.communityUuid,
recipientUserIdentifier: 'invalid recipient',
creationDate: new Date().toISOString(),
amount: 100,
memo: 'X-Com-TX memo',
communitySenderIdentifier: homeCom.communityUuid,
userSenderIdentifier: sendUser.gradidoID,
userSenderName: fullName(sendUser.firstName, sendUser.lastName),
senderCommunityUuid: homeCom.communityUuid,
senderUserUuid: sendUser.gradidoID,
senderUserName: fullName(sendUser.firstName, sendUser.lastName),
},
}),
).toEqual(
expect.objectContaining({
errors: [
new GraphQLError(
'voteForSendCoins with unknown userReceiverIdentifier in the community=',
'voteForSendCoins with unknown recipientUserIdentifier in the community=',
),
],
}),
@ -221,14 +207,14 @@ describe('SendCoinsResolver', () => {
await mutate({
mutation: voteForSendCoinsMutation,
variables: {
communityReceiverIdentifier: foreignCom.communityUuid,
userReceiverIdentifier: recipUser.gradidoID,
recipientCommunityUuid: foreignCom.communityUuid,
recipientUserIdentifier: recipUser.gradidoID,
creationDate: new Date().toISOString(),
amount: 100,
memo: 'X-Com-TX memo',
communitySenderIdentifier: homeCom.communityUuid,
userSenderIdentifier: sendUser.gradidoID,
userSenderName: fullName(sendUser.firstName, sendUser.lastName),
senderCommunityUuid: homeCom.communityUuid,
senderUserUuid: sendUser.gradidoID,
senderUserName: fullName(sendUser.firstName, sendUser.lastName),
},
}),
).toEqual(
@ -243,59 +229,43 @@ describe('SendCoinsResolver', () => {
})
describe('revertSendCoins', () => {
let homeCom: DbCommunity
let foreignCom: DbCommunity
let sendUser: DbUser
let recipUser: DbUser
const revertSendCoinsMutation = `
mutation (
$recipientCommunityUuid: String!
$recipientUserIdentifier: String!
$creationDate: String!
$amount: Decimal!
$memo: String!
$senderCommunityUuid: String!
$senderUserUuid: String!
$senderUserName: String!
) {
revertSendCoins(
recipientCommunityUuid: $recipientCommunityUuid
recipientUserIdentifier: $recipientUserIdentifier
creationDate: $creationDate
amount: $amount
memo: $memo
senderCommunityUuid: $senderCommunityUuid
senderUserUuid: $senderUserUuid
senderUserName: $senderUserName
)
}`
const creationDate = new Date()
beforeEach(async () => {
await cleanDB()
homeCom = DbCommunity.create()
homeCom.foreign = false
homeCom.url = 'homeCom-url'
homeCom.name = 'homeCom-Name'
homeCom.description = 'homeCom-Description'
homeCom.creationDate = new Date()
homeCom.publicKey = Buffer.from('homeCom-publicKey')
homeCom.communityUuid = 'homeCom-UUID'
await DbCommunity.insert(homeCom)
foreignCom = DbCommunity.create()
foreignCom.foreign = true
foreignCom.url = 'foreignCom-url'
foreignCom.name = 'foreignCom-Name'
foreignCom.description = 'foreignCom-Description'
foreignCom.creationDate = new Date()
foreignCom.publicKey = Buffer.from('foreignCom-publicKey')
foreignCom.communityUuid = 'foreignCom-UUID'
await DbCommunity.insert(foreignCom)
sendUser = DbUser.create()
sendUser.alias = 'sendUser-alias'
sendUser.firstName = 'sendUser-FirstName'
sendUser.gradidoID = 'sendUser-GradidoID'
sendUser.lastName = 'sendUser-LastName'
await DbUser.insert(sendUser)
recipUser = DbUser.create()
recipUser.alias = 'recipUser-alias'
recipUser.firstName = 'recipUser-FirstName'
recipUser.gradidoID = 'recipUser-GradidoID'
recipUser.lastName = 'recipUser-LastName'
await DbUser.insert(recipUser)
await mutate({
mutation: voteForSendCoinsMutation,
variables: {
communityReceiverIdentifier: foreignCom.communityUuid,
userReceiverIdentifier: recipUser.gradidoID,
recipientCommunityUuid: foreignCom.communityUuid,
recipientUserIdentifier: recipUser.gradidoID,
creationDate: creationDate.toISOString(),
amount: 100,
memo: 'X-Com-TX memo',
communitySenderIdentifier: homeCom.communityUuid,
userSenderIdentifier: sendUser.gradidoID,
userSenderName: fullName(sendUser.firstName, sendUser.lastName),
senderCommunityUuid: homeCom.communityUuid,
senderUserUuid: sendUser.gradidoID,
senderUserName: fullName(sendUser.firstName, sendUser.lastName),
},
})
})
@ -307,19 +277,19 @@ describe('SendCoinsResolver', () => {
await mutate({
mutation: revertSendCoinsMutation,
variables: {
communityReceiverIdentifier: 'invalid foreignCom',
userReceiverIdentifier: recipUser.gradidoID,
recipientCommunityUuid: 'invalid foreignCom',
recipientUserIdentifier: recipUser.gradidoID,
creationDate: creationDate.toISOString(),
amount: 100,
memo: 'X-Com-TX memo',
communitySenderIdentifier: homeCom.communityUuid,
userSenderIdentifier: sendUser.gradidoID,
userSenderName: fullName(sendUser.firstName, sendUser.lastName),
senderCommunityUuid: homeCom.communityUuid,
senderUserUuid: sendUser.gradidoID,
senderUserName: fullName(sendUser.firstName, sendUser.lastName),
},
}),
).toEqual(
expect.objectContaining({
errors: [new GraphQLError('revertSendCoins with wrong communityReceiverIdentifier')],
errors: [new GraphQLError('revertSendCoins with wrong recipientCommunityUuid')],
}),
)
})
@ -332,21 +302,21 @@ describe('SendCoinsResolver', () => {
await mutate({
mutation: revertSendCoinsMutation,
variables: {
communityReceiverIdentifier: foreignCom.communityUuid,
userReceiverIdentifier: 'invalid recipient',
recipientCommunityUuid: foreignCom.communityUuid,
recipientUserIdentifier: 'invalid recipient',
creationDate: creationDate.toISOString(),
amount: 100,
memo: 'X-Com-TX memo',
communitySenderIdentifier: homeCom.communityUuid,
userSenderIdentifier: sendUser.gradidoID,
userSenderName: fullName(sendUser.firstName, sendUser.lastName),
senderCommunityUuid: homeCom.communityUuid,
senderUserUuid: sendUser.gradidoID,
senderUserName: fullName(sendUser.firstName, sendUser.lastName),
},
}),
).toEqual(
expect.objectContaining({
errors: [
new GraphQLError(
'revertSendCoins with unknown userReceiverIdentifier in the community=',
'revertSendCoins with unknown recipientUserIdentifier in the community=',
),
],
}),
@ -361,14 +331,14 @@ describe('SendCoinsResolver', () => {
await mutate({
mutation: revertSendCoinsMutation,
variables: {
communityReceiverIdentifier: foreignCom.communityUuid,
userReceiverIdentifier: recipUser.gradidoID,
recipientCommunityUuid: foreignCom.communityUuid,
recipientUserIdentifier: recipUser.gradidoID,
creationDate: creationDate.toISOString(),
amount: 100,
memo: 'X-Com-TX memo',
communitySenderIdentifier: homeCom.communityUuid,
userSenderIdentifier: sendUser.gradidoID,
userSenderName: fullName(sendUser.firstName, sendUser.lastName),
senderCommunityUuid: homeCom.communityUuid,
senderUserUuid: sendUser.gradidoID,
senderUserName: fullName(sendUser.firstName, sendUser.lastName),
},
}),
).toEqual(
@ -383,61 +353,26 @@ describe('SendCoinsResolver', () => {
})
describe('settleSendCoins', () => {
let homeCom: DbCommunity
let foreignCom: DbCommunity
let sendUser: DbUser
let recipUser: DbUser
let pendingTx: DbPendingTransaction
const creationDate = new Date()
beforeEach(async () => {
await cleanDB()
homeCom = DbCommunity.create()
homeCom.foreign = false
homeCom.url = 'homeCom-url'
homeCom.name = 'homeCom-Name'
homeCom.description = 'homeCom-Description'
homeCom.creationDate = new Date()
homeCom.publicKey = Buffer.from('homeCom-publicKey')
homeCom.communityUuid = 'homeCom-UUID'
await DbCommunity.insert(homeCom)
foreignCom = DbCommunity.create()
foreignCom.foreign = true
foreignCom.url = 'foreignCom-url'
foreignCom.name = 'foreignCom-Name'
foreignCom.description = 'foreignCom-Description'
foreignCom.creationDate = new Date()
foreignCom.publicKey = Buffer.from('foreignCom-publicKey')
foreignCom.communityUuid = 'foreignCom-UUID'
await DbCommunity.insert(foreignCom)
sendUser = DbUser.create()
sendUser.alias = 'sendUser-alias'
sendUser.firstName = 'sendUser-FirstName'
sendUser.gradidoID = 'sendUser-GradidoID'
sendUser.lastName = 'sendUser-LastName'
await DbUser.insert(sendUser)
recipUser = DbUser.create()
recipUser.alias = 'recipUser-alias'
recipUser.firstName = 'recipUser-FirstName'
recipUser.gradidoID = 'recipUser-GradidoID'
recipUser.lastName = 'recipUser-LastName'
await DbUser.insert(recipUser)
pendingTx = DbPendingTransaction.create()
pendingTx.amount = new Decimal(100)
pendingTx.balanceDate = creationDate
// pendingTx.balance = new Decimal(0)
pendingTx.linkedUserId = sendUser.id
pendingTx.linkedUserCommunityUuid = foreignCom.communityUuid
if (foreignCom.communityUuid) {
pendingTx.linkedUserCommunityUuid = foreignCom.communityUuid
}
pendingTx.linkedUserGradidoID = sendUser.gradidoID
pendingTx.state = PendingTransactionState.NEW
pendingTx.typeId = TransactionTypeId.RECEIVE
pendingTx.memo = 'X-Com-TX memo'
pendingTx.userId = recipUser.id
pendingTx.userCommunityUuid = homeCom.communityUuid
if (homeCom.communityUuid) {
pendingTx.userCommunityUuid = homeCom.communityUuid
}
pendingTx.userGradidoID = recipUser.gradidoID
await DbPendingTransaction.insert(pendingTx)
})
@ -449,19 +384,19 @@ describe('SendCoinsResolver', () => {
await mutate({
mutation: settleSendCoinsMutation,
variables: {
communityReceiverIdentifier: 'invalid foreignCom',
userReceiverIdentifier: recipUser.gradidoID,
recipientCommunityUuid: 'invalid foreignCom',
recipientUserIdentifier: recipUser.gradidoID,
creationDate: creationDate.toISOString(),
amount: 100,
memo: 'X-Com-TX memo',
communitySenderIdentifier: foreignCom.communityUuid,
userSenderIdentifier: sendUser.gradidoID,
userSenderName: fullName(sendUser.firstName, sendUser.lastName),
senderCommunityUuid: foreignCom.communityUuid,
senderUserUuid: sendUser.gradidoID,
senderUserName: fullName(sendUser.firstName, sendUser.lastName),
},
}),
).toEqual(
expect.objectContaining({
errors: [new GraphQLError('settleSendCoins with wrong communityReceiverIdentifier')],
errors: [new GraphQLError('settleSendCoins with wrong recipientCommunityUuid')],
}),
)
})
@ -474,21 +409,21 @@ describe('SendCoinsResolver', () => {
await mutate({
mutation: settleSendCoinsMutation,
variables: {
communityReceiverIdentifier: homeCom.communityUuid,
userReceiverIdentifier: 'invalid recipient',
recipientCommunityUuid: homeCom.communityUuid,
recipientUserIdentifier: 'invalid recipient',
creationDate: creationDate.toISOString(),
amount: 100,
memo: 'X-Com-TX memo',
communitySenderIdentifier: foreignCom.communityUuid,
userSenderIdentifier: sendUser.gradidoID,
userSenderName: fullName(sendUser.firstName, sendUser.lastName),
senderCommunityUuid: foreignCom.communityUuid,
senderUserUuid: sendUser.gradidoID,
senderUserName: fullName(sendUser.firstName, sendUser.lastName),
},
}),
).toEqual(
expect.objectContaining({
errors: [
new GraphQLError(
'settleSendCoins with unknown userReceiverIdentifier in the community=',
'settleSendCoins with unknown recipientUserIdentifier in the community=',
),
],
}),
@ -503,14 +438,14 @@ describe('SendCoinsResolver', () => {
await mutate({
mutation: settleSendCoinsMutation,
variables: {
communityReceiverIdentifier: homeCom.communityUuid,
userReceiverIdentifier: recipUser.gradidoID,
recipientCommunityUuid: homeCom.communityUuid,
recipientUserIdentifier: recipUser.gradidoID,
creationDate: creationDate.toISOString(),
amount: 100,
memo: 'X-Com-TX memo',
communitySenderIdentifier: foreignCom.communityUuid,
userSenderIdentifier: sendUser.gradidoID,
userSenderName: fullName(sendUser.firstName, sendUser.lastName),
senderCommunityUuid: foreignCom.communityUuid,
senderUserUuid: sendUser.gradidoID,
senderUserName: fullName(sendUser.firstName, sendUser.lastName),
},
}),
).toEqual(
@ -523,4 +458,164 @@ describe('SendCoinsResolver', () => {
})
})
})
describe('revertSettledSendCoins', () => {
const revertSettledSendCoinsMutation = `
mutation (
$recipientCommunityUuid: String!
$recipientUserIdentifier: String!
$creationDate: String!
$amount: Decimal!
$memo: String!
$senderCommunityUuid: String!
$senderUserUuid: String!
$senderUserName: String!
) {
revertSettledSendCoins(
recipientCommunityUuid: $recipientCommunityUuid
recipientUserIdentifier: $recipientUserIdentifier
creationDate: $creationDate
amount: $amount
memo: $memo
senderCommunityUuid: $senderCommunityUuid
senderUserUuid: $senderUserUuid
senderUserName: $senderUserName
)
}`
let pendingTx: DbPendingTransaction
let settledTx: DbTransaction
const creationDate = new Date()
beforeEach(async () => {
pendingTx = DbPendingTransaction.create()
pendingTx.amount = new Decimal(100)
pendingTx.balanceDate = creationDate
// pendingTx.balance = new Decimal(0)
pendingTx.linkedUserId = sendUser.id
if (foreignCom.communityUuid) {
pendingTx.linkedUserCommunityUuid = foreignCom.communityUuid
}
pendingTx.linkedUserGradidoID = sendUser.gradidoID
pendingTx.linkedUserName = fullName(sendUser.firstName, sendUser.lastName)
pendingTx.state = PendingTransactionState.SETTLED
pendingTx.typeId = TransactionTypeId.RECEIVE
pendingTx.memo = 'X-Com-TX memo'
pendingTx.userId = recipUser.id
if (homeCom.communityUuid) {
pendingTx.userCommunityUuid = homeCom.communityUuid
}
pendingTx.userGradidoID = recipUser.gradidoID
await DbPendingTransaction.insert(pendingTx)
settledTx = DbTransaction.create()
settledTx.amount = new Decimal(100)
settledTx.balanceDate = creationDate
// pendingTx.balance = new Decimal(0)
settledTx.linkedUserId = sendUser.id
settledTx.linkedUserCommunityUuid = foreignCom.communityUuid
settledTx.linkedUserGradidoID = sendUser.gradidoID
settledTx.linkedUserName = fullName(sendUser.firstName, sendUser.lastName)
settledTx.typeId = TransactionTypeId.RECEIVE
settledTx.memo = 'X-Com-TX memo'
settledTx.userId = recipUser.id
if (homeCom.communityUuid) {
settledTx.userCommunityUuid = homeCom.communityUuid
}
settledTx.userGradidoID = recipUser.gradidoID
await DbTransaction.insert(settledTx)
})
describe('unknown recipient community', () => {
it('throws an error', async () => {
jest.clearAllMocks()
expect(
await mutate({
mutation: revertSettledSendCoinsMutation,
variables: {
recipientCommunityUuid: 'invalid foreignCom',
recipientUserIdentifier: recipUser.gradidoID,
creationDate: creationDate.toISOString(),
amount: 100,
memo: 'X-Com-TX memo',
senderCommunityUuid: foreignCom.communityUuid,
senderUserUuid: sendUser.gradidoID,
senderUserName: fullName(sendUser.firstName, sendUser.lastName),
},
}),
).toEqual(
expect.objectContaining({
errors: [new GraphQLError('revertSettledSendCoins with wrong recipientCommunityUuid')],
}),
)
})
})
describe('unknown recipient user', () => {
it('throws an error', async () => {
jest.clearAllMocks()
expect(
await mutate({
mutation: revertSettledSendCoinsMutation,
variables: {
recipientCommunityUuid: homeCom.communityUuid,
recipientUserIdentifier: 'invalid recipient',
creationDate: creationDate.toISOString(),
amount: 100,
memo: 'X-Com-TX memo',
senderCommunityUuid: foreignCom.communityUuid,
senderUserUuid: sendUser.gradidoID,
senderUserName: fullName(sendUser.firstName, sendUser.lastName),
},
}),
).toEqual(
expect.objectContaining({
errors: [
new GraphQLError(
'revertSettledSendCoins with unknown recipientUserIdentifier in the community=',
),
],
}),
)
})
})
describe('valid X-Com-TX settled', () => {
it('throws an error', async () => {
jest.clearAllMocks()
expect(
await mutate({
mutation: revertSettledSendCoinsMutation,
variables: {
recipientCommunityUuid: homeCom.communityUuid,
recipientUserIdentifier: recipUser.gradidoID,
creationDate: creationDate.toISOString(),
amount: 100,
memo: 'X-Com-TX memo',
senderCommunityUuid: foreignCom.communityUuid,
senderUserUuid: sendUser.gradidoID,
senderUserName: fullName(sendUser.firstName, sendUser.lastName),
},
}),
).toEqual(
expect.objectContaining({
data: {
revertSettledSendCoins: true,
},
}),
)
})
})
})
})
async function newEmailContact(email: string, userId: number): Promise<DbUserContact> {
const emailContact = new DbUserContact()
emailContact.email = email
emailContact.userId = userId
emailContact.type = 'EMAIL'
emailContact.emailChecked = false
emailContact.emailOptInTypeId = 1
emailContact.emailVerificationCode = '1' + userId
return emailContact
}

View File

@ -4,7 +4,6 @@ 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 { User as DbUser } from '@entity/User'
import { LogError } from '@/server/LogError'
import { PendingTransactionState } from '../enum/PendingTransactionState'
import { TransactionTypeId } from '../enum/TransactionTypeId'
@ -14,6 +13,7 @@ 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'
@Resolver()
// eslint-disable-next-line @typescript-eslint/no-unused-vars
@ -22,33 +22,46 @@ export class SendCoinsResolver {
async voteForSendCoins(
@Args()
{
communityReceiverIdentifier,
userReceiverIdentifier,
recipientCommunityUuid,
recipientUserIdentifier,
creationDate,
amount,
memo,
communitySenderIdentifier,
userSenderIdentifier,
userSenderName,
senderCommunityUuid,
senderUserUuid,
senderUserName,
}: SendCoinsArgs,
): Promise<string | null> {
logger.debug(`voteForSendCoins() via apiVersion=1_0 ...`)
let result: string | null = null
): Promise<string> {
logger.debug(
`voteForSendCoins() via apiVersion=1_0 ...`,
recipientCommunityUuid,
recipientUserIdentifier,
creationDate,
amount.toString(),
memo,
senderCommunityUuid,
senderUserUuid,
senderUserName,
)
let result: string
// first check if receiver community is correct
const homeCom = await DbCommunity.findOneBy({
communityUuid: communityReceiverIdentifier,
communityUuid: recipientCommunityUuid,
})
if (!homeCom) {
throw new LogError(
`voteForSendCoins with wrong communityReceiverIdentifier`,
communityReceiverIdentifier,
`voteForSendCoins with wrong recipientCommunityUuid`,
recipientCommunityUuid,
)
}
// second check if receiver user exists in this community
const receiverUser = await DbUser.findOneBy({ gradidoID: userReceiverIdentifier })
if (!receiverUser) {
let receiverUser
try {
// second check if receiver user exists in this community
receiverUser = await findUserByIdentifier(recipientUserIdentifier)
} catch (err) {
logger.error('Error in findUserByIdentifier:', err)
throw new LogError(
`voteForSendCoins with unknown userReceiverIdentifier in the community=`,
`voteForSendCoins with unknown recipientUserIdentifier in the community=`,
homeCom.name,
)
}
@ -57,21 +70,21 @@ export class SendCoinsResolver {
const receiveBalance = await calculateRecipientBalance(receiverUser.id, amount, txDate)
const pendingTx = DbPendingTransaction.create()
pendingTx.amount = amount
pendingTx.balance = receiveBalance ? receiveBalance.balance : new Decimal(0)
pendingTx.balance = receiveBalance ? receiveBalance.balance : 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 = communitySenderIdentifier
pendingTx.linkedUserGradidoID = userSenderIdentifier
pendingTx.linkedUserName = userSenderName
pendingTx.linkedUserCommunityUuid = senderCommunityUuid
pendingTx.linkedUserGradidoID = senderUserUuid
pendingTx.linkedUserName = senderUserName
pendingTx.memo = memo
pendingTx.previous = receiveBalance ? receiveBalance.lastTransactionId : null
pendingTx.state = PendingTransactionState.NEW
pendingTx.typeId = TransactionTypeId.RECEIVE
pendingTx.userId = receiverUser.id
pendingTx.userCommunityUuid = communityReceiverIdentifier
pendingTx.userGradidoID = userReceiverIdentifier
pendingTx.userCommunityUuid = recipientCommunityUuid
pendingTx.userGradidoID = receiverUser.gradidoID
pendingTx.userName = fullName(receiverUser.firstName, receiverUser.lastName)
await DbPendingTransaction.insert(pendingTx)
@ -87,44 +100,47 @@ export class SendCoinsResolver {
async revertSendCoins(
@Args()
{
communityReceiverIdentifier,
userReceiverIdentifier,
recipientCommunityUuid,
recipientUserIdentifier,
creationDate,
amount,
memo,
communitySenderIdentifier,
userSenderIdentifier,
userSenderName,
senderCommunityUuid,
senderUserUuid,
senderUserName,
}: SendCoinsArgs,
): Promise<boolean> {
logger.debug(`revertSendCoins() via apiVersion=1_0 ...`)
// first check if receiver community is correct
const homeCom = await DbCommunity.findOneBy({
communityUuid: communityReceiverIdentifier,
communityUuid: recipientCommunityUuid,
})
if (!homeCom) {
throw new LogError(
`revertSendCoins with wrong communityReceiverIdentifier`,
communityReceiverIdentifier,
`revertSendCoins with wrong recipientCommunityUuid`,
recipientCommunityUuid,
)
}
// second check if receiver user exists in this community
const receiverUser = await DbUser.findOneBy({ gradidoID: userReceiverIdentifier })
if (!receiverUser) {
let receiverUser
try {
// second check if receiver user exists in this community
receiverUser = await findUserByIdentifier(recipientUserIdentifier)
} catch (err) {
logger.error('Error in findUserByIdentifier:', err)
throw new LogError(
`revertSendCoins with unknown userReceiverIdentifier in the community=`,
`revertSendCoins with unknown recipientUserIdentifier in the community=`,
homeCom.name,
)
}
try {
const pendingTx = await DbPendingTransaction.findOneBy({
userCommunityUuid: communityReceiverIdentifier,
userGradidoID: userReceiverIdentifier,
userCommunityUuid: recipientCommunityUuid,
userGradidoID: receiverUser.gradidoID,
state: PendingTransactionState.NEW,
typeId: TransactionTypeId.RECEIVE,
balanceDate: new Date(creationDate),
linkedUserCommunityUuid: communitySenderIdentifier,
linkedUserGradidoID: userSenderIdentifier,
linkedUserCommunityUuid: senderCommunityUuid,
linkedUserGradidoID: senderUserUuid,
})
logger.debug('XCom: revertSendCoins found pendingTX=', pendingTx)
if (pendingTx && pendingTx.amount.toString() === amount.toString()) {
@ -143,16 +159,16 @@ export class SendCoinsResolver {
)
throw new LogError(
`Can't find in revertSendCoins the pending receiver TX for args=`,
communityReceiverIdentifier,
userReceiverIdentifier,
recipientCommunityUuid,
recipientUserIdentifier,
PendingTransactionState.NEW,
TransactionTypeId.RECEIVE,
creationDate,
amount,
memo,
communitySenderIdentifier,
userSenderIdentifier,
userSenderName,
senderCommunityUuid,
senderUserUuid,
senderUserName,
)
}
logger.debug(`revertSendCoins()-1_0... successfull`)
@ -166,56 +182,53 @@ export class SendCoinsResolver {
async settleSendCoins(
@Args()
{
communityReceiverIdentifier,
userReceiverIdentifier,
recipientCommunityUuid,
recipientUserIdentifier,
creationDate,
amount,
memo,
communitySenderIdentifier,
userSenderIdentifier,
userSenderName,
senderCommunityUuid,
senderUserUuid,
senderUserName,
}: SendCoinsArgs,
): Promise<boolean> {
logger.debug(
`settleSendCoins() via apiVersion=1_0 ...userCommunityUuid=${communityReceiverIdentifier}, userGradidoID=${userReceiverIdentifier}, balanceDate=${creationDate},amount=${amount.valueOf()}, memo=${memo}, linkedUserCommunityUuid = ${communitySenderIdentifier}, userSenderIdentifier=${userSenderIdentifier}, userSenderName=${userSenderName}`,
`settleSendCoins() via apiVersion=1_0 ...userCommunityUuid=${recipientCommunityUuid}, userGradidoID=${recipientUserIdentifier}, balanceDate=${creationDate},amount=${amount.valueOf()}, memo=${memo}, linkedUserCommunityUuid = ${senderCommunityUuid}, userSenderIdentifier=${senderUserUuid}, userSenderName=${senderUserName}`,
)
// first check if receiver community is correct
const homeCom = await DbCommunity.findOneBy({
communityUuid: communityReceiverIdentifier,
communityUuid: recipientCommunityUuid,
})
if (!homeCom) {
throw new LogError(
`settleSendCoins with wrong communityReceiverIdentifier`,
communityReceiverIdentifier,
`settleSendCoins with wrong recipientCommunityUuid`,
recipientCommunityUuid,
)
}
// second check if receiver user exists in this community
const receiverUser = await DbUser.findOneBy({ gradidoID: userReceiverIdentifier })
if (!receiverUser) {
let receiverUser
try {
// second check if receiver user exists in this community
receiverUser = await findUserByIdentifier(recipientUserIdentifier)
} catch (err) {
logger.error('Error in findUserByIdentifier:', err)
throw new LogError(
`settleSendCoins with unknown userReceiverIdentifier in the community=`,
`settleSendCoins with unknown recipientUserIdentifier in the community=`,
homeCom.name,
)
}
// try {
const pendingTx = await DbPendingTransaction.findOneBy({
userCommunityUuid: communityReceiverIdentifier,
userGradidoID: userReceiverIdentifier,
userCommunityUuid: recipientCommunityUuid,
userGradidoID: receiverUser.gradidoID,
state: PendingTransactionState.NEW,
typeId: TransactionTypeId.RECEIVE,
balanceDate: new Date(creationDate),
linkedUserCommunityUuid: communitySenderIdentifier,
linkedUserGradidoID: userSenderIdentifier,
linkedUserCommunityUuid: senderCommunityUuid,
linkedUserGradidoID: senderUserUuid,
})
logger.debug('XCom: settleSendCoins found pendingTX=', pendingTx?.toString())
if (pendingTx && pendingTx.amount.toString() === amount.toString() && pendingTx.memo === memo) {
logger.debug('XCom: settleSendCoins matching pendingTX for settlement...')
const homeCom = await DbCommunity.findOneByOrFail({
communityUuid: communityReceiverIdentifier,
})
const receiverUser = await DbUser.findOneByOrFail({ gradidoID: userReceiverIdentifier })
await settlePendingReceiveTransaction(homeCom, receiverUser, pendingTx)
logger.debug(`XCom: settlePendingReceiveTransaction()-1_0... successfull`)
return true
@ -223,70 +236,67 @@ export class SendCoinsResolver {
logger.debug('XCom: settlePendingReceiveTransaction NOT matching pendingTX for settlement...')
throw new LogError(
`Can't find in settlePendingReceiveTransaction the pending receiver TX for args=`,
communityReceiverIdentifier,
userReceiverIdentifier,
recipientCommunityUuid,
recipientUserIdentifier,
PendingTransactionState.NEW,
TransactionTypeId.RECEIVE,
creationDate,
amount,
memo,
communitySenderIdentifier,
userSenderIdentifier,
userSenderName,
senderCommunityUuid,
senderUserUuid,
senderUserName,
)
}
/*
} catch (err) {
throw new LogError(`Error in settlePendingReceiveTransaction: `, err)
}
*/
}
@Mutation(() => Boolean)
async revertSettledSendCoins(
@Args()
{
communityReceiverIdentifier,
userReceiverIdentifier,
recipientCommunityUuid,
recipientUserIdentifier,
creationDate,
amount,
memo,
communitySenderIdentifier,
userSenderIdentifier,
userSenderName,
senderCommunityUuid,
senderUserUuid,
senderUserName,
}: SendCoinsArgs,
): Promise<boolean> {
// try {
logger.debug(`revertSettledSendCoins() via apiVersion=1_0 ...`)
// first check if receiver community is correct
const homeCom = await DbCommunity.findOneBy({
communityUuid: communityReceiverIdentifier,
communityUuid: recipientCommunityUuid,
})
if (!homeCom) {
throw new LogError(
`revertSettledSendCoins with wrong communityReceiverIdentifier`,
communityReceiverIdentifier,
`revertSettledSendCoins with wrong recipientCommunityUuid`,
recipientCommunityUuid,
)
}
// second check if receiver user exists in this community
const receiverUser = await DbUser.findOneBy({ gradidoID: userReceiverIdentifier })
if (!receiverUser) {
let receiverUser
try {
// second check if receiver user exists in this community
receiverUser = await findUserByIdentifier(recipientUserIdentifier)
} catch (err) {
logger.error('Error in findUserByIdentifier:', err)
throw new LogError(
`revertSettledSendCoins with unknown userReceiverIdentifier in the community=`,
`revertSettledSendCoins with unknown recipientUserIdentifier in the community=`,
homeCom.name,
)
}
const pendingTx = await DbPendingTransaction.findOneBy({
userCommunityUuid: communityReceiverIdentifier,
userGradidoID: userReceiverIdentifier,
userCommunityUuid: recipientCommunityUuid,
userGradidoID: receiverUser.gradidoID,
state: PendingTransactionState.SETTLED,
typeId: TransactionTypeId.RECEIVE,
balanceDate: new Date(creationDate),
linkedUserCommunityUuid: communitySenderIdentifier,
linkedUserGradidoID: userSenderIdentifier,
linkedUserCommunityUuid: senderCommunityUuid,
linkedUserGradidoID: senderUserUuid,
})
logger.debug('XCom: revertSettledSendCoins found pendingTX=', pendingTx)
if (pendingTx && pendingTx.amount === amount && pendingTx.memo === memo) {
if (pendingTx && pendingTx.amount.toString() === amount.toString() && pendingTx.memo === memo) {
logger.debug('XCom: revertSettledSendCoins matching pendingTX for remove...')
try {
await revertSettledReceiveTransaction(homeCom, receiverUser, pendingTx)
@ -298,24 +308,19 @@ export class SendCoinsResolver {
logger.debug('XCom: revertSettledSendCoins NOT matching pendingTX...')
throw new LogError(
`Can't find in revertSettledSendCoins the pending receiver TX for args=`,
communityReceiverIdentifier,
userReceiverIdentifier,
recipientCommunityUuid,
recipientUserIdentifier,
PendingTransactionState.SETTLED,
TransactionTypeId.RECEIVE,
creationDate,
amount,
memo,
communitySenderIdentifier,
userSenderIdentifier,
userSenderName,
senderCommunityUuid,
senderUserUuid,
senderUserName,
)
}
logger.debug(`revertSendCoins()-1_0... successfull`)
return true
/*
} catch (err) {
throw new LogError(`Error in revertSendCoins: `, err)
}
*/
}
}

View File

@ -64,10 +64,10 @@ export async function revertSettledReceiveTransaction(
if (
lastTransaction &&
lastTransaction.balance === pendingTx.balance &&
lastTransaction.balanceDate === pendingTx.balanceDate &&
lastTransaction.balanceDate.toISOString() === pendingTx.balanceDate.toISOString() &&
lastTransaction.userGradidoID === pendingTx.userGradidoID &&
lastTransaction.userName === pendingTx.userName &&
lastTransaction.amount === pendingTx.amount &&
lastTransaction.amount.toString() === pendingTx.amount.toString() &&
lastTransaction.memo === pendingTx.memo &&
lastTransaction.linkedUserGradidoID === pendingTx.linkedUserGradidoID &&
lastTransaction.linkedUserName === pendingTx.linkedUserName
@ -83,7 +83,9 @@ export async function revertSettledReceiveTransaction(
} else {
// TODO: if the last TX is not equivelant to pendingTX, the transactions must be corrected in EXPERT-MODE
throw new LogError(
`X-Com: missmatching transaction order for revert settlement! lastTransation=${lastTransaction} != pendingTx=${pendingTx}`,
`X-Com: missmatching transaction order for revert settlement!`,
lastTransaction,
pendingTx,
)
}

View File

@ -16,6 +16,7 @@ import { federationLogger as logger } from '@/server/logger'
import { getLastTransaction } from '@/graphql/util/getLastTransaction'
import { TRANSACTIONS_LOCK } from '@/graphql/util/TRANSACTIONS_LOCK'
import { calculateRecipientBalance } from './calculateRecipientBalance'
import Decimal from 'decimal.js-light'
export async function settlePendingReceiveTransaction(
homeCom: DbCommunity,
@ -52,7 +53,7 @@ export async function settlePendingReceiveTransaction(
const lastTransaction = await getLastTransaction(receiverUser.id)
if (lastTransaction === undefined && lastTransaction.id !== pendingTx.previous) {
if (lastTransaction !== null && lastTransaction.id !== pendingTx.previous) {
throw new LogError(
`X-Com: missmatching transaction order! lastTransationId=${lastTransaction?.id} != pendingTx.previous=${pendingTx.previous}`,
)
@ -63,9 +64,11 @@ export async function settlePendingReceiveTransaction(
transactionReceive.typeId = pendingTx.typeId
transactionReceive.memo = pendingTx.memo
transactionReceive.userId = pendingTx.userId
transactionReceive.userCommunityUuid = pendingTx.userCommunityUuid
transactionReceive.userGradidoID = pendingTx.userGradidoID
transactionReceive.userName = pendingTx.userName
transactionReceive.linkedUserId = pendingTx.linkedUserId
transactionReceive.linkedUserCommunityUuid = pendingTx.linkedUserCommunityUuid
transactionReceive.linkedUserGradidoID = pendingTx.linkedUserGradidoID
transactionReceive.linkedUserName = pendingTx.linkedUserName
transactionReceive.amount = pendingTx.amount
@ -74,16 +77,19 @@ export async function settlePendingReceiveTransaction(
pendingTx.amount,
pendingTx.balanceDate,
)
if (receiveBalance?.balance !== pendingTx.balance) {
if (
receiveBalance !== null &&
receiveBalance.balance.toString() !== pendingTx.balance.toString()
) {
throw new LogError(
`X-Com: Calculation-Error on receiver balance: receiveBalance=${receiveBalance?.balance}, pendingTx.balance=${pendingTx.balance}`,
`X-Com: Calculation-Error on receiver balance: receiveBalance=${receiveBalance.balance}, pendingTx.balance=${pendingTx.balance}`,
)
}
transactionReceive.balance = pendingTx.balance
transactionReceive.balance = receiveBalance ? receiveBalance.balance : pendingTx.amount
transactionReceive.balanceDate = pendingTx.balanceDate
transactionReceive.decay = pendingTx.decay
transactionReceive.decayStart = pendingTx.decayStart
transactionReceive.previous = pendingTx.previous
transactionReceive.decay = receiveBalance ? receiveBalance.decay.decay : new Decimal(0)
transactionReceive.decayStart = receiveBalance ? receiveBalance.decay.start : null
transactionReceive.previous = receiveBalance ? receiveBalance.lastTransactionId : null
transactionReceive.linkedTransactionId = pendingTx.linkedTransactionId
await queryRunner.manager.insert(dbTransaction, transactionReceive)
logger.debug(`receive Transaction inserted: ${dbTransaction}`)

View File

@ -0,0 +1,42 @@
import { User as DbUser } from '@entity/User'
import { UserContact as DbUserContact } from '@entity/UserContact'
import { validate, version } from 'uuid'
import { LogError } from '@/server/LogError'
import { VALID_ALIAS_REGEX } from './validateAlias'
export const findUserByIdentifier = async (identifier: string): Promise<DbUser> => {
let user: DbUser | null
if (validate(identifier) && version(identifier) === 4) {
user = await DbUser.findOne({ where: { gradidoID: identifier }, relations: ['emailContact'] })
if (!user) {
throw new LogError('No user found to given identifier', identifier)
}
} else if (/^.{2,}@.{2,}\..{2,}$/.exec(identifier)) {
const userContact = await DbUserContact.findOne({
where: {
email: identifier,
emailChecked: true,
},
relations: ['user'],
})
if (!userContact) {
throw new LogError('No user with this credentials', identifier)
}
if (!userContact.user) {
throw new LogError('No user to given contact', identifier)
}
user = userContact.user
user.emailContact = userContact
} else if (VALID_ALIAS_REGEX.exec(identifier)) {
user = await DbUser.findOne({ where: { alias: identifier }, relations: ['emailContact'] })
if (!user) {
throw new LogError('No user found to given identifier', identifier)
}
} else {
throw new LogError('Unknown identifier type', identifier)
}
return user
}

View File

@ -0,0 +1,39 @@
import { Raw } from '@dbTools/typeorm'
import { User as DbUser } from '@entity/User'
import { LogError } from '@/server/LogError'
export const VALID_ALIAS_REGEX = /^(?=.{3,20}$)[a-zA-Z0-9]+(?:[_-][a-zA-Z0-9]+?)*$/
const RESERVED_ALIAS = [
'admin',
'email',
'gast',
'gdd',
'gradido',
'guest',
'home',
'root',
'support',
'temp',
'tmp',
'tmp',
'user',
'usr',
'var',
]
export const validateAlias = async (alias: string): Promise<boolean> => {
if (alias.length < 3) throw new LogError('Given alias is too short', alias)
if (alias.length > 20) throw new LogError('Given alias is too long', alias)
if (!alias.match(VALID_ALIAS_REGEX)) throw new LogError('Invalid characters in alias', alias)
if (RESERVED_ALIAS.includes(alias.toLowerCase()))
throw new LogError('Alias is not allowed', alias)
const aliasInUse = await DbUser.find({
where: { alias: Raw((a) => `LOWER(${a}) = "${alias.toLowerCase()}"`) },
})
if (aliasInUse.length !== 0) {
throw new LogError('Alias already in use', alias)
}
return true
}

View File

@ -1057,6 +1057,11 @@
resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c"
integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==
"@types/uuid@8.3.4":
version "8.3.4"
resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc"
integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==
"@types/ws@^7.0.0":
version "7.4.7"
resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702"
@ -5442,16 +5447,16 @@ utils-merge@1.0.1:
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==
uuid@8.3.2, uuid@^8.0.0:
version "8.3.2"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
uuid@^3.1.0:
version "3.4.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
uuid@^8.0.0:
version "8.3.2"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
v8-compile-cache-lib@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf"