mirror of
https://github.com/IT4Change/gradido.git
synced 2026-02-06 09:56:05 +00:00
refactored process
This commit is contained in:
parent
de162647e5
commit
7ddd1cf922
@ -9,6 +9,7 @@ import { backendLogger as logger } from '@/server/logger'
|
||||
// eslint-disable-next-line import/named, n/no-extraneous-import
|
||||
|
||||
import { TransactionDraft } from './model/TransactionDraft'
|
||||
import { TransactionLinkDraft } from './model/TransactionLinkDraft'
|
||||
import { TransactionResult } from './model/TransactionResult'
|
||||
import { UserAccountDraft } from './model/UserAccountDraft'
|
||||
|
||||
@ -29,6 +30,23 @@ const sendTransaction = gql`
|
||||
}
|
||||
`
|
||||
|
||||
const deferredTransfer = gql`
|
||||
mutation ($input: TransactionLinkDraft!) {
|
||||
deferredTransfer(data: $input) {
|
||||
error {
|
||||
message
|
||||
name
|
||||
}
|
||||
succeed
|
||||
recipe {
|
||||
createdAt
|
||||
type
|
||||
messageIdHex
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
const registerAddress = gql`
|
||||
mutation ($input: UserAccountDraft!) {
|
||||
registerAddress(data: $input) {
|
||||
@ -114,6 +132,15 @@ export class DltConnectorClient {
|
||||
return this.handleTransactionResult(result)
|
||||
}
|
||||
|
||||
private async deferredTransfer(input: TransactionLinkDraft) {
|
||||
const {
|
||||
data: { deferredTransfer: result },
|
||||
} = await this.client.rawRequest<{ deferredTransfer: TransactionResult }>(deferredTransfer, {
|
||||
input,
|
||||
})
|
||||
return this.handleTransactionResult(result)
|
||||
}
|
||||
|
||||
private async registerAddress(input: UserAccountDraft) {
|
||||
const {
|
||||
data: { registerAddress: result },
|
||||
@ -128,7 +155,7 @@ export class DltConnectorClient {
|
||||
* and update dltTransactionId of transaction in db with iota message id
|
||||
*/
|
||||
public async transmitTransaction(
|
||||
input: TransactionDraft | UserAccountDraft,
|
||||
input: TransactionDraft | UserAccountDraft | TransactionLinkDraft,
|
||||
): Promise<TransactionResult | undefined> {
|
||||
// we don't need the receive transactions, there contain basically the same data as the send transactions
|
||||
if (
|
||||
@ -144,6 +171,8 @@ export class DltConnectorClient {
|
||||
return await this.sendTransaction(input)
|
||||
} else if (input instanceof UserAccountDraft) {
|
||||
return await this.registerAddress(input)
|
||||
} else if (input instanceof TransactionLinkDraft) {
|
||||
return await this.deferredTransfer(input)
|
||||
} else {
|
||||
throw new LogError('unhandled branch reached')
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@ import { ObjectLiteral, OrderByCondition, SelectQueryBuilder } from '@dbTools/ty
|
||||
import { DltTransaction } from '@entity/DltTransaction'
|
||||
|
||||
import { TransactionDraft } from '@dltConnector/model/TransactionDraft'
|
||||
import { TransactionLinkDraft } from '@dltConnector/model/TransactionLinkDraft'
|
||||
import { UserAccountDraft } from '@dltConnector/model/UserAccountDraft'
|
||||
|
||||
import { backendLogger as logger } from '@/server/logger'
|
||||
@ -13,7 +14,11 @@ export abstract class AbstractTransactionToDltRole<T extends ObjectLiteral> {
|
||||
// public interface
|
||||
public abstract initWithLast(): Promise<this>
|
||||
public abstract getTimestamp(): number
|
||||
public abstract convertToGraphqlInput(): TransactionDraft | UserAccountDraft
|
||||
public abstract convertToGraphqlInput():
|
||||
| TransactionDraft
|
||||
| UserAccountDraft
|
||||
| TransactionLinkDraft
|
||||
|
||||
public getEntity(): T | null {
|
||||
return this.self
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ import { DltTransaction } from '@entity/DltTransaction'
|
||||
import { TransactionLink } from '@entity/TransactionLink'
|
||||
|
||||
import { TransactionDraft } from '@dltConnector/model/TransactionDraft'
|
||||
import { TransactionLinkDraft } from '@dltConnector/model/TransactionLinkDraft'
|
||||
import { UserAccountDraft } from '@dltConnector/model/UserAccountDraft'
|
||||
|
||||
import { LogError } from '@/server/LogError'
|
||||
@ -29,11 +30,11 @@ export class TransactionLinkToDltRole extends AbstractTransactionToDltRole<Trans
|
||||
return this.self.createdAt.getTime()
|
||||
}
|
||||
|
||||
public convertToGraphqlInput(): TransactionDraft | UserAccountDraft {
|
||||
public convertToGraphqlInput(): TransactionDraft | UserAccountDraft | TransactionLinkDraft {
|
||||
if (!this.self) {
|
||||
throw new LogError('try to create dlt entry for empty transaction link')
|
||||
}
|
||||
return new TransactionDraft(this.self)
|
||||
return new TransactionLinkDraft(this.self)
|
||||
}
|
||||
|
||||
protected setJoinId(dltTransaction: DltTransaction): void {
|
||||
|
||||
@ -2,6 +2,7 @@ import { DltTransaction } from '@entity/DltTransaction'
|
||||
import { Transaction } from '@entity/Transaction'
|
||||
|
||||
import { TransactionDraft } from '@dltConnector/model/TransactionDraft'
|
||||
import { TransactionLinkDraft } from '@dltConnector/model/TransactionLinkDraft'
|
||||
import { UserAccountDraft } from '@dltConnector/model/UserAccountDraft'
|
||||
|
||||
import { LogError } from '@/server/LogError'
|
||||
@ -29,7 +30,7 @@ export class TransactionToDltRole extends AbstractTransactionToDltRole<Transacti
|
||||
return this.self.balanceDate.getTime()
|
||||
}
|
||||
|
||||
public convertToGraphqlInput(): TransactionDraft | UserAccountDraft {
|
||||
public convertToGraphqlInput(): TransactionDraft | UserAccountDraft | TransactionLinkDraft {
|
||||
if (!this.self) {
|
||||
throw new LogError('try to create dlt entry for empty transaction')
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ import { DltTransaction } from '@entity/DltTransaction'
|
||||
import { User } from '@entity/User'
|
||||
|
||||
import { TransactionDraft } from '@dltConnector/model/TransactionDraft'
|
||||
import { TransactionLinkDraft } from '@dltConnector/model/TransactionLinkDraft'
|
||||
import { UserAccountDraft } from '@dltConnector/model/UserAccountDraft'
|
||||
|
||||
import { LogError } from '@/server/LogError'
|
||||
@ -29,7 +30,7 @@ export class UserToDltRole extends AbstractTransactionToDltRole<User> {
|
||||
return this.self.createdAt.getTime()
|
||||
}
|
||||
|
||||
public convertToGraphqlInput(): TransactionDraft | UserAccountDraft {
|
||||
public convertToGraphqlInput(): TransactionDraft | UserAccountDraft | TransactionLinkDraft {
|
||||
if (!this.self) {
|
||||
throw new LogError('try to create dlt entry for empty transaction')
|
||||
}
|
||||
|
||||
@ -1,7 +0,0 @@
|
||||
export class IdentifierSeed {
|
||||
seed: string
|
||||
|
||||
constructor(seed: string) {
|
||||
this.seed = seed
|
||||
}
|
||||
}
|
||||
@ -1,52 +1,39 @@
|
||||
// https://www.npmjs.com/package/@apollo/protobufjs
|
||||
import { Transaction } from '@entity/Transaction'
|
||||
import { TransactionLink } from '@entity/TransactionLink'
|
||||
|
||||
import { TransactionTypeId } from '@/graphql/enum/TransactionTypeId'
|
||||
import { LogError } from '@/server/LogError'
|
||||
|
||||
import { IdentifierSeed } from './IdentifierSeed'
|
||||
import { UserIdentifier } from './UserIdentifier'
|
||||
|
||||
export class TransactionDraft {
|
||||
user: UserIdentifier
|
||||
linkedUser: UserIdentifier | IdentifierSeed
|
||||
linkedUser: UserIdentifier
|
||||
amount: string
|
||||
type: string
|
||||
createdAt: string
|
||||
// only for creation transactions
|
||||
targetDate?: string
|
||||
// only for transaction links
|
||||
timeoutDate?: string
|
||||
|
||||
constructor(transaction: Transaction | TransactionLink) {
|
||||
constructor(transaction: Transaction) {
|
||||
this.amount = transaction.amount.abs().toString()
|
||||
|
||||
if (transaction instanceof Transaction) {
|
||||
if (
|
||||
!transaction.linkedUserGradidoID ||
|
||||
!transaction.linkedUserCommunityUuid ||
|
||||
!transaction.userCommunityUuid
|
||||
) {
|
||||
throw new LogError(
|
||||
`missing necessary field in transaction: ${transaction.id}, need linkedUserGradidoID, linkedUserCommunityUuid and userCommunityUuid`,
|
||||
)
|
||||
}
|
||||
this.user = new UserIdentifier(transaction.userGradidoID, transaction.userCommunityUuid)
|
||||
this.linkedUser = new UserIdentifier(
|
||||
transaction.linkedUserGradidoID,
|
||||
transaction.linkedUserCommunityUuid,
|
||||
if (
|
||||
!transaction.linkedUserGradidoID ||
|
||||
!transaction.linkedUserCommunityUuid ||
|
||||
!transaction.userCommunityUuid
|
||||
) {
|
||||
throw new LogError(
|
||||
`missing necessary field in transaction: ${transaction.id}, need linkedUserGradidoID, linkedUserCommunityUuid and userCommunityUuid`,
|
||||
)
|
||||
this.createdAt = transaction.balanceDate.toISOString()
|
||||
this.targetDate = transaction.creationDate?.toISOString()
|
||||
this.type = TransactionTypeId[transaction.typeId]
|
||||
} else if (transaction instanceof TransactionLink) {
|
||||
const user = transaction.user
|
||||
this.user = new UserIdentifier(user.gradidoID, user.communityUuid)
|
||||
this.linkedUser = new IdentifierSeed(transaction.code)
|
||||
this.createdAt = transaction.createdAt.toISOString()
|
||||
this.type = TransactionTypeId[TransactionTypeId.LINK_SUMMARY]
|
||||
this.timeoutDate = transaction.validUntil.toISOString()
|
||||
}
|
||||
this.user = new UserIdentifier(transaction.userGradidoID, transaction.userCommunityUuid)
|
||||
this.linkedUser = new UserIdentifier(
|
||||
transaction.linkedUserGradidoID,
|
||||
transaction.linkedUserCommunityUuid,
|
||||
)
|
||||
this.createdAt = transaction.balanceDate.toISOString()
|
||||
this.targetDate = transaction.creationDate?.toISOString()
|
||||
this.type = TransactionTypeId[transaction.typeId]
|
||||
}
|
||||
}
|
||||
|
||||
21
backend/src/apis/dltConnector/model/TransactionLinkDraft.ts
Normal file
21
backend/src/apis/dltConnector/model/TransactionLinkDraft.ts
Normal file
@ -0,0 +1,21 @@
|
||||
// https://www.npmjs.com/package/@apollo/protobufjs
|
||||
import { TransactionLink } from '@entity/TransactionLink'
|
||||
|
||||
import { UserIdentifier } from './UserIdentifier'
|
||||
|
||||
export class TransactionLinkDraft {
|
||||
user: UserIdentifier
|
||||
seed: string
|
||||
amount: string
|
||||
createdAt: string
|
||||
timeoutDate: string
|
||||
|
||||
constructor(transaction: TransactionLink) {
|
||||
this.amount = transaction.amount.abs().toString()
|
||||
const user = transaction.user
|
||||
this.user = new UserIdentifier(user.gradidoID, user.communityUuid)
|
||||
this.seed = transaction.code
|
||||
this.createdAt = transaction.createdAt.toISOString()
|
||||
this.timeoutDate = transaction.validUntil.toISOString()
|
||||
}
|
||||
}
|
||||
@ -6,6 +6,9 @@ export enum InputTransactionType {
|
||||
CREATION = 1,
|
||||
SEND = 2,
|
||||
RECEIVE = 3,
|
||||
// This is a virtual property, never occurring on the database
|
||||
DECAY = 4,
|
||||
LINK_SUMMARY = 5,
|
||||
}
|
||||
|
||||
registerEnumType(InputTransactionType, {
|
||||
|
||||
@ -1,9 +1,15 @@
|
||||
// https://www.npmjs.com/package/@apollo/protobufjs
|
||||
|
||||
import { IsString } from 'class-validator'
|
||||
import { InputType, Field } from 'type-graphql'
|
||||
import { Field, InputType } from 'type-graphql'
|
||||
|
||||
@InputType()
|
||||
export class IdentifierSeed {
|
||||
@Field(() => String)
|
||||
@IsString()
|
||||
seed: string
|
||||
|
||||
constructor(seed: string) {
|
||||
this.seed = seed
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,11 +1,9 @@
|
||||
// https://www.npmjs.com/package/@apollo/protobufjs
|
||||
import { InputTransactionType } from '@enum/InputTransactionType'
|
||||
import { isValidDateString, isValidNumberString } from '@validator/DateString'
|
||||
import { IsEnum, IsObject, ValidateNested } from 'class-validator'
|
||||
import { InputType, Field } from 'type-graphql'
|
||||
|
||||
import { InputTransactionType } from '@enum/InputTransactionType'
|
||||
import { isValidDateString, isValidNumberString } from '@validator/DateString'
|
||||
|
||||
import { IdentifierSeed } from './IdentifierSeed'
|
||||
import { UserIdentifier } from './UserIdentifier'
|
||||
|
||||
@InputType()
|
||||
@ -18,7 +16,7 @@ export class TransactionDraft {
|
||||
@Field(() => UserIdentifier)
|
||||
@IsObject()
|
||||
@ValidateNested()
|
||||
linkedUser: UserIdentifier | IdentifierSeed
|
||||
linkedUser: UserIdentifier
|
||||
|
||||
@Field(() => String)
|
||||
@isValidNumberString()
|
||||
@ -36,9 +34,4 @@ export class TransactionDraft {
|
||||
@Field(() => String, { nullable: true })
|
||||
@isValidDateString()
|
||||
targetDate?: string
|
||||
|
||||
// only for transaction links
|
||||
@Field(() => String, { nullable: true })
|
||||
@isValidDateString()
|
||||
timeoutDate?: string
|
||||
}
|
||||
|
||||
30
dlt-connector/src/graphql/input/TransactionLinkDraft.ts
Normal file
30
dlt-connector/src/graphql/input/TransactionLinkDraft.ts
Normal file
@ -0,0 +1,30 @@
|
||||
// https://www.npmjs.com/package/@apollo/protobufjs
|
||||
import { isValidDateString, isValidNumberString } from '@validator/DateString'
|
||||
import { IsObject, IsString, ValidateNested } from 'class-validator'
|
||||
import { InputType, Field } from 'type-graphql'
|
||||
|
||||
import { UserIdentifier } from './UserIdentifier'
|
||||
|
||||
@InputType()
|
||||
export class TransactionLinkDraft {
|
||||
@Field(() => UserIdentifier)
|
||||
@IsObject()
|
||||
@ValidateNested()
|
||||
user: UserIdentifier
|
||||
|
||||
@Field(() => String)
|
||||
@IsString()
|
||||
seed: string
|
||||
|
||||
@Field(() => String)
|
||||
@isValidNumberString()
|
||||
amount: string
|
||||
|
||||
@Field(() => String)
|
||||
@isValidDateString()
|
||||
createdAt: string
|
||||
|
||||
@Field(() => String)
|
||||
@isValidDateString()
|
||||
timeoutDate: string
|
||||
}
|
||||
@ -1,9 +1,9 @@
|
||||
import { TransactionLinkDraft } from '@input/TransactionLinkDraft'
|
||||
import { Resolver, Arg, Mutation } from 'type-graphql'
|
||||
|
||||
import { TransactionDraft } from '@input/TransactionDraft'
|
||||
|
||||
import { SendToIotaContext } from '@/interactions/sendToIota/SendToIota.context'
|
||||
|
||||
import { TransactionDraft } from '../input/TransactionDraft'
|
||||
import { TransactionError } from '../model/TransactionError'
|
||||
import { TransactionResult } from '../model/TransactionResult'
|
||||
|
||||
@ -25,4 +25,21 @@ export class TransactionResolver {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Mutation(() => TransactionResult)
|
||||
async deferredTransfer(
|
||||
@Arg('data')
|
||||
transactionLinkDraft: TransactionLinkDraft,
|
||||
): Promise<TransactionResult> {
|
||||
try {
|
||||
return await SendToIotaContext(transactionLinkDraft)
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
} catch (error: any) {
|
||||
if (error instanceof TransactionError) {
|
||||
return new TransactionResult(error)
|
||||
} else {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import { GradidoTransactionBuilder, TransferAmount } from 'gradido-blockchain-js'
|
||||
|
||||
import { IdentifierSeed } from '@/graphql/input/IdentifierSeed'
|
||||
import { TransactionDraft } from '@/graphql/input/TransactionDraft'
|
||||
import { LogError } from '@/server/LogError'
|
||||
|
||||
@ -22,9 +21,6 @@ export class CreationTransactionRole extends AbstractTransactionRole {
|
||||
}
|
||||
|
||||
public async getGradidoTransactionBuilder(): Promise<GradidoTransactionBuilder> {
|
||||
if (this.self.linkedUser instanceof IdentifierSeed) {
|
||||
throw new LogError('invalid recipient, it is a IdentifierSeed instead of a UserIdentifier')
|
||||
}
|
||||
if (!this.self.targetDate) {
|
||||
throw new LogError('target date missing for creation transaction')
|
||||
}
|
||||
|
||||
@ -1,27 +1,30 @@
|
||||
import { GradidoTransactionBuilder, GradidoTransfer, TransferAmount } from 'gradido-blockchain-js'
|
||||
|
||||
import { UserIdentifier } from '@/graphql/input/UserIdentifier'
|
||||
import { IdentifierSeed } from '@/graphql/input/IdentifierSeed'
|
||||
import { TransactionLinkDraft } from '@/graphql/input/TransactionLinkDraft'
|
||||
import { LogError } from '@/server/LogError'
|
||||
|
||||
import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context'
|
||||
|
||||
import { TransferTransactionRole } from './TransferTransaction.role'
|
||||
import { AbstractTransactionRole } from './AbstractTransaction.role'
|
||||
|
||||
export class DeferredTransferTransactionRole extends AbstractTransactionRole {
|
||||
constructor(protected self: TransactionLinkDraft) {
|
||||
super()
|
||||
}
|
||||
|
||||
getSenderCommunityUuid(): string {
|
||||
return this.self.user.communityUuid
|
||||
}
|
||||
|
||||
export class DeferredTransferTransactionRole extends TransferTransactionRole {
|
||||
getRecipientCommunityUuid(): string {
|
||||
throw new LogError('cannot be used as cross group transaction')
|
||||
}
|
||||
|
||||
public async getGradidoTransactionBuilder(): Promise<GradidoTransactionBuilder> {
|
||||
if (this.self.linkedUser instanceof UserIdentifier) {
|
||||
throw new LogError('invalid recipient, it is a UserIdentifier instead of a IdentifierSeed')
|
||||
}
|
||||
if (!this.self.timeoutDate) {
|
||||
throw new LogError('timeoutDate date missing for deferred transfer transaction')
|
||||
}
|
||||
const builder = new GradidoTransactionBuilder()
|
||||
const senderKeyPair = await KeyPairCalculation(this.self.user)
|
||||
const recipientKeyPair = await KeyPairCalculation(this.self.linkedUser)
|
||||
const recipientKeyPair = await KeyPairCalculation(new IdentifierSeed(this.self.seed))
|
||||
|
||||
builder
|
||||
.setCreatedAt(new Date(this.self.createdAt))
|
||||
|
||||
@ -12,6 +12,7 @@ import { InputTransactionType } from '@/graphql/enum/InputTransactionType'
|
||||
import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType'
|
||||
import { CommunityDraft } from '@/graphql/input/CommunityDraft'
|
||||
import { TransactionDraft } from '@/graphql/input/TransactionDraft'
|
||||
import { TransactionLinkDraft } from '@/graphql/input/TransactionLinkDraft'
|
||||
import { UserAccountDraft } from '@/graphql/input/UserAccountDraft'
|
||||
import { TransactionError } from '@/graphql/model/TransactionError'
|
||||
import { TransactionRecipe } from '@/graphql/model/TransactionRecipe'
|
||||
@ -23,6 +24,7 @@ import { uuid4ToHash } from '@/utils/typeConverter'
|
||||
import { AbstractTransactionRole } from './AbstractTransaction.role'
|
||||
import { CommunityRootTransactionRole } from './CommunityRootTransaction.role'
|
||||
import { CreationTransactionRole } from './CreationTransaction.role'
|
||||
import { DeferredTransferTransactionRole } from './DeferredTransferTransaction.role'
|
||||
import { RegisterAddressTransactionRole } from './RegisterAddressTransaction.role'
|
||||
import { TransferTransactionRole } from './TransferTransaction.role'
|
||||
|
||||
@ -32,7 +34,7 @@ import { TransferTransactionRole } from './TransferTransaction.role'
|
||||
* send every transaction only once to iota!
|
||||
*/
|
||||
export async function SendToIotaContext(
|
||||
input: TransactionDraft | UserAccountDraft | CommunityDraft,
|
||||
input: TransactionDraft | UserAccountDraft | CommunityDraft | TransactionLinkDraft,
|
||||
): Promise<TransactionResult> {
|
||||
const validate = (transaction: GradidoTransaction): void => {
|
||||
try {
|
||||
@ -81,6 +83,8 @@ export async function SendToIotaContext(
|
||||
} else {
|
||||
throw new LogError('not supported transaction type')
|
||||
}
|
||||
} else if (input instanceof TransactionLinkDraft) {
|
||||
role = new DeferredTransferTransactionRole(input)
|
||||
} else if (input instanceof UserAccountDraft) {
|
||||
role = new RegisterAddressTransactionRole(input)
|
||||
} else if (input instanceof CommunityDraft) {
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
import { GradidoTransactionBuilder, TransferAmount } from 'gradido-blockchain-js'
|
||||
|
||||
import { IdentifierSeed } from '@/graphql/input/IdentifierSeed'
|
||||
import { TransactionDraft } from '@/graphql/input/TransactionDraft'
|
||||
import { LogError } from '@/server/LogError'
|
||||
import { uuid4ToHash } from '@/utils/typeConverter'
|
||||
|
||||
import { KeyPairCalculation } from '../keyPairCalculation/KeyPairCalculation.context'
|
||||
@ -19,17 +17,10 @@ export class TransferTransactionRole extends AbstractTransactionRole {
|
||||
}
|
||||
|
||||
getRecipientCommunityUuid(): string {
|
||||
if (this.self.linkedUser instanceof IdentifierSeed) {
|
||||
throw new LogError('invalid recipient, it is a IdentifierSeed instead of a UserIdentifier')
|
||||
}
|
||||
return this.self.linkedUser.communityUuid
|
||||
}
|
||||
|
||||
public async getGradidoTransactionBuilder(): Promise<GradidoTransactionBuilder> {
|
||||
if (this.self.linkedUser instanceof IdentifierSeed) {
|
||||
throw new LogError('invalid recipient, it is a IdentifierSeed instead of a UserIdentifier')
|
||||
}
|
||||
|
||||
const builder = new GradidoTransactionBuilder()
|
||||
const senderKeyPair = await KeyPairCalculation(this.self.user)
|
||||
const recipientKeyPair = await KeyPairCalculation(this.self.linkedUser)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user