mirror of
https://github.com/IT4Change/gradido.git
synced 2026-02-06 09:56:05 +00:00
refactored, not final yet
This commit is contained in:
parent
2ff7adef52
commit
8ccc52ae0a
@ -14,6 +14,7 @@ module.exports = {
|
||||
// 'plugin:import/typescript',
|
||||
// 'plugin:security/recommended',
|
||||
'plugin:@eslint-community/eslint-comments/recommended',
|
||||
'plugin:dci-lint/recommended',
|
||||
],
|
||||
settings: {
|
||||
'import/parsers': {
|
||||
@ -36,6 +37,7 @@ module.exports = {
|
||||
htmlWhitespaceSensitivity: 'ignore',
|
||||
},
|
||||
],
|
||||
// 'dci-lint/literal-role-contracts': 'off'
|
||||
// import
|
||||
// 'import/export': 'error',
|
||||
// 'import/no-deprecated': 'error',
|
||||
|
||||
@ -53,6 +53,7 @@
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-config-standard": "^17.0.0",
|
||||
"eslint-import-resolver-typescript": "^3.5.4",
|
||||
"eslint-plugin-dci-lint": "^0.3.0",
|
||||
"eslint-plugin-import": "^2.27.5",
|
||||
"eslint-plugin-jest": "^27.2.1",
|
||||
"eslint-plugin-n": "^15.7.0",
|
||||
|
||||
44
dlt-connector/src/data/Account.factory.ts
Normal file
44
dlt-connector/src/data/Account.factory.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import { KeyManager } from '@/controller/KeyManager'
|
||||
import { KeyPair } from '@/data/KeyPair'
|
||||
import { AddressType } from '@/data/proto/3_3/enum/AddressType'
|
||||
import { hardenDerivationIndex } from '@/utils/derivationHelper'
|
||||
import { Account } from '@entity/Account'
|
||||
import Decimal from 'decimal.js-light'
|
||||
|
||||
const GMW_ACCOUNT_DERIVATION_INDEX = 1
|
||||
const AUF_ACCOUNT_DERIVATION_INDEX = 2
|
||||
|
||||
export class AccountFactory {
|
||||
public static createAccount(
|
||||
keyPair: KeyPair,
|
||||
createdAt: Date,
|
||||
derivationIndex: number,
|
||||
type: AddressType,
|
||||
): Account {
|
||||
const account = Account.create()
|
||||
account.derivationIndex = derivationIndex
|
||||
account.derive2Pubkey = KeyManager.getInstance().derive([derivationIndex], keyPair).publicKey
|
||||
account.type = type.valueOf()
|
||||
account.createdAt = createdAt
|
||||
account.balance = new Decimal(0)
|
||||
return account
|
||||
}
|
||||
|
||||
public static createGmwAccount(keyPair: KeyPair, createdAt: Date): Account {
|
||||
return AccountFactory.createAccount(
|
||||
keyPair,
|
||||
createdAt,
|
||||
hardenDerivationIndex(GMW_ACCOUNT_DERIVATION_INDEX),
|
||||
AddressType.COMMUNITY_GMW,
|
||||
)
|
||||
}
|
||||
|
||||
public static createAufAccount(keyPair: KeyPair, createdAt: Date): Account {
|
||||
return AccountFactory.createAccount(
|
||||
keyPair,
|
||||
createdAt,
|
||||
hardenDerivationIndex(AUF_ACCOUNT_DERIVATION_INDEX),
|
||||
AddressType.COMMUNITY_AUF,
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -1,42 +0,0 @@
|
||||
import { KeyManager } from '@/controller/KeyManager'
|
||||
import { KeyPair } from '@/data/KeyPair'
|
||||
import { AddressType } from '@/data/proto/3_3/enum/AddressType'
|
||||
import { hardenDerivationIndex } from '@/utils/derivationHelper'
|
||||
import { Account } from '@entity/Account'
|
||||
import Decimal from 'decimal.js-light'
|
||||
|
||||
const GMW_ACCOUNT_DERIVATION_INDEX = 1
|
||||
const AUF_ACCOUNT_DERIVATION_INDEX = 2
|
||||
|
||||
export const createAccount = (
|
||||
keyPair: KeyPair,
|
||||
createdAt: Date,
|
||||
derivationIndex: number,
|
||||
type: AddressType,
|
||||
): Account => {
|
||||
const account = Account.create()
|
||||
account.derivationIndex = derivationIndex
|
||||
account.derive2Pubkey = KeyManager.getInstance().derive([derivationIndex], keyPair).publicKey
|
||||
account.type = type.valueOf()
|
||||
account.createdAt = createdAt
|
||||
account.balance = new Decimal(0)
|
||||
return account
|
||||
}
|
||||
|
||||
export const createGmwAccount = (keyPair: KeyPair, createdAt: Date): Account => {
|
||||
return createAccount(
|
||||
keyPair,
|
||||
createdAt,
|
||||
hardenDerivationIndex(GMW_ACCOUNT_DERIVATION_INDEX),
|
||||
AddressType.COMMUNITY_GMW,
|
||||
)
|
||||
}
|
||||
|
||||
export const createAufAccount = (keyPair: KeyPair, createdAt: Date): Account => {
|
||||
return createAccount(
|
||||
keyPair,
|
||||
createdAt,
|
||||
hardenDerivationIndex(AUF_ACCOUNT_DERIVATION_INDEX),
|
||||
AddressType.COMMUNITY_AUF,
|
||||
)
|
||||
}
|
||||
@ -1,31 +0,0 @@
|
||||
import { KeyManager } from '@/controller/KeyManager'
|
||||
import { CommunityDraft } from '@/graphql/input/CommunityDraft'
|
||||
import { iotaTopicFromCommunityUUID } from '@/utils/typeConverter'
|
||||
import { Community } from '@entity/Community'
|
||||
import { createAufAccount, createGmwAccount } from './account.factory'
|
||||
|
||||
export const createCommunity = (communityDraft: CommunityDraft, topic?: string): Community => {
|
||||
const communityEntity = Community.create()
|
||||
communityEntity.iotaTopic = topic ?? iotaTopicFromCommunityUUID(communityDraft.uuid)
|
||||
communityEntity.createdAt = new Date(communityDraft.createdAt)
|
||||
communityEntity.foreign = communityDraft.foreign
|
||||
return communityEntity
|
||||
}
|
||||
|
||||
export const createHomeCommunity = (communityDraft: CommunityDraft, topic?: string): Community => {
|
||||
// create community entity
|
||||
const community = createCommunity(communityDraft, topic)
|
||||
|
||||
// generate key pair for signing transactions and deriving all keys for community
|
||||
const keyPair = KeyManager.generateKeyPair()
|
||||
community.rootPubkey = keyPair.publicKey
|
||||
community.rootPrivkey = keyPair.privateKey
|
||||
community.rootChaincode = keyPair.chainCode
|
||||
// we should only have one home community per server
|
||||
KeyManager.getInstance().setHomeCommunityKeyPair(keyPair)
|
||||
|
||||
// create auf account and gmw account
|
||||
community.aufAccount = createAufAccount(keyPair, community.createdAt)
|
||||
community.gmwAccount = createGmwAccount(keyPair, community.createdAt)
|
||||
return community
|
||||
}
|
||||
@ -11,7 +11,7 @@ import { CommunityArg } from '@arg/CommunityArg'
|
||||
import { LogError } from '@/server/LogError'
|
||||
import { logger } from '@/server/logger'
|
||||
import { CommunityRepository } from '@/data/Community.repository'
|
||||
import { addCommunity } from '@/interactions/backendToDb/community/community.context'
|
||||
import { AddCommunityContext } from '@/interactions/backendToDb/community/AddCommunity.context'
|
||||
|
||||
@Resolver()
|
||||
export class CommunityResolver {
|
||||
@ -54,6 +54,20 @@ export class CommunityResolver {
|
||||
new TransactionError(TransactionErrorType.ALREADY_EXIST, 'community already exist!'),
|
||||
)
|
||||
}
|
||||
return await addCommunity(communityDraft, topic)
|
||||
// prepare context for interaction
|
||||
// shouldn't throw at all
|
||||
// TODO: write tests to make sure that it doesn't throw
|
||||
const addCommunityContext = new AddCommunityContext(communityDraft, topic)
|
||||
try {
|
||||
// actually run interaction, create community, accounts for foreign community and transactionRecipe
|
||||
await addCommunityContext.run()
|
||||
return new TransactionResult()
|
||||
} catch (error) {
|
||||
if (error instanceof TransactionError) {
|
||||
return new TransactionResult(error)
|
||||
} else {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
import { CommunityDraft } from '@/graphql/input/CommunityDraft'
|
||||
import { ForeignCommunityRole } from './ForeignCommunity.role'
|
||||
import { HomeCommunityRole } from './HomeCommunity.role'
|
||||
import { iotaTopicFromCommunityUUID } from '@/utils/typeConverter'
|
||||
import { CommunityRole } from './Community.role'
|
||||
|
||||
/**
|
||||
* @DCI-Context
|
||||
* Context for adding community to DB
|
||||
* using roles to distinct between foreign and home communities
|
||||
*/
|
||||
export class AddCommunityContext {
|
||||
private communityRole: CommunityRole
|
||||
private iotaTopic: string
|
||||
public constructor(private communityDraft: CommunityDraft, iotaTopic?: string) {
|
||||
if (!iotaTopic) {
|
||||
this.iotaTopic = iotaTopicFromCommunityUUID(this.communityDraft.uuid)
|
||||
} else {
|
||||
this.iotaTopic = iotaTopic
|
||||
}
|
||||
this.communityRole = communityDraft.foreign
|
||||
? new ForeignCommunityRole()
|
||||
: new HomeCommunityRole()
|
||||
}
|
||||
|
||||
public async run(): Promise<void> {
|
||||
this.communityRole.create(this.communityDraft, this.iotaTopic)
|
||||
await this.communityRole.store()
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,27 @@
|
||||
import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType'
|
||||
import { CommunityDraft } from '@/graphql/input/CommunityDraft'
|
||||
import { TransactionError } from '@/graphql/model/TransactionError'
|
||||
import { logger } from '@/server/logger'
|
||||
import { Community } from '@entity/Community'
|
||||
|
||||
export abstract class CommunityRole {
|
||||
abstract addCommunity(communityDraft: CommunityDraft, topic: string): Promise<Community>
|
||||
protected self: Community
|
||||
public constructor() {
|
||||
this.self = Community.create()
|
||||
}
|
||||
|
||||
public create(communityDraft: CommunityDraft, topic: string): void {
|
||||
this.self.iotaTopic = topic
|
||||
this.self.createdAt = new Date(communityDraft.createdAt)
|
||||
this.self.foreign = communityDraft.foreign
|
||||
}
|
||||
|
||||
public store(): Promise<Community> {
|
||||
try {
|
||||
return this.self.save()
|
||||
} catch (error) {
|
||||
logger.error('error saving new community into db: %s', error)
|
||||
throw new TransactionError(TransactionErrorType.DB_ERROR, 'error saving community into db')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,19 +1,4 @@
|
||||
import { CommunityDraft } from '@/graphql/input/CommunityDraft'
|
||||
import { Community } from '@entity/Community'
|
||||
import { CommunityRole } from './Community.role'
|
||||
import { logger } from '@/server/logger'
|
||||
import { TransactionError } from '@/graphql/model/TransactionError'
|
||||
import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType'
|
||||
import { createCommunity } from '@/data/community.factory'
|
||||
|
||||
export class ForeignCommunityRole extends CommunityRole {
|
||||
addCommunity(communityDraft: CommunityDraft, topic: string): Promise<Community> {
|
||||
const community = createCommunity(communityDraft, topic)
|
||||
try {
|
||||
return community.save()
|
||||
} catch (error) {
|
||||
logger.error('error saving new foreign community into db: %s', error)
|
||||
throw new TransactionError(TransactionErrorType.DB_ERROR, 'error saving community into db')
|
||||
}
|
||||
}
|
||||
}
|
||||
// same as base class
|
||||
export class ForeignCommunityRole extends CommunityRole {}
|
||||
|
||||
@ -1,28 +1,47 @@
|
||||
import { CommunityDraft } from '@/graphql/input/CommunityDraft'
|
||||
import { Community } from '@entity/Community'
|
||||
import { CommunityRole } from './Community.role'
|
||||
import { getTransaction } from '@/client/GradidoNode'
|
||||
import { timestampSecondsToDate } from '@/utils/typeConverter'
|
||||
import { createHomeCommunity } from '@/data/community.factory'
|
||||
import { createCommunityRootTransactionRecipe } from '../transaction/transaction.context'
|
||||
import { QueryRunner } from 'typeorm'
|
||||
import { Transaction } from '@entity/Transaction'
|
||||
import { KeyManager } from '@/controller/KeyManager'
|
||||
import { AccountFactory } from '@/data/Account.factory'
|
||||
import { CreateTransactionRecipeContext } from '../transaction/CreateTransationRecipe.context'
|
||||
|
||||
export class HomeCommunityRole extends CommunityRole {
|
||||
private transactionRecipe: Transaction
|
||||
|
||||
public create(communityDraft: CommunityDraft, topic: string): void {
|
||||
super.create(communityDraft, topic)
|
||||
// generate key pair for signing transactions and deriving all keys for community
|
||||
const keyPair = KeyManager.generateKeyPair()
|
||||
this.self.rootPubkey = keyPair.publicKey
|
||||
this.self.rootPrivkey = keyPair.privateKey
|
||||
this.self.rootChaincode = keyPair.chainCode
|
||||
// we should only have one home community per server
|
||||
KeyManager.getInstance().setHomeCommunityKeyPair(keyPair)
|
||||
|
||||
// create auf account and gmw account
|
||||
this.self.aufAccount = AccountFactory.createAufAccount(keyPair, this.self.createdAt)
|
||||
this.self.gmwAccount = AccountFactory.createGmwAccount(keyPair, this.self.createdAt)
|
||||
|
||||
const transactionRecipeContext = new CreateTransactionRecipeContext(communityDraft)
|
||||
transactionRecipeContext.setCommunity(this.self)
|
||||
transactionRecipeContext.run()
|
||||
this.transactionRecipe = transactionRecipeContext.getTransactionRecipe()
|
||||
}
|
||||
|
||||
public store(): Promise<Community> {
|
||||
|
||||
}
|
||||
|
||||
public async addCommunity(communityDraft: CommunityDraft, topic: string): Promise<Community> {
|
||||
const community = createHomeCommunity(communityDraft, topic)
|
||||
|
||||
// check if a CommunityRoot Transaction exist already on iota blockchain
|
||||
const existingCommunityRootTransaction = await getTransaction(1, community.iotaTopic)
|
||||
if (existingCommunityRootTransaction) {
|
||||
community.confirmedAt = timestampSecondsToDate(existingCommunityRootTransaction.confirmedAt)
|
||||
return community.save()
|
||||
} else {
|
||||
createCommunityRootTransactionRecipe(communityDraft, community).storeAsTransaction(
|
||||
async (queryRunner: QueryRunner): Promise<void> => {
|
||||
await queryRunner.manager.save(community)
|
||||
},
|
||||
)
|
||||
}
|
||||
createCommunityRootTransactionRecipe(communityDraft, community).storeAsTransaction(
|
||||
async (queryRunner: QueryRunner): Promise<void> => {
|
||||
await queryRunner.manager.save(community)
|
||||
},
|
||||
)
|
||||
return community.save()
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,30 +0,0 @@
|
||||
import { CommunityDraft } from '@/graphql/input/CommunityDraft'
|
||||
import { TransactionResult } from '@/graphql/model/TransactionResult'
|
||||
import { ForeignCommunityRole } from './ForeignCommunity.role'
|
||||
import { HomeCommunityRole } from './HomeCommunity.role'
|
||||
import { TransactionError } from '@/graphql/model/TransactionError'
|
||||
import { TransactionsManager } from '@/controller/TransactionsManager'
|
||||
import { iotaTopicFromCommunityUUID } from '@/utils/typeConverter'
|
||||
|
||||
export const addCommunity = async (
|
||||
communityDraft: CommunityDraft,
|
||||
iotaTopic?: string,
|
||||
): Promise<TransactionResult> => {
|
||||
const communityRole = communityDraft.foreign
|
||||
? new ForeignCommunityRole()
|
||||
: new HomeCommunityRole()
|
||||
try {
|
||||
if (!iotaTopic) {
|
||||
iotaTopic = iotaTopicFromCommunityUUID(communityDraft.uuid)
|
||||
}
|
||||
await communityRole.addCommunity(communityDraft, iotaTopic)
|
||||
await TransactionsManager.getInstance().addTopic(iotaTopic)
|
||||
return new TransactionResult()
|
||||
} catch (error) {
|
||||
if (error instanceof TransactionError) {
|
||||
return new TransactionResult(error)
|
||||
} else {
|
||||
throw error
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6,7 +6,7 @@ import { KeyPair } from '@/data/KeyPair'
|
||||
import { sign } from '@/utils/cryptoHelper'
|
||||
|
||||
export class CommunityRootTransactionRole extends TransactionRecipeRole {
|
||||
public createFromCommunityDraft(
|
||||
public createFromCommunityRoot(
|
||||
communityDraft: CommunityDraft,
|
||||
community: Community,
|
||||
): CommunityRootTransactionRole {
|
||||
|
||||
@ -0,0 +1,51 @@
|
||||
import { CommunityDraft } from '@/graphql/input/CommunityDraft'
|
||||
import { Community } from '@entity/Community'
|
||||
import { TransactionRecipeRole } from './TransactionRecipe.role'
|
||||
import { CommunityRootTransactionRole } from './CommunityRootTransaction.role'
|
||||
import { TransactionDraft } from '@/graphql/input/TransactionDraft'
|
||||
import { Transaction } from '@entity/Transaction'
|
||||
import { TransactionError } from '@/graphql/model/TransactionError'
|
||||
import { TransactionErrorType } from '@/graphql/enum/TransactionErrorType'
|
||||
|
||||
/**
|
||||
* @DCI-Context
|
||||
* Context for create and add Transaction Recipe to DB
|
||||
*/
|
||||
|
||||
export class CreateTransactionRecipeContext {
|
||||
private transactionRecipeRole: TransactionRecipeRole
|
||||
private community?: Community
|
||||
public constructor(private draft: CommunityDraft | TransactionDraft) {
|
||||
if (draft instanceof CommunityDraft) {
|
||||
this.transactionRecipeRole = new CommunityRootTransactionRole()
|
||||
} else if (draft instanceof TransactionDraft) {
|
||||
this.transactionRecipeRole = new TransactionRecipeRole()
|
||||
}
|
||||
}
|
||||
|
||||
public setCommunity(community: Community) {
|
||||
this.community = community
|
||||
}
|
||||
|
||||
public getCommunity() {
|
||||
return this.community
|
||||
}
|
||||
|
||||
public getTransactionRecipe(): Transaction {
|
||||
return this.transactionRecipeRole.getTransaction()
|
||||
}
|
||||
|
||||
public run(): void {
|
||||
if (this.draft instanceof TransactionDraft) {
|
||||
this.transactionRecipeRole = new TransactionRecipeRole().create(this.draft)
|
||||
} else if (this.draft instanceof CommunityDraft) {
|
||||
if (!this.community) {
|
||||
throw new TransactionError(TransactionErrorType.MISSING_PARAMETER, 'community was not set')
|
||||
}
|
||||
this.transactionRecipeRole = new CommunityRootTransactionRole().createFromCommunityRoot(
|
||||
this.draft,
|
||||
this.community,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -14,10 +14,14 @@ export class TransactionRecipeRole {
|
||||
this.transactionBuilder = new TransactionBuilder()
|
||||
}
|
||||
|
||||
public createFromTransactionDraft(transactionDraft: TransactionDraft): TransactionRecipeRole {
|
||||
public create(transactionDraft: TransactionDraft): TransactionRecipeRole {
|
||||
return this
|
||||
}
|
||||
|
||||
public getTransaction(): Transaction {
|
||||
return this.transactionBuilder.getTransaction()
|
||||
}
|
||||
|
||||
public async storeAsTransaction(
|
||||
transactionFunction: (queryRunner: QueryRunner) => Promise<void>,
|
||||
): Promise<TransactionResult> {
|
||||
|
||||
@ -1,20 +0,0 @@
|
||||
import { CommunityDraft } from '@/graphql/input/CommunityDraft'
|
||||
import { Community } from '@entity/Community'
|
||||
import { TransactionRecipeRole } from './TransactionRecipe.role'
|
||||
import { CommunityRootTransactionRole } from './CommunityRootTransaction.role'
|
||||
import { TransactionDraft } from '@/graphql/input/TransactionDraft'
|
||||
|
||||
export const createCommunityRootTransactionRecipe = (
|
||||
communityDraft: CommunityDraft,
|
||||
community: Community,
|
||||
): TransactionRecipeRole => {
|
||||
const communityRootTransactionRole = new CommunityRootTransactionRole()
|
||||
return communityRootTransactionRole.createFromCommunityDraft(communityDraft, community)
|
||||
}
|
||||
|
||||
export const createTransactionRecipe = (
|
||||
transactionDraft: TransactionDraft,
|
||||
): TransactionRecipeRole => {
|
||||
const transactionRecipeRole = new TransactionRecipeRole()
|
||||
return transactionRecipeRole.createFromTransactionDraft(transactionDraft)
|
||||
}
|
||||
@ -2586,6 +2586,11 @@ eslint-module-utils@^2.7.4, eslint-module-utils@^2.8.0:
|
||||
dependencies:
|
||||
debug "^3.2.7"
|
||||
|
||||
eslint-plugin-dci-lint@^0.3.0:
|
||||
version "0.3.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-dci-lint/-/eslint-plugin-dci-lint-0.3.0.tgz#dcd73c50505b589b415017cdb72716f98e9495c3"
|
||||
integrity sha512-BhgrwJ5k3eMN41NwCZ/tYQGDTMOrHXpH8XOfRZrGtPqmlnOZCVGWow+KyZMz0/wOFVpXx/q9B0y7R7qtU7lnqg==
|
||||
|
||||
eslint-plugin-es@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/eslint-plugin-es/-/eslint-plugin-es-4.1.0.tgz#f0822f0c18a535a97c3e714e89f88586a7641ec9"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user