From c6d1852c647edf9ae8f2915bd406e0a0b686d305 Mon Sep 17 00:00:00 2001 From: William Calderipe Date: Tue, 20 Feb 2024 15:31:16 +0100 Subject: [PATCH 1/9] Entity storage module --- .../__test__/e2e/entity-storage.spec.ts | 82 ++++++++++ .../core/repository/entity.repository.ts | 8 + .../storage/core/service/entity.service.ts | 15 ++ .../rest/controller/storage.controller.ts | 23 +++ .../http/rest/dto/address-book-account.dto.ts | 23 +++ .../storage/http/rest/dto/credential.dto.ts | 24 +++ .../src/storage/http/rest/dto/entities.dto.ts | 68 ++++++++ .../src/storage/http/rest/dto/token.dto.ts | 33 ++++ .../rest/dto/update-entities-request.dto.ts | 10 ++ .../http/rest/dto/user-group-member.dto.ts | 18 +++ .../storage/http/rest/dto/user-group.dto.ts | 13 ++ .../storage/http/rest/dto/user-wallet.dto.ts | 18 +++ .../src/storage/http/rest/dto/user.dto.ts | 18 +++ .../http/rest/dto/wallet-group-member.dto.ts | 18 +++ .../storage/http/rest/dto/wallet-group.dto.ts | 11 ++ .../src/storage/http/rest/dto/wallet.dto.ts | 30 ++++ .../repository/in-memory-entity.repository.ts | 20 +++ apps/armory/src/storage/storage.module.ts | 26 +++ .../src/lib/dev.fixture.ts | 150 ++++++++++++------ .../src/lib/type/entity.type.ts | 16 +- 20 files changed, 567 insertions(+), 57 deletions(-) create mode 100644 apps/armory/src/storage/__test__/e2e/entity-storage.spec.ts create mode 100644 apps/armory/src/storage/core/repository/entity.repository.ts create mode 100644 apps/armory/src/storage/core/service/entity.service.ts create mode 100644 apps/armory/src/storage/http/rest/controller/storage.controller.ts create mode 100644 apps/armory/src/storage/http/rest/dto/address-book-account.dto.ts create mode 100644 apps/armory/src/storage/http/rest/dto/credential.dto.ts create mode 100644 apps/armory/src/storage/http/rest/dto/entities.dto.ts create mode 100644 apps/armory/src/storage/http/rest/dto/token.dto.ts create mode 100644 apps/armory/src/storage/http/rest/dto/update-entities-request.dto.ts create mode 100644 apps/armory/src/storage/http/rest/dto/user-group-member.dto.ts create mode 100644 apps/armory/src/storage/http/rest/dto/user-group.dto.ts create mode 100644 apps/armory/src/storage/http/rest/dto/user-wallet.dto.ts create mode 100644 apps/armory/src/storage/http/rest/dto/user.dto.ts create mode 100644 apps/armory/src/storage/http/rest/dto/wallet-group-member.dto.ts create mode 100644 apps/armory/src/storage/http/rest/dto/wallet-group.dto.ts create mode 100644 apps/armory/src/storage/http/rest/dto/wallet.dto.ts create mode 100644 apps/armory/src/storage/persistence/repository/in-memory-entity.repository.ts create mode 100644 apps/armory/src/storage/storage.module.ts diff --git a/apps/armory/src/storage/__test__/e2e/entity-storage.spec.ts b/apps/armory/src/storage/__test__/e2e/entity-storage.spec.ts new file mode 100644 index 000000000..fb6190c09 --- /dev/null +++ b/apps/armory/src/storage/__test__/e2e/entity-storage.spec.ts @@ -0,0 +1,82 @@ +import { FIXTURE, OrganizationEntity } from '@narval/policy-engine-shared' +import { HttpStatus, INestApplication } from '@nestjs/common' +import { Test, TestingModule } from '@nestjs/testing' +import request from 'supertest' +import { REQUEST_HEADER_ORG_ID } from '../../../armory.constant' +// import { TestPrismaService } from '../../../shared/module/persistence/service/test-prisma.service' +import { EntityRepository } from '../../core/repository/entity.repository' +import { StorageModule } from '../../storage.module' + +const ENDPOINT = '/storage/entities' + +describe('Entity Storage', () => { + let app: INestApplication + let module: TestingModule + let entityRepository: EntityRepository + // let testPrismaService: TestPrismaService + + const organization: OrganizationEntity = { + uid: 'ac1374c2-fd62-4b6e-bd49-a4afcdcb91cc' + } + + beforeAll(async () => { + module = await Test.createTestingModule({ + imports: [StorageModule] + }).compile() + + // testPrismaService = module.get(TestPrismaService) + + entityRepository = module.get(EntityRepository) + + app = module.createNestApplication() + + await app.init() + }) + + afterAll(async () => { + // await testPrismaService.truncateAll() + await module.close() + await app.close() + }) + + beforeEach(async () => {}) + + afterEach(async () => { + // await testPrismaService.truncateAll() + }) + + describe(`PUT ${ENDPOINT}`, () => { + it('puts a new entities set for the organization', async () => { + const payload = { + entities: FIXTURE.ENTITIES + } + + const { status, body } = await request(app.getHttpServer()) + .put(ENDPOINT) + .set(REQUEST_HEADER_ORG_ID, organization.uid) + .send(payload) + + console.log(payload) + + expect(body).toEqual(payload) + expect(status).toEqual(HttpStatus.OK) + }) + }) + + describe(`GET ${ENDPOINT}`, () => { + it('responds with the organization entities', async () => { + await entityRepository.put(organization.uid, FIXTURE.ENTITIES) + + console.log(entityRepository) + + const { status, body } = await request(app.getHttpServer()) + .get(ENDPOINT) + .set(REQUEST_HEADER_ORG_ID, organization.uid) + + expect(body).toEqual({ + entities: FIXTURE.ENTITIES + }) + expect(status).toEqual(HttpStatus.OK) + }) + }) +}) diff --git a/apps/armory/src/storage/core/repository/entity.repository.ts b/apps/armory/src/storage/core/repository/entity.repository.ts new file mode 100644 index 000000000..4ae599bab --- /dev/null +++ b/apps/armory/src/storage/core/repository/entity.repository.ts @@ -0,0 +1,8 @@ +import { Entities } from '@narval/policy-engine-shared' + +export const EntityRepository = Symbol('Storage:EntityRepository') + +export interface EntityRepository { + put(orgId: string, entities: Entities): Promise + findByOrgId(orgId: string): Promise +} diff --git a/apps/armory/src/storage/core/service/entity.service.ts b/apps/armory/src/storage/core/service/entity.service.ts new file mode 100644 index 000000000..a1f8a161d --- /dev/null +++ b/apps/armory/src/storage/core/service/entity.service.ts @@ -0,0 +1,15 @@ +import { Entities } from '@narval/policy-engine-shared' +import { Inject } from '@nestjs/common' +import { EntityRepository } from '../repository/entity.repository' + +export class EntityService { + constructor(@Inject(EntityRepository) private entityRepository: EntityRepository) {} + + put(orgId: string, data: { entities: Entities }): Promise { + return this.entityRepository.put(orgId, data.entities) + } + + findByOrgId(orgId: string): Promise { + return this.entityRepository.findByOrgId(orgId) + } +} diff --git a/apps/armory/src/storage/http/rest/controller/storage.controller.ts b/apps/armory/src/storage/http/rest/controller/storage.controller.ts new file mode 100644 index 000000000..9b8540c98 --- /dev/null +++ b/apps/armory/src/storage/http/rest/controller/storage.controller.ts @@ -0,0 +1,23 @@ +import { Body, Controller, Get, Put } from '@nestjs/common' +import { OrgId } from '../../../../shared/decorator/org-id.decorator' +import { EntityService } from '../../../core/service/entity.service' +import { UpdateEntitiesRequestDto } from '../dto/update-entities-request.dto' + +@Controller('/storage') +export class StorageController { + constructor(private entityService: EntityService) {} + + @Put('/entities') + async putEntities(@OrgId() orgId: string, @Body() body: UpdateEntitiesRequestDto) { + const entities = await this.entityService.put(orgId, body) + + return { entities } + } + + @Get('/entities') + async getEntities(@OrgId() orgId: string) { + const entities = await this.entityService.findByOrgId(orgId) + + return { entities } + } +} diff --git a/apps/armory/src/storage/http/rest/dto/address-book-account.dto.ts b/apps/armory/src/storage/http/rest/dto/address-book-account.dto.ts new file mode 100644 index 000000000..95fe6b4a1 --- /dev/null +++ b/apps/armory/src/storage/http/rest/dto/address-book-account.dto.ts @@ -0,0 +1,23 @@ +import { AccountClassification, Address } from '@narval/policy-engine-shared' +import { ApiProperty } from '@nestjs/swagger' +import { IsEnum, IsEthereumAddress, IsNotEmpty, IsNumber, IsString } from 'class-validator' + +export class AddressBookAccountDto { + @IsString() + @IsNotEmpty() + uid: string + + @IsEnum(AccountClassification) + @ApiProperty({ enum: AccountClassification }) + classification: AccountClassification + + @IsEthereumAddress() + @ApiProperty({ + format: 'address', + type: String + }) + address: Address + + @IsNumber() + chainId: number +} diff --git a/apps/armory/src/storage/http/rest/dto/credential.dto.ts b/apps/armory/src/storage/http/rest/dto/credential.dto.ts new file mode 100644 index 000000000..2cc576a39 --- /dev/null +++ b/apps/armory/src/storage/http/rest/dto/credential.dto.ts @@ -0,0 +1,24 @@ +import { Alg } from '@narval/policy-engine-shared' +import { ApiProperty } from '@nestjs/swagger' +import { IsEnum, IsNotEmpty, IsString } from 'class-validator' + +export class CredentialDto { + @IsString() + @IsNotEmpty() + @ApiProperty() + uid: string + + @IsString() + @IsNotEmpty() + @ApiProperty() + pubKey: string + + @IsEnum(Alg) + @ApiProperty({ enum: Alg }) + alg: Alg + + @IsString() + @IsNotEmpty() + @ApiProperty() + userId: string +} diff --git a/apps/armory/src/storage/http/rest/dto/entities.dto.ts b/apps/armory/src/storage/http/rest/dto/entities.dto.ts new file mode 100644 index 000000000..de8d42a9a --- /dev/null +++ b/apps/armory/src/storage/http/rest/dto/entities.dto.ts @@ -0,0 +1,68 @@ +import { Type } from 'class-transformer' +import { IsDefined, ValidateNested } from 'class-validator' +import { AddressBookAccountDto } from './address-book-account.dto' +import { CredentialDto } from './credential.dto' +import { TokenDto } from './token.dto' +import { UserGroupMemberDto } from './user-group-member.dto' +import { UserGroupDto } from './user-group.dto' +import { UserWalletDto } from './user-wallet.dto' +import { UserDto } from './user.dto' +import { WalletGroupMemberDto } from './wallet-group-member.dto' +import { WalletGroupDto } from './wallet-group.dto' +import { WalletDto } from './wallet.dto' + +export class EntitiesDto { + @IsDefined() + @Type(() => AddressBookAccountDto) + @ValidateNested({ each: true }) + addressBook: AddressBookAccountDto[] + + @IsDefined() + @Type(() => CredentialDto) + @ValidateNested({ each: true }) + credentials: CredentialDto[] + + @IsDefined() + @Type(() => TokenDto) + @ValidateNested({ each: true }) + tokens: TokenDto[] + + @IsDefined() + @Type(() => UserDto) + @ValidateNested({ each: true }) + users: UserDto[] + + @IsDefined() + @Type(() => UserGroupDto) + @ValidateNested({ each: true }) + userGroups: UserGroupDto[] + + @IsDefined() + @Type(() => UserGroupMemberDto) + @ValidateNested({ each: true }) + userGroupMembers: UserGroupMemberDto[] + + @IsDefined() + @Type(() => UserWalletDto) + @ValidateNested({ each: true }) + userWallets: UserWalletDto[] + + @IsDefined() + @Type(() => WalletDto) + @ValidateNested({ each: true }) + wallets: WalletDto[] + + @IsDefined() + @Type(() => WalletGroupDto) + @ValidateNested({ each: true }) + walletGroups: WalletGroupDto[] + + @IsDefined() + @Type(() => WalletGroupMemberDto) + @ValidateNested({ each: true }) + walletGroupMembers: WalletGroupMemberDto[] + + constructor(partial: Partial) { + Object.assign(this, partial) + } +} diff --git a/apps/armory/src/storage/http/rest/dto/token.dto.ts b/apps/armory/src/storage/http/rest/dto/token.dto.ts new file mode 100644 index 000000000..3ed746747 --- /dev/null +++ b/apps/armory/src/storage/http/rest/dto/token.dto.ts @@ -0,0 +1,33 @@ +import { Address } from '@narval/policy-engine-shared' +import { ApiProperty } from '@nestjs/swagger' +import { IsDefined, IsEthereumAddress, IsNotEmpty, IsNumber, IsString, Min } from 'class-validator' + +export class TokenDto { + @IsString() + @IsNotEmpty() + uid: string + + @IsEthereumAddress() + @ApiProperty({ + format: 'address', + type: String + }) + address: Address + + @IsNumber() + @IsDefined() + @Min(1) + chainId: number + + @IsString() + @IsNotEmpty() + symbol: string + + @IsNumber() + @IsDefined() + decimals: number + + constructor(partial: Partial) { + Object.assign(this, partial) + } +} diff --git a/apps/armory/src/storage/http/rest/dto/update-entities-request.dto.ts b/apps/armory/src/storage/http/rest/dto/update-entities-request.dto.ts new file mode 100644 index 000000000..e575adef5 --- /dev/null +++ b/apps/armory/src/storage/http/rest/dto/update-entities-request.dto.ts @@ -0,0 +1,10 @@ +import { Type } from 'class-transformer' +import { IsDefined, ValidateNested } from 'class-validator' +import { EntitiesDto } from './entities.dto' + +export class UpdateEntitiesRequestDto { + @IsDefined() + @Type(() => EntitiesDto) + @ValidateNested() + entities: EntitiesDto +} diff --git a/apps/armory/src/storage/http/rest/dto/user-group-member.dto.ts b/apps/armory/src/storage/http/rest/dto/user-group-member.dto.ts new file mode 100644 index 000000000..59d05a42a --- /dev/null +++ b/apps/armory/src/storage/http/rest/dto/user-group-member.dto.ts @@ -0,0 +1,18 @@ +import { ApiProperty } from '@nestjs/swagger' +import { IsNotEmpty, IsString } from 'class-validator' + +export class UserGroupMemberDto { + @IsString() + @IsNotEmpty() + @ApiProperty() + groupId: string + + @IsString() + @IsNotEmpty() + @ApiProperty() + userId: string + + constructor(partial: Partial) { + Object.assign(this, partial) + } +} diff --git a/apps/armory/src/storage/http/rest/dto/user-group.dto.ts b/apps/armory/src/storage/http/rest/dto/user-group.dto.ts new file mode 100644 index 000000000..819804edc --- /dev/null +++ b/apps/armory/src/storage/http/rest/dto/user-group.dto.ts @@ -0,0 +1,13 @@ +import { ApiProperty } from '@nestjs/swagger' +import { IsNotEmpty, IsString } from 'class-validator' + +export class UserGroupDto { + @IsString() + @IsNotEmpty() + @ApiProperty() + uid: string + + constructor(partial: Partial) { + Object.assign(this, partial) + } +} diff --git a/apps/armory/src/storage/http/rest/dto/user-wallet.dto.ts b/apps/armory/src/storage/http/rest/dto/user-wallet.dto.ts new file mode 100644 index 000000000..192ece581 --- /dev/null +++ b/apps/armory/src/storage/http/rest/dto/user-wallet.dto.ts @@ -0,0 +1,18 @@ +import { ApiProperty } from '@nestjs/swagger' +import { IsNotEmpty, IsString } from 'class-validator' + +export class UserWalletDto { + @IsString() + @IsNotEmpty() + @ApiProperty() + walletId: string + + @IsString() + @IsNotEmpty() + @ApiProperty() + userId: string + + constructor(partial: Partial) { + Object.assign(this, partial) + } +} diff --git a/apps/armory/src/storage/http/rest/dto/user.dto.ts b/apps/armory/src/storage/http/rest/dto/user.dto.ts new file mode 100644 index 000000000..830660892 --- /dev/null +++ b/apps/armory/src/storage/http/rest/dto/user.dto.ts @@ -0,0 +1,18 @@ +import { UserRole } from '@narval/policy-engine-shared' +import { ApiProperty } from '@nestjs/swagger' +import { IsEnum, IsNotEmpty, IsString } from 'class-validator' + +export class UserDto { + @IsString() + @IsNotEmpty() + @ApiProperty() + uid: string + + @IsEnum(UserRole) + @ApiProperty({ enum: UserRole }) + role: UserRole + + constructor(partial: Partial) { + Object.assign(this, partial) + } +} diff --git a/apps/armory/src/storage/http/rest/dto/wallet-group-member.dto.ts b/apps/armory/src/storage/http/rest/dto/wallet-group-member.dto.ts new file mode 100644 index 000000000..54c5f4fbb --- /dev/null +++ b/apps/armory/src/storage/http/rest/dto/wallet-group-member.dto.ts @@ -0,0 +1,18 @@ +import { ApiProperty } from '@nestjs/swagger' +import { IsNotEmpty, IsString } from 'class-validator' + +export class WalletGroupMemberDto { + @IsString() + @IsNotEmpty() + @ApiProperty() + groupId: string + + @IsString() + @IsNotEmpty() + @ApiProperty() + walletId: string + + constructor(partial: Partial) { + Object.assign(this, partial) + } +} diff --git a/apps/armory/src/storage/http/rest/dto/wallet-group.dto.ts b/apps/armory/src/storage/http/rest/dto/wallet-group.dto.ts new file mode 100644 index 000000000..08d779bae --- /dev/null +++ b/apps/armory/src/storage/http/rest/dto/wallet-group.dto.ts @@ -0,0 +1,11 @@ +import { IsNotEmpty, IsString } from 'class-validator' + +export class WalletGroupDto { + @IsString() + @IsNotEmpty() + uid: string + + constructor(partial: Partial) { + Object.assign(this, partial) + } +} diff --git a/apps/armory/src/storage/http/rest/dto/wallet.dto.ts b/apps/armory/src/storage/http/rest/dto/wallet.dto.ts new file mode 100644 index 000000000..9e8f2af01 --- /dev/null +++ b/apps/armory/src/storage/http/rest/dto/wallet.dto.ts @@ -0,0 +1,30 @@ +import { AccountType, Address } from '@narval/policy-engine-shared' +import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger' +import { IsEnum, IsEthereumAddress, IsNotEmpty, IsNumber, IsOptional, IsString } from 'class-validator' + +export class WalletDto { + @IsString() + @IsNotEmpty() + @ApiProperty() + uid: string + + @IsEnum(AccountType) + @ApiProperty({ enum: AccountType }) + accountType: AccountType + + @IsEthereumAddress() + @ApiProperty({ + type: String, + format: 'address' + }) + address: Address + + @IsNumber() + @IsOptional() + @ApiPropertyOptional() + chainId?: number + + constructor(partial: Partial) { + Object.assign(this, partial) + } +} diff --git a/apps/armory/src/storage/persistence/repository/in-memory-entity.repository.ts b/apps/armory/src/storage/persistence/repository/in-memory-entity.repository.ts new file mode 100644 index 000000000..d17abd85c --- /dev/null +++ b/apps/armory/src/storage/persistence/repository/in-memory-entity.repository.ts @@ -0,0 +1,20 @@ +import { Entities } from '@narval/policy-engine-shared' +import { Injectable } from '@nestjs/common' +import { EntityRepository } from '../../core/repository/entity.repository' + +@Injectable() +export class InMemoryEntityRepository implements EntityRepository { + private entities = new Map() + + async put(orgId: string, entities: Entities): Promise { + this.entities.set(orgId, entities) + + return entities + } + + async findByOrgId(orgId: string): Promise { + const entities = this.entities.get(orgId) + + return entities || null + } +} diff --git a/apps/armory/src/storage/storage.module.ts b/apps/armory/src/storage/storage.module.ts new file mode 100644 index 000000000..2fa8be906 --- /dev/null +++ b/apps/armory/src/storage/storage.module.ts @@ -0,0 +1,26 @@ +import { ClassSerializerInterceptor, Module, ValidationPipe } from '@nestjs/common' +import { APP_INTERCEPTOR, APP_PIPE } from '@nestjs/core' +import { EntityRepository } from './core/repository/entity.repository' +import { EntityService } from './core/service/entity.service' +import { StorageController } from './http/rest/controller/storage.controller' +import { InMemoryEntityRepository } from './persistence/repository/in-memory-entity.repository' + +@Module({ + controllers: [StorageController], + providers: [ + EntityService, + { + provide: EntityRepository, + useClass: InMemoryEntityRepository + }, + { + provide: APP_INTERCEPTOR, + useClass: ClassSerializerInterceptor + }, + { + provide: APP_PIPE, + useClass: ValidationPipe + } + ] +}) +export class StorageModule {} diff --git a/packages/policy-engine-shared/src/lib/dev.fixture.ts b/packages/policy-engine-shared/src/lib/dev.fixture.ts index 11481951b..055608c9c 100644 --- a/packages/policy-engine-shared/src/lib/dev.fixture.ts +++ b/packages/policy-engine-shared/src/lib/dev.fixture.ts @@ -11,20 +11,27 @@ import { TokenEntity, UserEntity, UserGroupEntity, + UserGroupMemberEntity, UserRole, + UserWalletEntity, WalletEntity, - WalletGroupEntity + WalletGroupEntity, + WalletGroupMemberEntity } from './type/entity.type' -const PERSONA = ['Root', 'Alice', 'Bob', 'Carol', 'Dave'] as const +const PERSONAS = ['Root', 'Alice', 'Bob', 'Carol', 'Dave'] as const +const GROUPS = ['Engineering', 'Treasury'] as const +const WALLETS = ['Engineering', 'Testing', 'Treasury', 'Operation'] as const -type Persona = (typeof PERSONA)[number] +type Personas = (typeof PERSONAS)[number] +type Groups = (typeof GROUPS)[number] +type Wallets = (typeof WALLETS)[number] export const ORGANIZATION: OrganizationEntity = { uid: '7d704a62-d15e-4382-a826-1eb41563043b' } -export const UNSAFE_PRIVATE_KEY: Record = { +export const UNSAFE_PRIVATE_KEY: Record = { // 0x000966c8bf232032cd23f9002c4513dfea2531be Root: '0x4d377dba5424a7c1545a3c7b0522592927d49d2600a66f12e07a3977bafd79ab', Alice: '0x454c9f13f6591f6482b17bdb6a671a7294500c7dd126111ce1643b03b6aeb354', @@ -33,7 +40,7 @@ export const UNSAFE_PRIVATE_KEY: Record = { Dave: '0x82a0cf4f0fdfd42d93ff328b73bfdbc9c8b4f95f5aedfae82059753fc08a180f' } -export const ACCOUNT: Record = { +export const ACCOUNT: Record = { Root: privateKeyToAccount(UNSAFE_PRIVATE_KEY.Root), Alice: privateKeyToAccount(UNSAFE_PRIVATE_KEY.Alice), Bob: privateKeyToAccount(UNSAFE_PRIVATE_KEY.Bob), @@ -41,30 +48,30 @@ export const ACCOUNT: Record = { Dave: privateKeyToAccount(UNSAFE_PRIVATE_KEY.Dave) } -export const USER: Record = { +export const USER: Record = { Root: { - uid: 'root:608bi1ef7-0efc-4a40-8739-0178a993b77c', + uid: 'test-root-user-uid', role: UserRole.ROOT }, Alice: { - uid: 'alice:0c6111fb-96ef-4177-8510-8cd994cc17ba', + uid: 'test-alice-user-uid', role: UserRole.ADMIN }, Bob: { - uid: 'bob:3761b384-b5d3-4d29-9ed8-4b615fa1bcb3', + uid: 'test-bob-user-uid', role: UserRole.ADMIN }, Carol: { - uid: 'carol:422dfe0b-0de1-44de-aaee-5262d6ebfb64', + uid: 'test-carol-user-uid', role: UserRole.MANAGER }, Dave: { - uid: 'dave:4e7f31ad-a8e9-4a07-a19b-91c6883d7adb', + uid: 'test-dave-user-uid', role: UserRole.MEMBER } } -export const CREDENTIAL: Record = { +export const CREDENTIAL: Record = { Root: { uid: sha256(ACCOUNT.Root.address).toLowerCase(), pubKey: ACCOUNT.Root.address, @@ -97,88 +104,130 @@ export const CREDENTIAL: Record = { } } -export const USER_GROUP: Record = { - engineering: { - uid: 'ug:4735e190-6985-4f58-a723-c1a3aeec8b8c', - users: [USER.Alice.uid, USER.Carol.uid] +export const USER_GROUP: Record = { + Engineering: { + uid: 'test-engineering-user-group-uid' }, - treasury: { - uid: 'ug:08319ee9-c4f1-458f-b88c-e501ac575957', - users: [USER.Bob.uid, USER.Dave.uid] + Treasury: { + uid: 'test-treasury-user-group-uid' } } -export const WALLET: Record = { - engineering1: { +export const USER_GROUP_MEMBER: UserGroupMemberEntity[] = [ + { + groupId: USER_GROUP.Engineering.uid, + userId: USER.Alice.uid + }, + { + groupId: USER_GROUP.Engineering.uid, + userId: USER.Carol.uid + }, + { + groupId: USER_GROUP.Treasury.uid, + userId: USER.Bob.uid + } +] + +export const WALLET: Record = { + Testing: { uid: 'eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e', address: '0xddcf208f219a6e6af072f2cfdc615b2c1805f98e', - accountType: AccountType.EOA, - assignees: [USER.Alice.uid] + accountType: AccountType.EOA }, - engineering2: { + Engineering: { uid: 'eip155:eoa:0x22228d0504d4f3363a5b7fda1f5fff1c7bca8ad4', address: '0x22228d0504d4f3363a5b7fda1f5fff1c7bca8ad4', accountType: AccountType.EOA }, - treasury: { + Treasury: { uid: 'eip155:eoa:0x90d03a8971a2faa19a9d7ffdcbca28fe826a289b', // Prod guild 58 - treasury wallet address: '0x90d03a8971a2faa19a9d7ffdcbca28fe826a289b', - accountType: AccountType.EOA, - assignees: [USER.Alice.uid] + accountType: AccountType.EOA }, - operations: { + Operation: { uid: 'eip155:eoa:0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4', address: '0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4', - accountType: AccountType.EOA, - assignees: [USER.Alice.uid] + accountType: AccountType.EOA } } -export const WALLET_GROUP: Record = { - engineering: { - uid: 'wg:9e60a686-ffbb-44fb-8bae-742fe1dedefb', - wallets: [WALLET.engineering1.uid, WALLET.engineering2.uid] +export const WALLET_GROUP: Record = { + Engineering: { + uid: 'test-engineering-wallet-group-uid' }, - treasury: { - uid: 'wg:df5db763-a3e0-4e19-848c-214e527e47cc', - wallets: [WALLET.treasury.uid] + Treasury: { + uid: 'test-treasury-wallet-group-uid' } } +export const WALLET_GROUP_MEMBER: WalletGroupMemberEntity[] = [ + { + groupId: WALLET_GROUP.Engineering.uid, + walletId: WALLET.Engineering.uid + }, + { + groupId: WALLET_GROUP.Engineering.uid, + walletId: WALLET.Testing.uid + }, + { + groupId: WALLET_GROUP.Treasury.uid, + walletId: WALLET.Treasury.uid + }, + { + groupId: WALLET_GROUP.Treasury.uid, + walletId: WALLET.Operation.uid + } +] + +export const USER_WALLET: UserWalletEntity[] = [ + { + walletId: WALLET.Operation.uid, + userId: USER.Alice.uid + }, + { + walletId: WALLET.Testing.uid, + userId: USER.Alice.uid + }, + { + walletId: WALLET.Treasury.uid, + userId: USER.Alice.uid + } +] + export const ADDRESS_BOOK: AddressBookAccountEntity[] = [ { - uid: `eip155:137:${WALLET.engineering1.address}`, - address: WALLET.engineering1.address, + uid: `eip155:137:${WALLET.Testing.address}`, + address: WALLET.Testing.address, chainId: 137, classification: AccountClassification.WALLET }, { - uid: `eip155:1:${WALLET.engineering1.address}`, - address: WALLET.engineering1.address, + uid: `eip155:1:${WALLET.Engineering.address}`, + address: WALLET.Engineering.address, chainId: 1, classification: AccountClassification.WALLET }, { - uid: `eip155:137:${WALLET.engineering2.address}`, - address: WALLET.engineering2.address, + uid: `eip155:137:${WALLET.Engineering.address}`, + address: WALLET.Treasury.address, chainId: 137, classification: AccountClassification.WALLET }, { - uid: `eip155:137:${WALLET.treasury.address}`, - address: WALLET.treasury.address, + uid: `eip155:137:${WALLET.Engineering.address}`, + address: WALLET.Engineering.address, chainId: 137, classification: AccountClassification.WALLET }, { - uid: `eip155:1:${WALLET.treasury.address}`, - address: WALLET.treasury.address, + uid: `eip155:1:${WALLET.Treasury.address}`, + address: WALLET.Treasury.address, chainId: 1, classification: AccountClassification.WALLET }, { - uid: `eip155:137:${WALLET.operations.address}`, - address: WALLET.operations.address, + uid: `eip155:137:${WALLET.Operation.address}`, + address: WALLET.Operation.address, chainId: 137, classification: AccountClassification.WALLET } @@ -207,6 +256,9 @@ export const ENTITIES: Entities = { tokens: Object.values(TOKEN), userGroups: Object.values(USER_GROUP), users: Object.values(USER), + userGroupMembers: USER_GROUP_MEMBER, + userWallets: USER_WALLET, walletGroups: Object.values(WALLET_GROUP), + walletGroupMembers: WALLET_GROUP_MEMBER, wallets: Object.values(WALLET) } diff --git a/packages/policy-engine-shared/src/lib/type/entity.type.ts b/packages/policy-engine-shared/src/lib/type/entity.type.ts index 64429a5ea..d26242597 100644 --- a/packages/policy-engine-shared/src/lib/type/entity.type.ts +++ b/packages/policy-engine-shared/src/lib/type/entity.type.ts @@ -26,11 +26,6 @@ export const AccountClassification = { export type AccountClassification = (typeof AccountClassification)[keyof typeof AccountClassification] -export type UserGroupMemberEntity = { - userId: string - groupId: string -} - export type CredentialEntity = { uid: string pubKey: string @@ -49,7 +44,6 @@ export type UserEntity = { export type UserGroupEntity = { uid: string - users: string[] } export type UserWalletEntity = { @@ -57,17 +51,20 @@ export type UserWalletEntity = { walletId: string } +export type UserGroupMemberEntity = { + userId: string + groupId: string +} + export type WalletEntity = { uid: string address: Address accountType: AccountType chainId?: number - assignees?: string[] } export type WalletGroupEntity = { uid: string - wallets: string[] } export type WalletGroupMemberEntity = { @@ -94,8 +91,11 @@ export type Entities = { addressBook: AddressBookAccountEntity[] credentials: CredentialEntity[] tokens: TokenEntity[] + userGroupMembers: UserGroupMemberEntity[] userGroups: UserGroupEntity[] + userWallets: UserWalletEntity[] users: UserEntity[] + walletGroupMembers: WalletGroupMemberEntity[] walletGroups: WalletGroupEntity[] wallets: WalletEntity[] } From 2983f6d711af4ec6d0888503a2804393452b5eb0 Mon Sep 17 00:00:00 2001 From: William Calderipe Date: Wed, 21 Feb 2024 17:37:09 +0100 Subject: [PATCH 2/9] Move core schemas to the shared package --- .../src/__test__/fixture/price.fixture.ts | 3 +- .../src/__test__/fixture/shared.fixture.ts | 4 +- .../fixture/transfer-tracking.fixture.ts | 2 +- .../schema/transaction-request.schema.ts | 3 +- apps/armory/src/shared/schema/caip.schema.ts | 44 --- packages/policy-engine-shared/src/index.ts | 2 + .../__test__/unit/entity.domain.spec.ts | 335 ++++++++++++++++++ .../src/lib/domain/entity.domain.ts | 154 ++++++++ .../src/lib}/schema/address.schema.ts | 2 +- .../src/lib}/schema/hex.schema.ts | 0 10 files changed, 496 insertions(+), 53 deletions(-) delete mode 100644 apps/armory/src/shared/schema/caip.schema.ts create mode 100644 packages/policy-engine-shared/src/lib/domain/__test__/unit/entity.domain.spec.ts create mode 100644 packages/policy-engine-shared/src/lib/domain/entity.domain.ts rename {apps/armory/src/shared => packages/policy-engine-shared/src/lib}/schema/address.schema.ts (87%) rename {apps/armory/src/shared => packages/policy-engine-shared/src/lib}/schema/hex.schema.ts (100%) diff --git a/apps/armory/src/__test__/fixture/price.fixture.ts b/apps/armory/src/__test__/fixture/price.fixture.ts index 012a4672b..df6db254a 100644 --- a/apps/armory/src/__test__/fixture/price.fixture.ts +++ b/apps/armory/src/__test__/fixture/price.fixture.ts @@ -1,11 +1,10 @@ -import { AssetType, Namespace, Prices } from '@narval/policy-engine-shared' +import { AssetType, Namespace, Prices, assetIdSchema } from '@narval/policy-engine-shared' import { sample } from 'lodash' import { times } from 'lodash/fp' import { z } from 'zod' import { Fixture, Generator } from 'zod-fixture' import { CHAINS, FIAT_ID_USD } from '../../armory.constant' import { Price } from '../../shared/core/type/price.type' -import { assetIdSchema } from '../../shared/schema/caip.schema' import { generateAddress, generateSupportedChainId } from './shared.fixture' export const fiatIdSchema = z.custom<`fiat:${string}`>((value) => { diff --git a/apps/armory/src/__test__/fixture/shared.fixture.ts b/apps/armory/src/__test__/fixture/shared.fixture.ts index 64a106818..3d1a9b4d7 100644 --- a/apps/armory/src/__test__/fixture/shared.fixture.ts +++ b/apps/armory/src/__test__/fixture/shared.fixture.ts @@ -1,12 +1,10 @@ import { faker } from '@faker-js/faker' -import { Address, getAddress } from '@narval/policy-engine-shared' +import { Address, addressSchema, getAddress, hexSchema } from '@narval/policy-engine-shared' import { sample } from 'lodash/fp' import { Generator } from 'zod-fixture' import { CHAINS } from '../../armory.constant' import { ChainId } from '../../shared/core/lib/chains.lib' -import { addressSchema } from '../../shared/schema/address.schema' import { chainIdSchema } from '../../shared/schema/chain-id.schema' -import { hexSchema } from '../../shared/schema/hex.schema' export const hexGenerator = Generator({ schema: hexSchema, diff --git a/apps/armory/src/__test__/fixture/transfer-tracking.fixture.ts b/apps/armory/src/__test__/fixture/transfer-tracking.fixture.ts index a4d5bcef9..53d35f0b4 100644 --- a/apps/armory/src/__test__/fixture/transfer-tracking.fixture.ts +++ b/apps/armory/src/__test__/fixture/transfer-tracking.fixture.ts @@ -1,8 +1,8 @@ +import { addressSchema } from '@narval/policy-engine-shared' import { z } from 'zod' import { Fixture } from 'zod-fixture' import { generatePrice } from '../../__test__/fixture/price.fixture' import { Transfer } from '../../shared/core/type/transfer-tracking.type' -import { addressSchema } from '../../shared/schema/address.schema' import { chainIdSchema } from '../../shared/schema/chain-id.schema' import { addressGenerator, chainIdGenerator } from './shared.fixture' diff --git a/apps/armory/src/orchestration/persistence/schema/transaction-request.schema.ts b/apps/armory/src/orchestration/persistence/schema/transaction-request.schema.ts index 5456d5f4f..80abc11c4 100644 --- a/apps/armory/src/orchestration/persistence/schema/transaction-request.schema.ts +++ b/apps/armory/src/orchestration/persistence/schema/transaction-request.schema.ts @@ -1,7 +1,6 @@ +import { addressSchema, hexSchema } from '@narval/policy-engine-shared' import { z } from 'zod' -import { addressSchema } from '../../../shared/schema/address.schema' import { chainIdSchema } from '../../../shared/schema/chain-id.schema' -import { hexSchema } from '../../../shared/schema/hex.schema' export const accessListSchema = z.object({ address: addressSchema, diff --git a/apps/armory/src/shared/schema/caip.schema.ts b/apps/armory/src/shared/schema/caip.schema.ts deleted file mode 100644 index 22def77be..000000000 --- a/apps/armory/src/shared/schema/caip.schema.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { AssetType, Namespace, isAccountId, isAssetId } from '@narval/policy-engine-shared' -import { z } from 'zod' - -const nonCollectableAssetIdSchema = z.custom<`${Namespace}:${number}/${AssetType}:${string}`>((value) => { - const parse = z.string().safeParse(value) - - if (parse.success) { - return isAssetId(parse.data) - } - - return false -}) - -const collectableAssetIdSchema = z.custom<`${Namespace}:${number}/${AssetType}:${string}/${string}`>((value) => { - const parse = z.string().safeParse(value) - - if (parse.success) { - return isAssetId(parse.data) - } - - return false -}) - -const coinAssetIdSchema = z.custom<`${Namespace}:${number}/${AssetType.SLIP44}:${number}`>((value) => { - const parse = z.string().safeParse(value) - - if (parse.success) { - return isAssetId(parse.data) - } - - return false -}) - -export const accountIdSchema = z.custom<`${Namespace}:${number}/${string}`>((value) => { - const parse = z.string().safeParse(value) - - if (parse.success) { - return isAccountId(parse.data) - } - - return false -}) - -export const assetIdSchema = z.union([nonCollectableAssetIdSchema, collectableAssetIdSchema, coinAssetIdSchema]) diff --git a/packages/policy-engine-shared/src/index.ts b/packages/policy-engine-shared/src/index.ts index 65a21435d..149436979 100644 --- a/packages/policy-engine-shared/src/index.ts +++ b/packages/policy-engine-shared/src/index.ts @@ -5,6 +5,8 @@ export * from './lib/decorators/is-not-empty-array-enum.decorator' export * from './lib/decorators/is-not-empty-array-string.decorator' export * as FIXTURE from './lib/dev.fixture' export * from './lib/dto' +export * from './lib/schema/address.schema' +export * from './lib/schema/hex.schema' export * from './lib/type/action.type' export * from './lib/type/domain.type' export * from './lib/type/entity.type' diff --git a/packages/policy-engine-shared/src/lib/domain/__test__/unit/entity.domain.spec.ts b/packages/policy-engine-shared/src/lib/domain/__test__/unit/entity.domain.spec.ts new file mode 100644 index 000000000..d3f4cccb7 --- /dev/null +++ b/packages/policy-engine-shared/src/lib/domain/__test__/unit/entity.domain.spec.ts @@ -0,0 +1,335 @@ +import { ADDRESS_BOOK, CREDENTIAL, TOKEN, USER, USER_GROUP, WALLET, WALLET_GROUP } from '../../../dev.fixture' +import { AccountClassification, Entities } from '../../../type/entity.type' +import { validate } from '../../entity.domain' + +describe('validate', () => { + const emptyEntities: Entities = { + addressBook: [], + credentials: [], + tokens: [], + userGroupMembers: [], + userGroups: [], + userWallets: [], + users: [], + walletGroupMembers: [], + walletGroups: [], + wallets: [] + } + + describe('association integrity', () => { + it('fails when group from user group member does not exist', () => { + const result = validate({ + ...emptyEntities, + userGroupMembers: [ + { + groupId: USER_GROUP.Engineering.uid, + userId: USER.Alice.uid + } + ], + users: [USER.Alice] + }) + + expect(result).toEqual({ + success: false, + issues: [ + { + code: 'ENTITY_NOT_FOUND', + message: + "Couldn't create the user group member because the group test-engineering-user-group-uid is undefined" + } + ] + }) + }) + + it('fails when user from user group member does not exist', () => { + const result = validate({ + ...emptyEntities, + userGroups: [USER_GROUP.Engineering], + userGroupMembers: [ + { + groupId: USER_GROUP.Engineering.uid, + userId: USER.Alice.uid + } + ] + }) + + expect(result).toEqual({ + success: false, + issues: [ + { + code: 'ENTITY_NOT_FOUND', + message: + "Couldn't create the user group member for group test-engineering-user-group-uid because the user test-alice-user-uid is undefined" + } + ] + }) + }) + + it('fails when group from wallet group member does not exist', () => { + const result = validate({ + ...emptyEntities, + wallets: [WALLET.Engineering], + walletGroupMembers: [ + { + walletId: WALLET.Engineering.uid, + groupId: WALLET_GROUP.Engineering.uid + } + ] + }) + + expect(result).toEqual({ + success: false, + issues: [ + { + code: 'ENTITY_NOT_FOUND', + message: + "Couldn't create the wallet group member because the group test-engineering-wallet-group-uid is undefined" + } + ] + }) + }) + + it('fails when wallet from wallet group member does not exist', () => { + const result = validate({ + ...emptyEntities, + walletGroups: [WALLET_GROUP.Engineering], + walletGroupMembers: [ + { + walletId: WALLET.Engineering.uid, + groupId: WALLET_GROUP.Engineering.uid + } + ] + }) + + expect(result).toEqual({ + success: false, + issues: [ + { + code: 'ENTITY_NOT_FOUND', + message: + "Couldn't create the wallet group member for group test-engineering-wallet-group-uid because the wallet eip155:eoa:0x22228d0504d4f3363a5b7fda1f5fff1c7bca8ad4 is undefined" + } + ] + }) + }) + + it('fails when user from user wallet does not exist', () => { + const result = validate({ + ...emptyEntities, + wallets: [WALLET.Engineering], + userWallets: [ + { + userId: USER.Alice.uid, + walletId: WALLET.Engineering.uid + } + ] + }) + + expect(result).toEqual({ + success: false, + issues: [ + { + code: 'ENTITY_NOT_FOUND', + message: `Couldn't assign the wallet ${WALLET.Engineering.uid} because the user ${USER.Alice.uid} is undefined` + } + ] + }) + }) + + it('fails when wallet from user wallet does not exist', () => { + const result = validate({ + ...emptyEntities, + users: [USER.Alice], + userWallets: [ + { + userId: USER.Alice.uid, + walletId: WALLET.Engineering.uid + } + ] + }) + + expect(result).toEqual({ + success: false, + issues: [ + { + code: 'ENTITY_NOT_FOUND', + message: `Couldn't assign the wallet ${WALLET.Engineering.uid} because it's undefined` + } + ] + }) + }) + }) + + describe('uids duplication', () => { + it('fails when address book uids are not unique', () => { + const result = validate({ + ...emptyEntities, + addressBook: [ADDRESS_BOOK[0], ADDRESS_BOOK[0], ADDRESS_BOOK[1]] + }) + + expect(result).toEqual({ + success: false, + issues: [ + { + code: 'UNIQUE_IDENTIFIER_DUPLICATION', + message: `The address book account ${ADDRESS_BOOK[0].uid} is duplicated` + } + ] + }) + }) + + it('fails when credential uids are not unique', () => { + const result = validate({ + ...emptyEntities, + credentials: [CREDENTIAL.Alice, CREDENTIAL.Alice, CREDENTIAL.Bob] + }) + + expect(result).toEqual({ + success: false, + issues: [ + { + code: 'UNIQUE_IDENTIFIER_DUPLICATION', + message: `The credential ${CREDENTIAL.Alice.uid} is duplicated` + } + ] + }) + }) + + it('fails when token uids are not unique', () => { + const result = validate({ + ...emptyEntities, + tokens: [TOKEN.usdc1, TOKEN.usdc1, TOKEN.usdc137] + }) + + expect(result).toEqual({ + success: false, + issues: [ + { + code: 'UNIQUE_IDENTIFIER_DUPLICATION', + message: `The token ${TOKEN.usdc1.uid} is duplicated` + } + ] + }) + }) + + it('fails when user group uids are not unique', () => { + const result = validate({ + ...emptyEntities, + userGroups: [USER_GROUP.Engineering, USER_GROUP.Engineering, USER_GROUP.Treasury] + }) + + expect(result).toEqual({ + success: false, + issues: [ + { + code: 'UNIQUE_IDENTIFIER_DUPLICATION', + message: `The user group ${USER_GROUP.Engineering.uid} is duplicated` + } + ] + }) + }) + + it('fails when users uids are not unique', () => { + const result = validate({ + ...emptyEntities, + users: [USER.Alice, USER.Alice, USER.Bob] + }) + + expect(result).toEqual({ + success: false, + issues: [ + { + code: 'UNIQUE_IDENTIFIER_DUPLICATION', + message: `The user ${USER.Alice.uid} is duplicated` + } + ] + }) + }) + + it('fails when wallet group uids are not unique', () => { + const result = validate({ + ...emptyEntities, + walletGroups: [WALLET_GROUP.Engineering, WALLET_GROUP.Engineering, WALLET_GROUP.Treasury] + }) + + expect(result).toEqual({ + success: false, + issues: [ + { + code: 'UNIQUE_IDENTIFIER_DUPLICATION', + message: `The wallet group ${WALLET_GROUP.Engineering.uid} is duplicated` + } + ] + }) + }) + + it('fails when wallets uids are not unique', () => { + const result = validate({ + ...emptyEntities, + wallets: [WALLET.Engineering, WALLET.Engineering, WALLET.Treasury] + }) + + expect(result).toEqual({ + success: false, + issues: [ + { + code: 'UNIQUE_IDENTIFIER_DUPLICATION', + message: `The wallet ${WALLET.Engineering.uid} is duplicated` + } + ] + }) + }) + }) + + describe('uid format', () => { + it('fails when address book account uid is not an account id', () => { + const invalidAccountId = '16aba381-c54a-4f72-89bd-bd1e7c46ed29' + const result = validate({ + ...emptyEntities, + addressBook: [ + { + uid: invalidAccountId, + address: WALLET.Engineering.address, + chainId: 137, + classification: AccountClassification.WALLET + }, + ADDRESS_BOOK[0] + ] + }) + + expect(result).toEqual({ + success: false, + issues: [ + { + code: 'INVALID_UID_FORMAT', + message: `address book account uid ${invalidAccountId} is not a valid account id` + } + ] + }) + }) + + it('fails when token uid is not an asset id', () => { + const invalidAccountId = '16aba381-c54a-4f72-89bd-bd1e7c46ed29' + const result = validate({ + ...emptyEntities, + tokens: [ + { + ...TOKEN.usdc1, + uid: invalidAccountId + }, + TOKEN.usdc137 + ] + }) + + expect(result).toEqual({ + success: false, + issues: [ + { + code: 'INVALID_UID_FORMAT', + message: `token uid ${invalidAccountId} is not a valid asset id` + } + ] + }) + }) + }) +}) diff --git a/packages/policy-engine-shared/src/lib/domain/entity.domain.ts b/packages/policy-engine-shared/src/lib/domain/entity.domain.ts new file mode 100644 index 000000000..47231cebf --- /dev/null +++ b/packages/policy-engine-shared/src/lib/domain/entity.domain.ts @@ -0,0 +1,154 @@ +import { countBy, flatten, indexBy, keys, map, pickBy } from 'lodash/fp' +import { Entities } from '../type/entity.type' +import { isAccountId, isAssetId } from '../util/caip.util' + +export type ValidationIssue = { + code: string + message: string +} + +export type Validation = { success: true } | { success: false; issues: ValidationIssue[] } + +export type Validator = (entities: Entities) => ValidationIssue[] + +export type ValidationOption = { + validators?: Validator[] +} + +const validateUserGroupMemberIntegrity: Validator = (entities: Entities): ValidationIssue[] => { + const users = indexBy('uid', entities.users) + const userGroups = indexBy('uid', entities.userGroups) + + const userIssues: ValidationIssue[] = entities.userGroupMembers + .filter(({ userId }) => !users[userId]) + .map(({ userId, groupId }) => ({ + code: 'ENTITY_NOT_FOUND', + message: `Couldn't create the user group member for group ${groupId} because the user ${userId} is undefined` + })) + + const groupIssues: ValidationIssue[] = entities.userGroupMembers + .filter(({ groupId }) => !userGroups[groupId]) + .map(({ groupId }) => ({ + code: 'ENTITY_NOT_FOUND', + message: `Couldn't create the user group member because the group ${groupId} is undefined` + })) + + return [...userIssues, ...groupIssues] +} + +const validateWalletGroupMemberIntegrity: Validator = (entities: Entities): ValidationIssue[] => { + const wallets = indexBy('uid', entities.wallets) + const walletGroups = indexBy('uid', entities.walletGroups) + + const walletIssues: ValidationIssue[] = entities.walletGroupMembers + .filter(({ walletId }) => !wallets[walletId]) + .map(({ walletId, groupId }) => ({ + code: 'ENTITY_NOT_FOUND', + message: `Couldn't create the wallet group member for group ${groupId} because the wallet ${walletId} is undefined` + })) + + const groupIssues: ValidationIssue[] = entities.walletGroupMembers + .filter(({ groupId }) => !walletGroups[groupId]) + .map(({ groupId }) => ({ + code: 'ENTITY_NOT_FOUND', + message: `Couldn't create the wallet group member because the group ${groupId} is undefined` + })) + + return [...walletIssues, ...groupIssues] +} + +const validateUserWalletIntegrity: Validator = (entities: Entities): ValidationIssue[] => { + const wallets = indexBy('uid', entities.wallets) + const users = indexBy('uid', entities.users) + + const userIssues: ValidationIssue[] = entities.userWallets + .filter(({ userId }) => !users[userId]) + .map(({ userId, walletId }) => ({ + code: 'ENTITY_NOT_FOUND', + message: `Couldn't assign the wallet ${walletId} because the user ${userId} is undefined` + })) + + const walletIssues: ValidationIssue[] = entities.userWallets + .filter(({ walletId }) => !wallets[walletId]) + .map(({ walletId }) => ({ + code: 'ENTITY_NOT_FOUND', + message: `Couldn't assign the wallet ${walletId} because it's undefined` + })) + + return [...userIssues, ...walletIssues] +} + +const validateUniqueIdDuplication: Validator = (entities: Entities): ValidationIssue[] => { + const code = 'UNIQUE_IDENTIFIER_DUPLICATION' + + const findIssues = (values: T, message: (uid: string) => string): ValidationIssue[] => { + return map( + (uid) => ({ + code, + message: message(uid) + }), + keys(pickBy((count: number) => count > 1, countBy('uid', values))) + ) + } + + return flatten([ + findIssues(entities.addressBook, (uid) => `The address book account ${uid} is duplicated`), + findIssues(entities.credentials, (uid) => `The credential ${uid} is duplicated`), + findIssues(entities.tokens, (uid) => `The token ${uid} is duplicated`), + findIssues(entities.userGroups, (uid) => `The user group ${uid} is duplicated`), + findIssues(entities.users, (uid) => `The user ${uid} is duplicated`), + findIssues(entities.walletGroups, (uid) => `The wallet group ${uid} is duplicated`), + findIssues(entities.wallets, (uid) => `The wallet ${uid} is duplicated`) + ]) +} + +const validateAddressBookUniqueIdFormat: Validator = (entities: Entities): ValidationIssue[] => { + return entities.addressBook + .filter(({ uid }) => !isAccountId(uid)) + .map(({ uid }) => { + return { + code: 'INVALID_UID_FORMAT', + message: `address book account uid ${uid} is not a valid account id` + } + }) +} + +const validateTokenUniqueIdFormat: Validator = (entities: Entities): ValidationIssue[] => { + return entities.tokens + .filter(({ uid }) => !isAssetId(uid)) + .map(({ uid }) => { + return { + code: 'INVALID_UID_FORMAT', + message: `token uid ${uid} is not a valid asset id` + } + }) +} + +export const DEFAULT_VALIDATORS: Validator[] = [ + validateUserGroupMemberIntegrity, + validateWalletGroupMemberIntegrity, + validateUserWalletIntegrity, + validateUniqueIdDuplication, + validateAddressBookUniqueIdFormat, + validateTokenUniqueIdFormat + // TODO (@wcalderipe, 21/02/25): Missing domain invariants to be validate + // - fails when root user does not have a credential + // - fails when credential does not have a user +] + +export const validate = (entities: Entities, options?: ValidationOption): Validation => { + const validators = options?.validators || DEFAULT_VALIDATORS + + const issues = validators.flatMap((validation) => validation(entities)) + + if (issues.length) { + return { + success: false, + issues + } + } + + return { + success: true + } +} diff --git a/apps/armory/src/shared/schema/address.schema.ts b/packages/policy-engine-shared/src/lib/schema/address.schema.ts similarity index 87% rename from apps/armory/src/shared/schema/address.schema.ts rename to packages/policy-engine-shared/src/lib/schema/address.schema.ts index 321a00239..b0d4a548e 100644 --- a/apps/armory/src/shared/schema/address.schema.ts +++ b/packages/policy-engine-shared/src/lib/schema/address.schema.ts @@ -1,5 +1,5 @@ -import { isAddress } from '@narval/policy-engine-shared' import { z } from 'zod' +import { isAddress } from '../util/evm.util' /** * Schema backward compatible with viem's Address type. diff --git a/apps/armory/src/shared/schema/hex.schema.ts b/packages/policy-engine-shared/src/lib/schema/hex.schema.ts similarity index 100% rename from apps/armory/src/shared/schema/hex.schema.ts rename to packages/policy-engine-shared/src/lib/schema/hex.schema.ts From 5d46b064032dc1d99ffde8ecd3c1b7a920a0a2fe Mon Sep 17 00:00:00 2001 From: William Calderipe Date: Thu, 22 Feb 2024 17:07:29 +0100 Subject: [PATCH 3/9] Work in progress entity put --- .../exception/entity-validation.exception.ts | 13 ++ .../core/exception/storage.exception.ts | 3 + .../__test__/unit/entity.service.spec.ts | 58 +++++++++ .../storage/core/service/entity.service.ts | 13 +- .../store/entity/__test__/e2e/entity.spec.ts | 114 ++++-------------- .../entity/core/service/user-group.service.ts | 26 ++-- .../entity/core/service/wallet.service.ts | 5 +- .../entity/persistence/entity-store.seed.ts | 29 +++-- .../repository/user-group.repository.ts | 29 +---- .../repository/wallet-group.repository.ts | 32 +---- packages/policy-engine-shared/src/index.ts | 1 + .../src/lib/dev.fixture.ts | 6 +- .../__test__/unit/entity.util.spec.ts} | 2 +- .../entity.domain.ts => util/entity.util.ts} | 2 +- 14 files changed, 148 insertions(+), 185 deletions(-) create mode 100644 apps/armory/src/storage/core/exception/entity-validation.exception.ts create mode 100644 apps/armory/src/storage/core/exception/storage.exception.ts create mode 100644 apps/armory/src/storage/core/service/__test__/unit/entity.service.spec.ts rename packages/policy-engine-shared/src/lib/{domain/__test__/unit/entity.domain.spec.ts => util/__test__/unit/entity.util.spec.ts} (99%) rename packages/policy-engine-shared/src/lib/{domain/entity.domain.ts => util/entity.util.ts} (98%) diff --git a/apps/armory/src/storage/core/exception/entity-validation.exception.ts b/apps/armory/src/storage/core/exception/entity-validation.exception.ts new file mode 100644 index 000000000..ff4cd1f5d --- /dev/null +++ b/apps/armory/src/storage/core/exception/entity-validation.exception.ts @@ -0,0 +1,13 @@ +import { EntityUtil } from '@narval/policy-engine-shared' +import { HttpStatus } from '@nestjs/common' +import { StorageException } from './storage.exception' + +export class EntityValidationException extends StorageException { + constructor(issues: EntityUtil.ValidationIssue[]) { + super({ + message: 'Entity validation failed', + suggestedHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY, + context: { issues } + }) + } +} diff --git a/apps/armory/src/storage/core/exception/storage.exception.ts b/apps/armory/src/storage/core/exception/storage.exception.ts new file mode 100644 index 000000000..4a30fba3e --- /dev/null +++ b/apps/armory/src/storage/core/exception/storage.exception.ts @@ -0,0 +1,3 @@ +import { ApplicationException } from '../../../shared/exception/application.exception' + +export class StorageException extends ApplicationException {} diff --git a/apps/armory/src/storage/core/service/__test__/unit/entity.service.spec.ts b/apps/armory/src/storage/core/service/__test__/unit/entity.service.spec.ts new file mode 100644 index 000000000..46a0629d6 --- /dev/null +++ b/apps/armory/src/storage/core/service/__test__/unit/entity.service.spec.ts @@ -0,0 +1,58 @@ +import { Entities, FIXTURE } from '@narval/policy-engine-shared' +import { Test } from '@nestjs/testing' +import { InMemoryEntityRepository } from '../../../../persistence/repository/in-memory-entity.repository' +import { EntityValidationException } from '../../../exception/entity-validation.exception' +import { EntityRepository } from '../../../repository/entity.repository' +import { EntityService } from '../../entity.service' + +describe(EntityService.name, () => { + let service: EntityService + + const orgId = 'test-org-id' + + const emptyEntities: Entities = { + addressBook: [], + credentials: [], + tokens: [], + userGroupMembers: [], + userGroups: [], + userWallets: [], + users: [], + walletGroupMembers: [], + walletGroups: [], + wallets: [] + } + + beforeEach(async () => { + const module = await Test.createTestingModule({ + providers: [ + EntityService, + { + provide: EntityRepository, + useClass: InMemoryEntityRepository + } + ] + }).compile() + + service = module.get(EntityService) + }) + + describe('put', () => { + it('throws EntityValidationException when validation fails', async () => { + await expect( + service.put(orgId, { + entities: { + ...emptyEntities, + userGroupMembers: [ + { + groupId: FIXTURE.USER_GROUP.Engineering.uid, + userId: FIXTURE.USER.Alice.uid + } + ], + users: [FIXTURE.USER.Alice] + } + }) + ).rejects.toThrow(EntityValidationException) + }) + }) +}) diff --git a/apps/armory/src/storage/core/service/entity.service.ts b/apps/armory/src/storage/core/service/entity.service.ts index a1f8a161d..5bdc63906 100644 --- a/apps/armory/src/storage/core/service/entity.service.ts +++ b/apps/armory/src/storage/core/service/entity.service.ts @@ -1,12 +1,19 @@ -import { Entities } from '@narval/policy-engine-shared' +import { Entities, EntityUtil } from '@narval/policy-engine-shared' import { Inject } from '@nestjs/common' +import { EntityValidationException } from '../exception/entity-validation.exception' import { EntityRepository } from '../repository/entity.repository' export class EntityService { constructor(@Inject(EntityRepository) private entityRepository: EntityRepository) {} - put(orgId: string, data: { entities: Entities }): Promise { - return this.entityRepository.put(orgId, data.entities) + async put(orgId: string, data: { entities: Entities }): Promise { + const result = EntityUtil.validate(data.entities) + + if (result.success) { + return this.entityRepository.put(orgId, data.entities) + } + + throw new EntityValidationException(result.issues) } findByOrgId(orgId: string): Promise { diff --git a/apps/armory/src/store/entity/__test__/e2e/entity.spec.ts b/apps/armory/src/store/entity/__test__/e2e/entity.spec.ts index 6e04e13ae..9137b0345 100644 --- a/apps/armory/src/store/entity/__test__/e2e/entity.spec.ts +++ b/apps/armory/src/store/entity/__test__/e2e/entity.spec.ts @@ -1,25 +1,22 @@ import { - AccountClassification, - AccountType, AddressBookAccountEntity, - Alg, CredentialEntity, Entities, + FIXTURE, OrganizationEntity, TokenEntity, UserEntity, UserGroupEntity, - UserRole, + UserGroupMemberEntity, UserWalletEntity, WalletEntity, - WalletGroupEntity + WalletGroupEntity, + WalletGroupMemberEntity } from '@narval/policy-engine-shared' import { HttpStatus, INestApplication } from '@nestjs/common' import { ConfigModule } from '@nestjs/config' import { Test, TestingModule } from '@nestjs/testing' -import { map } from 'lodash/fp' import request from 'supertest' -import { sha256 } from 'viem' import { load } from '../../../../armory.config' import { REQUEST_HEADER_ORG_ID } from '../../../../armory.constant' import { OrchestrationModule } from '../../../../orchestration/orchestration.module' @@ -58,84 +55,16 @@ describe('Entity', () => { uid: 'ac1374c2-fd62-4b6e-bd49-a4afcdcb91cc' } - const users: UserEntity[] = [ - { - uid: '2d7a6811-509f-4bee-90fb-e382fc127de5', - role: UserRole.ADMIN - }, - { - uid: '70d4128a-4b47-4944-859b-c570c69d3120', - role: UserRole.ADMIN - } - ] - - const credentials: CredentialEntity[] = [ - { - uid: sha256('0x5a4c3948723e02cbdef57d0eeb0fa8e2fc8f81fc'), - pubKey: '0x5a4c3948723e02cbdef57d0eeb0fa8e2fc8f81fc', - alg: Alg.ES256K, - userId: users[0].uid - } - ] - - const wallets: WalletEntity[] = [ - { - uid: 'a5c1fd4e-b021-4fad-b5a6-256b434916ef', - address: '0x648edbd0e1bd5f15d58481bc7f034a790f9741fe', - accountType: AccountType.EOA, - chainId: 1 - }, - { - uid: '3fe39a8e-1721-4111-bc3a-4f89c0d67594', - address: '0x40710fae7b7d1200b644a579ddee65aecd7a991a', - accountType: AccountType.EOA, - chainId: 1 - } - ] - - const walletGroups: WalletGroupEntity[] = [ - { - uid: 'a104baeb-c9dd-4066-ae56-d85168715f90', - wallets: map('uid', wallets) - } - ] - - const userWallets: UserWalletEntity[] = [ - { - userId: users[0].uid, - walletId: wallets[0].uid - }, - { - userId: users[1].uid, - walletId: wallets[1].uid - } - ] - - const userGroups: UserGroupEntity[] = [ - { - uid: 'd160dab5-211a-447d-9c25-2772e3ecbe17', - users: [users[0].uid] - } - ] - - const addressBook: AddressBookAccountEntity[] = [ - { - uid: '6b88f31f-564f-4463-86a6-28c3ad9105ff', - address: '0xeff7eda2dd2567b80f96ba5eb292e399cc360a05', - chainId: 1, - classification: AccountClassification.EXTERNAL - } - ] - - const tokens: TokenEntity[] = [ - { - uid: '2ece731a-51be-4b4f-91de-5665eacf7006', - address: '0x63d74e23f70f66511417bc7acf95f002d1dbd33c', - chainId: 1, - symbol: 'AAA', - decimals: 18 - } - ] + const addressBook: AddressBookAccountEntity[] = FIXTURE.ADDRESS_BOOK + const credentials: CredentialEntity[] = Object.values(FIXTURE.CREDENTIAL) + const tokens: TokenEntity[] = Object.values(FIXTURE.TOKEN) + const userGroupMembers: UserGroupMemberEntity[] = FIXTURE.USER_GROUP_MEMBER + const userGroups: UserGroupEntity[] = Object.values(FIXTURE.USER_GROUP) + const userWallets: UserWalletEntity[] = FIXTURE.USER_WALLET + const users: UserEntity[] = Object.values(FIXTURE.USER) + const walletGroupMembers: WalletGroupMemberEntity[] = FIXTURE.WALLET_GROUP_MEMBER + const walletGroups: WalletGroupEntity[] = Object.values(FIXTURE.WALLET_GROUP) + const wallets: WalletEntity[] = Object.values(FIXTURE.WALLET) const sortByUid = (entities: E[]): E[] => { return entities.sort((a, b) => a.uid.localeCompare(b.uid)) @@ -147,14 +76,20 @@ describe('Entity', () => { walletGroups, userGroups, addressBook, - credentials + credentials, + userGroupMembers, + userWallets, + walletGroupMembers }: Entities): Entities => { return { addressBook: sortByUid(addressBook), credentials: sortByUid(credentials), tokens: sortByUid(tokens), + userGroupMembers: userGroupMembers.sort(), userGroups: sortByUid(userGroups), + userWallets: userWallets.sort(), users: sortByUid(users), + walletGroupMembers: walletGroupMembers.sort(), walletGroups: sortByUid(walletGroups), wallets: sortByUid(wallets) } @@ -233,11 +168,14 @@ describe('Entity', () => { getDeterministicEntities({ addressBook, credentials, + tokens, + userGroupMembers, userGroups, + userWallets, users, + walletGroupMembers, walletGroups, - wallets, - tokens + wallets }) ) expect(status).toEqual(HttpStatus.OK) diff --git a/apps/armory/src/store/entity/core/service/user-group.service.ts b/apps/armory/src/store/entity/core/service/user-group.service.ts index 742c7441b..a839d3333 100644 --- a/apps/armory/src/store/entity/core/service/user-group.service.ts +++ b/apps/armory/src/store/entity/core/service/user-group.service.ts @@ -10,17 +10,21 @@ export class UserGroupService { const { groupId, userId } = input.request.data const group = await this.userGroupRepository.findById(groupId) - if (group) { - await this.userGroupRepository.update({ - ...group, - users: group.users.concat(userId) - }) - } else { - await this.userGroupRepository.create(orgId, { - uid: groupId, - users: [userId] - }) - } + // if (!group) { + // await this.userGroupRepository.create(orgId, { uid: groupId }) + // } + + // if (group) { + // await this.userGroupRepository.update({ + // ...group, + // users: group.users.concat(userId) + // }) + // } else { + // await this.userGroupRepository.create(orgId, { + // uid: groupId, + // users: [userId] + // }) + // } return true } diff --git a/apps/armory/src/store/entity/core/service/wallet.service.ts b/apps/armory/src/store/entity/core/service/wallet.service.ts index 228ebbc1c..a24a397ae 100644 --- a/apps/armory/src/store/entity/core/service/wallet.service.ts +++ b/apps/armory/src/store/entity/core/service/wallet.service.ts @@ -22,10 +22,7 @@ export class WalletService { async assignGroup(orgId: string, input: AssignWalletGroupRequest): Promise { const { groupId, walletId } = input.request.data - await this.walletGroupRepository.create(orgId, { - uid: groupId, - wallets: [walletId] - }) + await this.walletGroupRepository.create(orgId, { uid: groupId }) return { groupId, walletId } } diff --git a/apps/armory/src/store/entity/persistence/entity-store.seed.ts b/apps/armory/src/store/entity/persistence/entity-store.seed.ts index 380fdcb26..20b6e3e49 100644 --- a/apps/armory/src/store/entity/persistence/entity-store.seed.ts +++ b/apps/armory/src/store/entity/persistence/entity-store.seed.ts @@ -1,6 +1,5 @@ import { FIXTURE } from '@narval/policy-engine-shared' import { Injectable } from '@nestjs/common' -import { compact } from 'lodash/fp' import { SeedService } from '../../../shared/module/persistence/service/seed.service' import { AddressBookRepository } from './repository/address-book.repository' import { CredentialRepository } from './repository/credential.repository' @@ -47,20 +46,20 @@ export class EntityStoreSeed extends SeedService { Object.values(FIXTURE.USER_GROUP).map((entity) => this.userGroupRepository.create(ORGANIZATION.uid, entity)) ) - await Promise.all( - compact( - Object.values(FIXTURE.WALLET).map(({ uid, assignees }) => { - if (assignees?.length) { - return assignees.map((userId) => - this.userWalletRepository.create(ORGANIZATION.uid, { - userId, - walletId: uid - }) - ) - } - }) - ) - ) + // await Promise.all( + // compact( + // Object.values(FIXTURE.WALLET).map(({ uid, assignees }) => { + // if (assignees?.length) { + // return assignees.map((userId) => + // this.userWalletRepository.create(ORGANIZATION.uid, { + // userId, + // walletId: uid + // }) + // ) + // } + // }) + // ) + // ) await Promise.all(FIXTURE.ADDRESS_BOOK.map((entity) => this.addressBookRepository.create(ORGANIZATION.uid, entity))) diff --git a/apps/armory/src/store/entity/persistence/repository/user-group.repository.ts b/apps/armory/src/store/entity/persistence/repository/user-group.repository.ts index b1a592671..ab48754db 100644 --- a/apps/armory/src/store/entity/persistence/repository/user-group.repository.ts +++ b/apps/armory/src/store/entity/persistence/repository/user-group.repository.ts @@ -1,7 +1,6 @@ import { UserGroupEntity } from '@narval/policy-engine-shared' import { Injectable } from '@nestjs/common' import { UserGroupEntity as GroupModel, UserGroupMemberEntity as MemberModel } from '@prisma/client/armory' -import { map } from 'lodash/fp' import { PrismaService } from '../../../../shared/module/persistence/service/prisma.service' type Model = GroupModel & { @@ -20,32 +19,9 @@ export class UserGroupRepository { } }) - if (userGroup.users.length) { - await this.enroll(userGroup.uid, userGroup.users) - } - - return userGroup - } - - async update(userGroup: UserGroupEntity): Promise { - if (userGroup.users.length) { - await this.enroll(userGroup.uid, userGroup.users) - } - return userGroup } - private async enroll(groupId: string, userIds: string[]): Promise { - const members = userIds.map((userId) => ({ userId, groupId })) - - await this.prismaService.userGroupMemberEntity.createMany({ - data: members, - skipDuplicates: true - }) - - return true - } - async findById(uid: string): Promise { const model = await this.prismaService.userGroupEntity.findUnique({ where: { uid }, @@ -73,9 +49,6 @@ export class UserGroupRepository { } private decode(model: Model): UserGroupEntity { - return { - uid: model.uid, - users: map('userId', model.members) - } + return { uid: model.uid } } } diff --git a/apps/armory/src/store/entity/persistence/repository/wallet-group.repository.ts b/apps/armory/src/store/entity/persistence/repository/wallet-group.repository.ts index 64cd826b4..3168df6c4 100644 --- a/apps/armory/src/store/entity/persistence/repository/wallet-group.repository.ts +++ b/apps/armory/src/store/entity/persistence/repository/wallet-group.repository.ts @@ -1,7 +1,6 @@ import { WalletGroupEntity } from '@narval/policy-engine-shared' import { Injectable } from '@nestjs/common' import { WalletGroupEntity as GroupModel, WalletGroupMemberEntity as MemberModel } from '@prisma/client/armory' -import { map } from 'lodash/fp' import { PrismaService } from '../../../../shared/module/persistence/service/prisma.service' type Model = GroupModel & { @@ -26,35 +25,9 @@ export class WalletGroupRepository { }) } - if (walletGroup.wallets.length) { - await this.enroll(walletGroup.uid, walletGroup.wallets) - } - - return walletGroup - } - - async update(walletGroup: WalletGroupEntity): Promise { - if (walletGroup.wallets.length) { - await this.enroll(walletGroup.uid, walletGroup.wallets) - } - return walletGroup } - private async enroll(groupId: string, walletIds: string[]): Promise { - const members = walletIds.map((walletId) => ({ - walletId, - groupId - })) - - await this.prismaService.walletGroupMemberEntity.createMany({ - data: members, - skipDuplicates: true - }) - - return true - } - async findById(uid: string): Promise { const model = await this.prismaService.walletGroupEntity.findUnique({ where: { uid }, @@ -82,9 +55,6 @@ export class WalletGroupRepository { } private decode(model: Model): WalletGroupEntity { - return { - uid: model.uid, - wallets: map('walletId', model.members) - } + return { uid: model.uid } } } diff --git a/packages/policy-engine-shared/src/index.ts b/packages/policy-engine-shared/src/index.ts index 149436979..14319d818 100644 --- a/packages/policy-engine-shared/src/index.ts +++ b/packages/policy-engine-shared/src/index.ts @@ -11,6 +11,7 @@ export * from './lib/type/action.type' export * from './lib/type/domain.type' export * from './lib/type/entity.type' export * from './lib/util/caip.util' +export * as EntityUtil from './lib/util/entity.util' export * from './lib/util/enum.util' export * from './lib/util/evm.util' export * from './lib/util/hash-request.util' diff --git a/packages/policy-engine-shared/src/lib/dev.fixture.ts b/packages/policy-engine-shared/src/lib/dev.fixture.ts index 055608c9c..5a5b7b0c3 100644 --- a/packages/policy-engine-shared/src/lib/dev.fixture.ts +++ b/packages/policy-engine-shared/src/lib/dev.fixture.ts @@ -254,11 +254,11 @@ export const ENTITIES: Entities = { addressBook: ADDRESS_BOOK, credentials: Object.values(CREDENTIAL), tokens: Object.values(TOKEN), - userGroups: Object.values(USER_GROUP), - users: Object.values(USER), userGroupMembers: USER_GROUP_MEMBER, + userGroups: Object.values(USER_GROUP), userWallets: USER_WALLET, - walletGroups: Object.values(WALLET_GROUP), + users: Object.values(USER), walletGroupMembers: WALLET_GROUP_MEMBER, + walletGroups: Object.values(WALLET_GROUP), wallets: Object.values(WALLET) } diff --git a/packages/policy-engine-shared/src/lib/domain/__test__/unit/entity.domain.spec.ts b/packages/policy-engine-shared/src/lib/util/__test__/unit/entity.util.spec.ts similarity index 99% rename from packages/policy-engine-shared/src/lib/domain/__test__/unit/entity.domain.spec.ts rename to packages/policy-engine-shared/src/lib/util/__test__/unit/entity.util.spec.ts index d3f4cccb7..38a07bd34 100644 --- a/packages/policy-engine-shared/src/lib/domain/__test__/unit/entity.domain.spec.ts +++ b/packages/policy-engine-shared/src/lib/util/__test__/unit/entity.util.spec.ts @@ -1,6 +1,6 @@ import { ADDRESS_BOOK, CREDENTIAL, TOKEN, USER, USER_GROUP, WALLET, WALLET_GROUP } from '../../../dev.fixture' import { AccountClassification, Entities } from '../../../type/entity.type' -import { validate } from '../../entity.domain' +import { validate } from '../../entity.util' describe('validate', () => { const emptyEntities: Entities = { diff --git a/packages/policy-engine-shared/src/lib/domain/entity.domain.ts b/packages/policy-engine-shared/src/lib/util/entity.util.ts similarity index 98% rename from packages/policy-engine-shared/src/lib/domain/entity.domain.ts rename to packages/policy-engine-shared/src/lib/util/entity.util.ts index 47231cebf..c86c80222 100644 --- a/packages/policy-engine-shared/src/lib/domain/entity.domain.ts +++ b/packages/policy-engine-shared/src/lib/util/entity.util.ts @@ -1,6 +1,6 @@ import { countBy, flatten, indexBy, keys, map, pickBy } from 'lodash/fp' import { Entities } from '../type/entity.type' -import { isAccountId, isAssetId } from '../util/caip.util' +import { isAccountId, isAssetId } from './caip.util' export type ValidationIssue = { code: string From 3356b3188877a51a94ce51134ae2e4c6ff029262 Mon Sep 17 00:00:00 2001 From: William Calderipe Date: Tue, 27 Feb 2024 17:37:13 +0100 Subject: [PATCH 4/9] Delete store module --- .../entity/__test__/e2e/address-book.spec.ts | 104 -------- .../entity/__test__/e2e/credential.spec.ts | 105 -------- .../store/entity/__test__/e2e/entity.spec.ts | 184 -------------- .../entity/__test__/e2e/organization.spec.ts | 117 --------- .../store/entity/__test__/e2e/token.spec.ts | 113 --------- .../entity/__test__/e2e/user-group.spec.ts | 121 ---------- .../entity/__test__/e2e/user-wallet.spec.ts | 127 ---------- .../store/entity/__test__/e2e/user.spec.ts | 224 ------------------ .../entity/__test__/e2e/wallet-group.spec.ts | 122 ---------- .../store/entity/__test__/e2e/wallet.spec.ts | 104 -------- .../core/service/address-book.service.ts | 12 - .../entity/core/service/credential.service.ts | 12 - .../entity/core/service/entity.service.ts | 44 ---- .../core/service/organization.service.ts | 41 ---- .../entity/core/service/token.service.ts | 12 - .../entity/core/service/user-group.service.ts | 31 --- .../store/entity/core/service/user.service.ts | 33 --- .../entity/core/service/wallet.service.ts | 29 --- .../src/store/entity/entity-store.constant.ts | 2 - .../src/store/entity/entity-store.module.ts | 79 ------ .../controller/address-book.controller.ts | 34 --- .../rest/controller/credential.controller.ts | 31 --- .../http/rest/controller/entity.controller.ts | 30 --- .../controller/organization.controller.ts | 30 --- .../http/rest/controller/token.controller.ts | 31 --- .../rest/controller/user-group.controller.ts | 35 --- .../rest/controller/user-wallet.controller.ts | 33 --- .../http/rest/controller/user.controller.ts | 58 ----- .../controller/wallet-group.controller.ts | 34 --- .../http/rest/controller/wallet.controller.ts | 31 --- .../http/rest/dto/address-book-account.dto.ts | 23 -- .../rest/dto/assign-user-group-request.dto.ts | 28 --- .../dto/assign-user-group-response.dto.ts | 16 -- .../dto/assign-user-wallet-request.dto.ts | 28 --- .../dto/assign-user-wallet-response.dto.ts | 16 -- .../dto/assign-wallet-group-request.dto.ts | 28 --- .../dto/assign-wallet-group-response.dto.ts | 16 -- .../http/rest/dto/auth-credential.dto.ts | 24 -- .../dto/create-address-book-request.dto.ts | 32 --- .../dto/create-address-book-response.dto.ts | 16 -- .../rest/dto/create-credential-request.dto.ts | 28 --- .../dto/create-credential-response.dto.ts | 16 -- .../dto/create-organization-request.dto.ts | 41 ---- .../dto/create-organization-response.dto.ts | 36 --- .../http/rest/dto/create-user-request.dto.ts | 45 ---- .../http/rest/dto/create-user-response.dto.ts | 16 -- .../entity/http/rest/dto/entities.dto.ts | 43 ---- .../rest/dto/register-tokens-request.dto.ts | 28 --- .../rest/dto/register-tokens-response.dto.ts | 16 -- .../rest/dto/register-wallet-request.dto.ts | 28 --- .../rest/dto/register-wallet-response.dto.ts | 16 -- .../http/rest/dto/request-signature.dto.ts | 19 -- .../store/entity/http/rest/dto/token.dto.ts | 33 --- .../http/rest/dto/update-user-request.dto.ts | 38 --- .../http/rest/dto/update-user-response.dto.ts | 16 -- .../rest/dto/user-group-membership.dto.ts | 18 -- .../entity/http/rest/dto/user-wallet.dto.ts | 18 -- .../store/entity/http/rest/dto/user.dto.ts | 18 -- .../rest/dto/wallet-group-membership.dto.ts | 18 -- .../entity/http/rest/dto/wallet-group.dto.ts | 14 -- .../store/entity/http/rest/dto/wallet.dto.ts | 30 --- .../store/entity/persistence/decode.util.ts | 14 -- .../entity/persistence/entity-store.seed.ts | 68 ------ .../repository/address-book.repository.ts | 49 ---- .../repository/credential.repository.ts | 49 ---- .../repository/organization.repository.ts | 20 -- .../repository/token.repository.ts | 29 --- .../repository/user-group.repository.ts | 54 ----- .../repository/user-wallet.repository.ts | 25 -- .../persistence/repository/user.repository.ts | 99 -------- .../repository/wallet-group.repository.ts | 60 ----- .../repository/wallet.repository.ts | 55 ----- apps/armory/src/store/store.module.ts | 7 - 73 files changed, 3254 deletions(-) delete mode 100644 apps/armory/src/store/entity/__test__/e2e/address-book.spec.ts delete mode 100644 apps/armory/src/store/entity/__test__/e2e/credential.spec.ts delete mode 100644 apps/armory/src/store/entity/__test__/e2e/entity.spec.ts delete mode 100644 apps/armory/src/store/entity/__test__/e2e/organization.spec.ts delete mode 100644 apps/armory/src/store/entity/__test__/e2e/token.spec.ts delete mode 100644 apps/armory/src/store/entity/__test__/e2e/user-group.spec.ts delete mode 100644 apps/armory/src/store/entity/__test__/e2e/user-wallet.spec.ts delete mode 100644 apps/armory/src/store/entity/__test__/e2e/user.spec.ts delete mode 100644 apps/armory/src/store/entity/__test__/e2e/wallet-group.spec.ts delete mode 100644 apps/armory/src/store/entity/__test__/e2e/wallet.spec.ts delete mode 100644 apps/armory/src/store/entity/core/service/address-book.service.ts delete mode 100644 apps/armory/src/store/entity/core/service/credential.service.ts delete mode 100644 apps/armory/src/store/entity/core/service/entity.service.ts delete mode 100644 apps/armory/src/store/entity/core/service/organization.service.ts delete mode 100644 apps/armory/src/store/entity/core/service/token.service.ts delete mode 100644 apps/armory/src/store/entity/core/service/user-group.service.ts delete mode 100644 apps/armory/src/store/entity/core/service/user.service.ts delete mode 100644 apps/armory/src/store/entity/core/service/wallet.service.ts delete mode 100644 apps/armory/src/store/entity/entity-store.constant.ts delete mode 100644 apps/armory/src/store/entity/entity-store.module.ts delete mode 100644 apps/armory/src/store/entity/http/rest/controller/address-book.controller.ts delete mode 100644 apps/armory/src/store/entity/http/rest/controller/credential.controller.ts delete mode 100644 apps/armory/src/store/entity/http/rest/controller/entity.controller.ts delete mode 100644 apps/armory/src/store/entity/http/rest/controller/organization.controller.ts delete mode 100644 apps/armory/src/store/entity/http/rest/controller/token.controller.ts delete mode 100644 apps/armory/src/store/entity/http/rest/controller/user-group.controller.ts delete mode 100644 apps/armory/src/store/entity/http/rest/controller/user-wallet.controller.ts delete mode 100644 apps/armory/src/store/entity/http/rest/controller/user.controller.ts delete mode 100644 apps/armory/src/store/entity/http/rest/controller/wallet-group.controller.ts delete mode 100644 apps/armory/src/store/entity/http/rest/controller/wallet.controller.ts delete mode 100644 apps/armory/src/store/entity/http/rest/dto/address-book-account.dto.ts delete mode 100644 apps/armory/src/store/entity/http/rest/dto/assign-user-group-request.dto.ts delete mode 100644 apps/armory/src/store/entity/http/rest/dto/assign-user-group-response.dto.ts delete mode 100644 apps/armory/src/store/entity/http/rest/dto/assign-user-wallet-request.dto.ts delete mode 100644 apps/armory/src/store/entity/http/rest/dto/assign-user-wallet-response.dto.ts delete mode 100644 apps/armory/src/store/entity/http/rest/dto/assign-wallet-group-request.dto.ts delete mode 100644 apps/armory/src/store/entity/http/rest/dto/assign-wallet-group-response.dto.ts delete mode 100644 apps/armory/src/store/entity/http/rest/dto/auth-credential.dto.ts delete mode 100644 apps/armory/src/store/entity/http/rest/dto/create-address-book-request.dto.ts delete mode 100644 apps/armory/src/store/entity/http/rest/dto/create-address-book-response.dto.ts delete mode 100644 apps/armory/src/store/entity/http/rest/dto/create-credential-request.dto.ts delete mode 100644 apps/armory/src/store/entity/http/rest/dto/create-credential-response.dto.ts delete mode 100644 apps/armory/src/store/entity/http/rest/dto/create-organization-request.dto.ts delete mode 100644 apps/armory/src/store/entity/http/rest/dto/create-organization-response.dto.ts delete mode 100644 apps/armory/src/store/entity/http/rest/dto/create-user-request.dto.ts delete mode 100644 apps/armory/src/store/entity/http/rest/dto/create-user-response.dto.ts delete mode 100644 apps/armory/src/store/entity/http/rest/dto/entities.dto.ts delete mode 100644 apps/armory/src/store/entity/http/rest/dto/register-tokens-request.dto.ts delete mode 100644 apps/armory/src/store/entity/http/rest/dto/register-tokens-response.dto.ts delete mode 100644 apps/armory/src/store/entity/http/rest/dto/register-wallet-request.dto.ts delete mode 100644 apps/armory/src/store/entity/http/rest/dto/register-wallet-response.dto.ts delete mode 100644 apps/armory/src/store/entity/http/rest/dto/request-signature.dto.ts delete mode 100644 apps/armory/src/store/entity/http/rest/dto/token.dto.ts delete mode 100644 apps/armory/src/store/entity/http/rest/dto/update-user-request.dto.ts delete mode 100644 apps/armory/src/store/entity/http/rest/dto/update-user-response.dto.ts delete mode 100644 apps/armory/src/store/entity/http/rest/dto/user-group-membership.dto.ts delete mode 100644 apps/armory/src/store/entity/http/rest/dto/user-wallet.dto.ts delete mode 100644 apps/armory/src/store/entity/http/rest/dto/user.dto.ts delete mode 100644 apps/armory/src/store/entity/http/rest/dto/wallet-group-membership.dto.ts delete mode 100644 apps/armory/src/store/entity/http/rest/dto/wallet-group.dto.ts delete mode 100644 apps/armory/src/store/entity/http/rest/dto/wallet.dto.ts delete mode 100644 apps/armory/src/store/entity/persistence/decode.util.ts delete mode 100644 apps/armory/src/store/entity/persistence/entity-store.seed.ts delete mode 100644 apps/armory/src/store/entity/persistence/repository/address-book.repository.ts delete mode 100644 apps/armory/src/store/entity/persistence/repository/credential.repository.ts delete mode 100644 apps/armory/src/store/entity/persistence/repository/organization.repository.ts delete mode 100644 apps/armory/src/store/entity/persistence/repository/token.repository.ts delete mode 100644 apps/armory/src/store/entity/persistence/repository/user-group.repository.ts delete mode 100644 apps/armory/src/store/entity/persistence/repository/user-wallet.repository.ts delete mode 100644 apps/armory/src/store/entity/persistence/repository/user.repository.ts delete mode 100644 apps/armory/src/store/entity/persistence/repository/wallet-group.repository.ts delete mode 100644 apps/armory/src/store/entity/persistence/repository/wallet.repository.ts delete mode 100644 apps/armory/src/store/store.module.ts diff --git a/apps/armory/src/store/entity/__test__/e2e/address-book.spec.ts b/apps/armory/src/store/entity/__test__/e2e/address-book.spec.ts deleted file mode 100644 index d74ce8baf..000000000 --- a/apps/armory/src/store/entity/__test__/e2e/address-book.spec.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { AccountClassification, Action, OrganizationEntity, Signature } from '@narval/policy-engine-shared' -import { HttpStatus, INestApplication } from '@nestjs/common' -import { ConfigModule } from '@nestjs/config' -import { Test, TestingModule } from '@nestjs/testing' -import request from 'supertest' -import { generateSignature } from '../../../../__test__/fixture/authorization-request.fixture' -import { load } from '../../../../armory.config' -import { REQUEST_HEADER_ORG_ID } from '../../../../armory.constant' -import { OrchestrationModule } from '../../../../orchestration/orchestration.module' -import { PersistenceModule } from '../../../../shared/module/persistence/persistence.module' -import { TestPrismaService } from '../../../../shared/module/persistence/service/test-prisma.service' -import { QueueModule } from '../../../../shared/module/queue/queue.module' -import { EntityStoreModule } from '../../entity-store.module' -import { AddressBookRepository } from '../../persistence/repository/address-book.repository' -import { OrganizationRepository } from '../../persistence/repository/organization.repository' - -const API_RESOURCE_USER_ENTITY = '/store/address-book' - -describe('Address Book Entity', () => { - let app: INestApplication - let module: TestingModule - let testPrismaService: TestPrismaService - let orgRepository: OrganizationRepository - let addressBookRepository: AddressBookRepository - - const organization: OrganizationEntity = { - uid: 'ac1374c2-fd62-4b6e-bd49-a4afcdcb91cc' - } - - const authentication: Signature = generateSignature() - - const approvals: Signature[] = [generateSignature(), generateSignature()] - - const nonce = 'b6d826b4-72cb-4c14-a6ca-235a2d8e9060' - - beforeAll(async () => { - module = await Test.createTestingModule({ - imports: [ - ConfigModule.forRoot({ - load: [load], - isGlobal: true - }), - PersistenceModule, - QueueModule.forRoot(), - OrchestrationModule, - EntityStoreModule - ] - }).compile() - - testPrismaService = module.get(TestPrismaService) - orgRepository = module.get(OrganizationRepository) - addressBookRepository = module.get(AddressBookRepository) - - app = module.createNestApplication() - - await app.init() - }) - - afterAll(async () => { - await testPrismaService.truncateAll() - await module.close() - await app.close() - }) - - beforeEach(async () => { - await orgRepository.create(organization.uid) - }) - - afterEach(async () => { - await testPrismaService.truncateAll() - }) - - describe(`POST ${API_RESOURCE_USER_ENTITY}`, () => { - it('registers a new account in the address book', async () => { - const account = { - uid: '089c131e-9507-412a-8b4a-45e6a8213d77', - address: '0xaaa8ee1cbaa1856f4550c6fc24abb16c5c9b2a43', - chainId: 1, - classification: AccountClassification.INTERNAL - } - - const payload = { - authentication, - approvals, - request: { - nonce, - action: Action.CREATE_ADDRESS_BOOK_ACCOUNT, - account - } - } - - const { status, body } = await request(app.getHttpServer()) - .post(API_RESOURCE_USER_ENTITY) - .set(REQUEST_HEADER_ORG_ID, organization.uid) - .send(payload) - - const actualAccount = await addressBookRepository.findById(account.uid) - - expect(body).toEqual({ account }) - expect(actualAccount).toEqual(account) - expect(status).toEqual(HttpStatus.CREATED) - }) - }) -}) diff --git a/apps/armory/src/store/entity/__test__/e2e/credential.spec.ts b/apps/armory/src/store/entity/__test__/e2e/credential.spec.ts deleted file mode 100644 index ea76baa17..000000000 --- a/apps/armory/src/store/entity/__test__/e2e/credential.spec.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { Action, Alg, CredentialEntity, OrganizationEntity, Signature } from '@narval/policy-engine-shared' -import { HttpStatus, INestApplication } from '@nestjs/common' -import { ConfigModule } from '@nestjs/config' -import { Test, TestingModule } from '@nestjs/testing' -import request from 'supertest' -import { sha256 } from 'viem' -import { generateSignature } from '../../../../__test__/fixture/authorization-request.fixture' -import { load } from '../../../../armory.config' -import { REQUEST_HEADER_ORG_ID } from '../../../../armory.constant' -import { OrchestrationModule } from '../../../../orchestration/orchestration.module' -import { PersistenceModule } from '../../../../shared/module/persistence/persistence.module' -import { TestPrismaService } from '../../../../shared/module/persistence/service/test-prisma.service' -import { QueueModule } from '../../../../shared/module/queue/queue.module' -import { EntityStoreModule } from '../../entity-store.module' -import { CredentialRepository } from '../../persistence/repository/credential.repository' -import { OrganizationRepository } from '../../persistence/repository/organization.repository' - -const API_RESOURCE_USER_ENTITY = '/store/credentials' - -describe('Credential Entity', () => { - let app: INestApplication - let module: TestingModule - let testPrismaService: TestPrismaService - let orgRepository: OrganizationRepository - let credentialRepository: CredentialRepository - - const organization: OrganizationEntity = { - uid: 'ac1374c2-fd62-4b6e-bd49-a4afcdcb91cc' - } - - const authentication: Signature = generateSignature() - - const approvals: Signature[] = [generateSignature(), generateSignature()] - - const nonce = 'b6d826b4-72cb-4c14-a6ca-235a2d8e9060' - - const credential: CredentialEntity = { - uid: sha256('0x501d5c2ce1ef208aadf9131a98baa593258cfa06'), - userId: '68182475-4365-4c4d-a7bd-295daad634c9', - alg: Alg.ES256K, - pubKey: '0x501d5c2ce1ef208aadf9131a98baa593258cfa06' - } - - beforeAll(async () => { - module = await Test.createTestingModule({ - imports: [ - ConfigModule.forRoot({ - load: [load], - isGlobal: true - }), - PersistenceModule, - QueueModule.forRoot(), - OrchestrationModule, - EntityStoreModule - ] - }).compile() - - testPrismaService = module.get(TestPrismaService) - orgRepository = module.get(OrganizationRepository) - credentialRepository = module.get(CredentialRepository) - - app = module.createNestApplication() - - await app.init() - }) - - afterAll(async () => { - await testPrismaService.truncateAll() - await module.close() - await app.close() - }) - - beforeEach(async () => { - await orgRepository.create(organization.uid) - }) - - afterEach(async () => { - await testPrismaService.truncateAll() - }) - - describe(`POST ${API_RESOURCE_USER_ENTITY}`, () => { - it('registers credential entity', async () => { - const payload = { - authentication, - approvals, - request: { - nonce, - action: Action.CREATE_CREDENTIAL, - credential - } - } - - const { status, body } = await request(app.getHttpServer()) - .post(API_RESOURCE_USER_ENTITY) - .set(REQUEST_HEADER_ORG_ID, organization.uid) - .send(payload) - - const actualCredential = await credentialRepository.findById(credential.uid) - - expect(body).toEqual({ credential }) - expect(actualCredential).toEqual(credential) - expect(status).toEqual(HttpStatus.CREATED) - }) - }) -}) diff --git a/apps/armory/src/store/entity/__test__/e2e/entity.spec.ts b/apps/armory/src/store/entity/__test__/e2e/entity.spec.ts deleted file mode 100644 index 9137b0345..000000000 --- a/apps/armory/src/store/entity/__test__/e2e/entity.spec.ts +++ /dev/null @@ -1,184 +0,0 @@ -import { - AddressBookAccountEntity, - CredentialEntity, - Entities, - FIXTURE, - OrganizationEntity, - TokenEntity, - UserEntity, - UserGroupEntity, - UserGroupMemberEntity, - UserWalletEntity, - WalletEntity, - WalletGroupEntity, - WalletGroupMemberEntity -} from '@narval/policy-engine-shared' -import { HttpStatus, INestApplication } from '@nestjs/common' -import { ConfigModule } from '@nestjs/config' -import { Test, TestingModule } from '@nestjs/testing' -import request from 'supertest' -import { load } from '../../../../armory.config' -import { REQUEST_HEADER_ORG_ID } from '../../../../armory.constant' -import { OrchestrationModule } from '../../../../orchestration/orchestration.module' -import { PersistenceModule } from '../../../../shared/module/persistence/persistence.module' -import { TestPrismaService } from '../../../../shared/module/persistence/service/test-prisma.service' -import { QueueModule } from '../../../../shared/module/queue/queue.module' -import { EntityStoreModule } from '../../entity-store.module' -import { AddressBookRepository } from '../../persistence/repository/address-book.repository' -import { CredentialRepository } from '../../persistence/repository/credential.repository' -import { OrganizationRepository } from '../../persistence/repository/organization.repository' -import { TokenRepository } from '../../persistence/repository/token.repository' -import { UserGroupRepository } from '../../persistence/repository/user-group.repository' -import { UserWalletRepository } from '../../persistence/repository/user-wallet.repository' -import { UserRepository } from '../../persistence/repository/user.repository' -import { WalletGroupRepository } from '../../persistence/repository/wallet-group.repository' -import { WalletRepository } from '../../persistence/repository/wallet.repository' - -const API_RESOURCE_USER_ENTITY = '/store/entities' - -describe('Entity', () => { - let app: INestApplication - let module: TestingModule - let testPrismaService: TestPrismaService - - let addressBookRepository: AddressBookRepository - let credentialRepository: CredentialRepository - let orgRepository: OrganizationRepository - let tokenRepository: TokenRepository - let userGroupRepository: UserGroupRepository - let userRepository: UserRepository - let userWalletRepository: UserWalletRepository - let walletGroupRepository: WalletGroupRepository - let walletRepository: WalletRepository - - const organization: OrganizationEntity = { - uid: 'ac1374c2-fd62-4b6e-bd49-a4afcdcb91cc' - } - - const addressBook: AddressBookAccountEntity[] = FIXTURE.ADDRESS_BOOK - const credentials: CredentialEntity[] = Object.values(FIXTURE.CREDENTIAL) - const tokens: TokenEntity[] = Object.values(FIXTURE.TOKEN) - const userGroupMembers: UserGroupMemberEntity[] = FIXTURE.USER_GROUP_MEMBER - const userGroups: UserGroupEntity[] = Object.values(FIXTURE.USER_GROUP) - const userWallets: UserWalletEntity[] = FIXTURE.USER_WALLET - const users: UserEntity[] = Object.values(FIXTURE.USER) - const walletGroupMembers: WalletGroupMemberEntity[] = FIXTURE.WALLET_GROUP_MEMBER - const walletGroups: WalletGroupEntity[] = Object.values(FIXTURE.WALLET_GROUP) - const wallets: WalletEntity[] = Object.values(FIXTURE.WALLET) - - const sortByUid = (entities: E[]): E[] => { - return entities.sort((a, b) => a.uid.localeCompare(b.uid)) - } - - const getDeterministicEntities = ({ - users, - wallets, - walletGroups, - userGroups, - addressBook, - credentials, - userGroupMembers, - userWallets, - walletGroupMembers - }: Entities): Entities => { - return { - addressBook: sortByUid(addressBook), - credentials: sortByUid(credentials), - tokens: sortByUid(tokens), - userGroupMembers: userGroupMembers.sort(), - userGroups: sortByUid(userGroups), - userWallets: userWallets.sort(), - users: sortByUid(users), - walletGroupMembers: walletGroupMembers.sort(), - walletGroups: sortByUid(walletGroups), - wallets: sortByUid(wallets) - } - } - - const bulkCreate = async ( - orgId: string, - entities: E[], - repository: { create: (orgId: string, entity: E) => Promise } - ): Promise => { - await Promise.all(entities.map((entity) => repository.create(orgId, entity))) - } - - beforeAll(async () => { - module = await Test.createTestingModule({ - imports: [ - ConfigModule.forRoot({ - load: [load], - isGlobal: true - }), - PersistenceModule, - QueueModule.forRoot(), - OrchestrationModule, - EntityStoreModule - ] - }).compile() - - testPrismaService = module.get(TestPrismaService) - - addressBookRepository = module.get(AddressBookRepository) - credentialRepository = module.get(CredentialRepository) - orgRepository = module.get(OrganizationRepository) - tokenRepository = module.get(TokenRepository) - userGroupRepository = module.get(UserGroupRepository) - userRepository = module.get(UserRepository) - userWalletRepository = module.get(UserWalletRepository) - walletGroupRepository = module.get(WalletGroupRepository) - walletRepository = module.get(WalletRepository) - - app = module.createNestApplication() - - await app.init() - }) - - afterAll(async () => { - await testPrismaService.truncateAll() - await module.close() - await app.close() - }) - - beforeEach(async () => { - await orgRepository.create(organization.uid) - await tokenRepository.create(organization.uid, tokens) - - // The order entities are created matters. - await bulkCreate(organization.uid, users, userRepository) - await bulkCreate(organization.uid, wallets, walletRepository) - await bulkCreate(organization.uid, walletGroups, walletGroupRepository) - await bulkCreate(organization.uid, userGroups, userGroupRepository) - await bulkCreate(organization.uid, addressBook, addressBookRepository) - await bulkCreate(organization.uid, userWallets, userWalletRepository) - await bulkCreate(organization.uid, credentials, credentialRepository) - }) - - afterEach(async () => { - await testPrismaService.truncateAll() - }) - - describe(`GET ${API_RESOURCE_USER_ENTITY}`, () => { - it('responds with the organization entities', async () => { - const { status, body } = await request(app.getHttpServer()) - .get(API_RESOURCE_USER_ENTITY) - .set(REQUEST_HEADER_ORG_ID, organization.uid) - - expect(getDeterministicEntities(body)).toEqual( - getDeterministicEntities({ - addressBook, - credentials, - tokens, - userGroupMembers, - userGroups, - userWallets, - users, - walletGroupMembers, - walletGroups, - wallets - }) - ) - expect(status).toEqual(HttpStatus.OK) - }) - }) -}) diff --git a/apps/armory/src/store/entity/__test__/e2e/organization.spec.ts b/apps/armory/src/store/entity/__test__/e2e/organization.spec.ts deleted file mode 100644 index 6587b97bb..000000000 --- a/apps/armory/src/store/entity/__test__/e2e/organization.spec.ts +++ /dev/null @@ -1,117 +0,0 @@ -import { Action, Alg, CredentialEntity, OrganizationEntity, Signature, UserRole } from '@narval/policy-engine-shared' -import { HttpStatus, INestApplication } from '@nestjs/common' -import { ConfigModule } from '@nestjs/config' -import { Test, TestingModule } from '@nestjs/testing' -import request from 'supertest' -import { sha256 } from 'viem' -import { generateSignature } from '../../../../__test__/fixture/authorization-request.fixture' -import { load } from '../../../../armory.config' -import { OrchestrationModule } from '../../../../orchestration/orchestration.module' -import { PersistenceModule } from '../../../../shared/module/persistence/persistence.module' -import { TestPrismaService } from '../../../../shared/module/persistence/service/test-prisma.service' -import { QueueModule } from '../../../../shared/module/queue/queue.module' -import { EntityStoreModule } from '../../entity-store.module' -import { CredentialRepository } from '../../persistence/repository/credential.repository' -import { OrganizationRepository } from '../../persistence/repository/organization.repository' -import { UserRepository } from '../../persistence/repository/user.repository' - -const API_RESOURCE_USER_ENTITY = '/store/organizations' - -describe('Organization Entity', () => { - let app: INestApplication - let module: TestingModule - let testPrismaService: TestPrismaService - let orgRepository: OrganizationRepository - let userRepository: UserRepository - let authCredentialRepository: CredentialRepository - - const organization: OrganizationEntity = { - uid: 'ac1374c2-fd62-4b6e-bd49-a4afcdcb91cc' - } - - const nonce = 'b6d826b4-72cb-4c14-a6ca-235a2d8e9060' - - const authentication: Signature = generateSignature() - - const approvals: Signature[] = [generateSignature(), generateSignature()] - - const credential: CredentialEntity = { - uid: sha256('0x501d5c2ce1ef208aadf9131a98baa593258cfa06'), - userId: '68182475-4365-4c4d-a7bd-295daad634c9', - alg: Alg.ES256K, - pubKey: '0x501d5c2ce1ef208aadf9131a98baa593258cfa06' - } - - beforeAll(async () => { - module = await Test.createTestingModule({ - imports: [ - ConfigModule.forRoot({ - load: [load], - isGlobal: true - }), - PersistenceModule, - QueueModule.forRoot(), - OrchestrationModule, - EntityStoreModule - ] - }).compile() - - testPrismaService = module.get(TestPrismaService) - orgRepository = module.get(OrganizationRepository) - userRepository = module.get(UserRepository) - authCredentialRepository = module.get(CredentialRepository) - - app = module.createNestApplication() - - await app.init() - }) - - afterAll(async () => { - await testPrismaService.truncateAll() - await module.close() - await app.close() - }) - - afterEach(async () => { - await testPrismaService.truncateAll() - }) - - describe(`POST ${API_RESOURCE_USER_ENTITY}`, () => { - it('creates organization and root user', async () => { - const payload = { - authentication, - approvals, - request: { - action: Action.CREATE_ORGANIZATION, - nonce, - organization: { - uid: organization.uid, - credential - } - } - } - - const expectedRootUser = { - uid: credential.userId, - role: UserRole.ROOT - } - - const { status, body } = await request(app.getHttpServer()).post(API_RESOURCE_USER_ENTITY).send(payload) - - const actualOrganization = await orgRepository.findById(organization.uid) - const actualRootUser = await userRepository.findById(credential.userId) - const actualCredential = await authCredentialRepository.findById(credential.uid) - - expect(body).toEqual({ - organization, - rootCredential: credential, - rootUser: expectedRootUser - }) - expect(status).toEqual(HttpStatus.CREATED) - - expect(actualOrganization).toEqual(organization) - expect(actualCredential).toEqual(credential) - expect(actualRootUser).toEqual(expectedRootUser) - }) - }) -}) diff --git a/apps/armory/src/store/entity/__test__/e2e/token.spec.ts b/apps/armory/src/store/entity/__test__/e2e/token.spec.ts deleted file mode 100644 index 3a37a3b1a..000000000 --- a/apps/armory/src/store/entity/__test__/e2e/token.spec.ts +++ /dev/null @@ -1,113 +0,0 @@ -import { Action, OrganizationEntity, Signature, TokenEntity } from '@narval/policy-engine-shared' -import { HttpStatus, INestApplication } from '@nestjs/common' -import { ConfigModule } from '@nestjs/config' -import { Test, TestingModule } from '@nestjs/testing' -import request from 'supertest' -import { generateSignature } from '../../../../__test__/fixture/authorization-request.fixture' -import { load } from '../../../../armory.config' -import { REQUEST_HEADER_ORG_ID } from '../../../../armory.constant' -import { OrchestrationModule } from '../../../../orchestration/orchestration.module' -import { PersistenceModule } from '../../../../shared/module/persistence/persistence.module' -import { TestPrismaService } from '../../../../shared/module/persistence/service/test-prisma.service' -import { QueueModule } from '../../../../shared/module/queue/queue.module' -import { EntityStoreModule } from '../../entity-store.module' -import { OrganizationRepository } from '../../persistence/repository/organization.repository' -import { TokenRepository } from '../../persistence/repository/token.repository' - -const API_RESOURCE_USER_ENTITY = '/store/tokens' - -describe('Token Entity', () => { - let app: INestApplication - let module: TestingModule - let testPrismaService: TestPrismaService - let orgRepository: OrganizationRepository - let tokenRepository: TokenRepository - - const organization: OrganizationEntity = { - uid: 'ac1374c2-fd62-4b6e-bd49-a4afcdcb91cc' - } - - const authentication: Signature = generateSignature() - - const approvals: Signature[] = [generateSignature(), generateSignature()] - - const nonce = 'b6d826b4-72cb-4c14-a6ca-235a2d8e9060' - - beforeAll(async () => { - module = await Test.createTestingModule({ - imports: [ - ConfigModule.forRoot({ - load: [load], - isGlobal: true - }), - PersistenceModule, - QueueModule.forRoot(), - OrchestrationModule, - EntityStoreModule - ] - }).compile() - - testPrismaService = module.get(TestPrismaService) - orgRepository = module.get(OrganizationRepository) - tokenRepository = module.get(TokenRepository) - - app = module.createNestApplication() - - await app.init() - }) - - afterAll(async () => { - await testPrismaService.truncateAll() - await module.close() - await app.close() - }) - - beforeEach(async () => { - await orgRepository.create(organization.uid) - }) - - afterEach(async () => { - await testPrismaService.truncateAll() - }) - - describe(`POST ${API_RESOURCE_USER_ENTITY}`, () => { - it('registers new tokens', async () => { - const tokenOne: TokenEntity = { - uid: '2ece731a-51be-4b4f-91de-5665eacf7006', - address: '0x63d74e23f70f66511417bc7acf95f002d1dbd33c', - chainId: 1, - symbol: 'AAA', - decimals: 18 - } - - const tokenTwo: TokenEntity = { - uid: '50972056-fb28-4701-a2b6-b784a7d23e70', - address: '0x33a184D851506C23d7B97f3d8d062483B9Cf495c', - chainId: 1, - symbol: 'BBB', - decimals: 18 - } - - const payload = { - authentication, - approvals, - request: { - action: Action.REGISTER_TOKENS, - nonce, - tokens: [tokenOne, tokenTwo] - } - } - - const { status, body } = await request(app.getHttpServer()) - .post(API_RESOURCE_USER_ENTITY) - .set(REQUEST_HEADER_ORG_ID, organization.uid) - .send(payload) - - const actualTokens = await tokenRepository.findByOrgId(organization.uid) - - expect(body).toEqual({ tokens: [tokenOne, tokenTwo] }) - expect(actualTokens).toEqual([tokenOne, tokenTwo]) - expect(status).toEqual(HttpStatus.CREATED) - }) - }) -}) diff --git a/apps/armory/src/store/entity/__test__/e2e/user-group.spec.ts b/apps/armory/src/store/entity/__test__/e2e/user-group.spec.ts deleted file mode 100644 index 6dfc11b98..000000000 --- a/apps/armory/src/store/entity/__test__/e2e/user-group.spec.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { Action, Signature, UserRole } from '@narval/policy-engine-shared' -import { HttpStatus, INestApplication } from '@nestjs/common' -import { ConfigModule } from '@nestjs/config' -import { Test, TestingModule } from '@nestjs/testing' -import { Organization } from '@prisma/client/armory' -import request from 'supertest' -import { generateSignature } from '../../../../__test__/fixture/authorization-request.fixture' -import { load } from '../../../../armory.config' -import { REQUEST_HEADER_ORG_ID } from '../../../../armory.constant' -import { OrchestrationModule } from '../../../../orchestration/orchestration.module' -import { PersistenceModule } from '../../../../shared/module/persistence/persistence.module' -import { TestPrismaService } from '../../../../shared/module/persistence/service/test-prisma.service' -import { QueueModule } from '../../../../shared/module/queue/queue.module' -import { EntityStoreModule } from '../../entity-store.module' -import { UserGroupRepository } from '../../persistence/repository/user-group.repository' -import { UserRepository } from '../../persistence/repository/user.repository' - -const API_RESOURCE_USER_ENTITY = '/store/user-groups' - -describe('User Group Entity', () => { - let app: INestApplication - let module: TestingModule - let testPrismaService: TestPrismaService - let userRepository: UserRepository - let userGroupRepository: UserGroupRepository - - const org: Organization = { - id: 'ac1374c2-fd62-4b6e-bd49-a4afcdcb91cc', - name: 'Test Evaluation', - createdAt: new Date(), - updatedAt: new Date() - } - - const authentication: Signature = generateSignature() - - const approvals: Signature[] = [generateSignature(), generateSignature()] - - const user = { - uid: '68182475-4365-4c4d-a7bd-295daad634c9', - role: UserRole.MEMBER - } - - const nonce = 'b6d826b4-72cb-4c14-a6ca-235a2d8e9060' - - const groupId = '2a1509ad-ea87-422e-bebd-974547cd4fee' - - beforeAll(async () => { - module = await Test.createTestingModule({ - imports: [ - ConfigModule.forRoot({ - load: [load], - isGlobal: true - }), - PersistenceModule, - QueueModule.forRoot(), - OrchestrationModule, - EntityStoreModule - ] - }).compile() - - testPrismaService = module.get(TestPrismaService) - userRepository = module.get(UserRepository) - userGroupRepository = module.get(UserGroupRepository) - - app = module.createNestApplication() - - await app.init() - }) - - afterAll(async () => { - await testPrismaService.truncateAll() - await module.close() - await app.close() - }) - - beforeEach(async () => { - await testPrismaService.getClient().organization.create({ data: org }) - await userRepository.create(org.id, user) - }) - - afterEach(async () => { - await testPrismaService.truncateAll() - }) - - describe(`POST ${API_RESOURCE_USER_ENTITY}`, () => { - it('assigns a user to a group', async () => { - const payload = { - authentication, - approvals, - request: { - action: Action.ASSIGN_USER_GROUP, - nonce, - data: { - userId: user.uid, - groupId - } - } - } - - const { status, body } = await request(app.getHttpServer()) - .post(API_RESOURCE_USER_ENTITY) - .set(REQUEST_HEADER_ORG_ID, org.id) - .send(payload) - - const group = await userGroupRepository.findById(groupId) - - expect(body).toEqual({ - data: { - userId: user.uid, - groupId - } - }) - - expect(group).toEqual({ - uid: groupId, - users: [user.uid] - }) - expect(status).toEqual(HttpStatus.CREATED) - }) - }) -}) diff --git a/apps/armory/src/store/entity/__test__/e2e/user-wallet.spec.ts b/apps/armory/src/store/entity/__test__/e2e/user-wallet.spec.ts deleted file mode 100644 index 63a77176d..000000000 --- a/apps/armory/src/store/entity/__test__/e2e/user-wallet.spec.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { - AccountType, - Action, - OrganizationEntity, - Signature, - UserEntity, - UserRole, - WalletEntity -} from '@narval/policy-engine-shared' -import { HttpStatus, INestApplication } from '@nestjs/common' -import { ConfigModule } from '@nestjs/config' -import { Test, TestingModule } from '@nestjs/testing' -import request from 'supertest' -import { generateSignature } from '../../../../__test__/fixture/authorization-request.fixture' -import { load } from '../../../../armory.config' -import { REQUEST_HEADER_ORG_ID } from '../../../../armory.constant' -import { OrchestrationModule } from '../../../../orchestration/orchestration.module' -import { PersistenceModule } from '../../../../shared/module/persistence/persistence.module' -import { TestPrismaService } from '../../../../shared/module/persistence/service/test-prisma.service' -import { QueueModule } from '../../../../shared/module/queue/queue.module' -import { EntityStoreModule } from '../../entity-store.module' -import { OrganizationRepository } from '../../persistence/repository/organization.repository' -import { UserRepository } from '../../persistence/repository/user.repository' -import { WalletRepository } from '../../persistence/repository/wallet.repository' - -const API_RESOURCE_USER_ENTITY = '/store/user-wallets' - -describe('User Wallet Entity', () => { - let app: INestApplication - let module: TestingModule - let testPrismaService: TestPrismaService - let orgRepository: OrganizationRepository - let walletRepository: WalletRepository - let userRepository: UserRepository - - const organization: OrganizationEntity = { - uid: 'ac1374c2-fd62-4b6e-bd49-a4afcdcb91cc' - } - - const authentication: Signature = generateSignature() - - const approvals: Signature[] = [generateSignature(), generateSignature()] - - const nonce = 'b6d826b4-72cb-4c14-a6ca-235a2d8e9060' - - const wallet: WalletEntity = { - uid: 'a5c1fd4e-b021-4fad-b5a6-256b434916ef', - address: '0x648edbd0e1bd5f15d58481bc7f034a790f9741fe', - accountType: AccountType.EOA, - chainId: 1 - } - - const user: UserEntity = { - uid: '2d7a6811-509f-4bee-90fb-e382fc127de5', - role: UserRole.ADMIN - } - - beforeAll(async () => { - module = await Test.createTestingModule({ - imports: [ - ConfigModule.forRoot({ - load: [load], - isGlobal: true - }), - PersistenceModule, - QueueModule.forRoot(), - OrchestrationModule, - EntityStoreModule - ] - }).compile() - - orgRepository = module.get(OrganizationRepository) - testPrismaService = module.get(TestPrismaService) - userRepository = module.get(UserRepository) - walletRepository = module.get(WalletRepository) - - app = module.createNestApplication() - - await app.init() - }) - - afterAll(async () => { - await testPrismaService.truncateAll() - await module.close() - await app.close() - }) - - beforeEach(async () => { - await orgRepository.create(organization.uid) - await walletRepository.create(organization.uid, wallet) - await userRepository.create(organization.uid, user) - }) - - afterEach(async () => { - await testPrismaService.truncateAll() - }) - - describe(`POST ${API_RESOURCE_USER_ENTITY}`, () => { - it('assigns a wallet to a user', async () => { - const payload = { - authentication, - approvals, - request: { - nonce, - action: Action.ASSIGN_USER_WALLET, - data: { - userId: user.uid, - walletId: wallet.uid - } - } - } - - const { status, body } = await request(app.getHttpServer()) - .post(API_RESOURCE_USER_ENTITY) - .set(REQUEST_HEADER_ORG_ID, organization.uid) - .send(payload) - - expect(body).toEqual({ - data: { - userId: user.uid, - walletId: wallet.uid - } - }) - expect(status).toEqual(HttpStatus.CREATED) - }) - }) -}) diff --git a/apps/armory/src/store/entity/__test__/e2e/user.spec.ts b/apps/armory/src/store/entity/__test__/e2e/user.spec.ts deleted file mode 100644 index 7133910e3..000000000 --- a/apps/armory/src/store/entity/__test__/e2e/user.spec.ts +++ /dev/null @@ -1,224 +0,0 @@ -import { Action, Alg, CredentialEntity, Signature, UserEntity, UserRole } from '@narval/policy-engine-shared' -import { HttpStatus, INestApplication } from '@nestjs/common' -import { ConfigModule } from '@nestjs/config' -import { Test, TestingModule } from '@nestjs/testing' -import { Organization } from '@prisma/client/armory' -import request from 'supertest' -import { sha256 } from 'viem' -import { generateSignature } from '../../../../__test__/fixture/authorization-request.fixture' -import { load } from '../../../../armory.config' -import { REQUEST_HEADER_ORG_ID } from '../../../../armory.constant' -import { OrchestrationModule } from '../../../../orchestration/orchestration.module' -import { PersistenceModule } from '../../../../shared/module/persistence/persistence.module' -import { TestPrismaService } from '../../../../shared/module/persistence/service/test-prisma.service' -import { QueueModule } from '../../../../shared/module/queue/queue.module' -import { EntityStoreModule } from '../../entity-store.module' -import { CredentialRepository } from '../../persistence/repository/credential.repository' -import { UserRepository } from '../../persistence/repository/user.repository' - -const API_RESOURCE_USER_ENTITY = '/store/users' - -describe('User Entity', () => { - let app: INestApplication - let module: TestingModule - let testPrismaService: TestPrismaService - let userRepository: UserRepository - let authCredentialRepository: CredentialRepository - - const org: Organization = { - id: 'ac1374c2-fd62-4b6e-bd49-a4afcdcb91cc', - name: 'Test Evaluation', - createdAt: new Date(), - updatedAt: new Date() - } - - const authentication: Signature = generateSignature() - - const approvals: Signature[] = [generateSignature(), generateSignature()] - - const user: UserEntity = { - uid: '68182475-4365-4c4d-a7bd-295daad634c9', - role: UserRole.MEMBER - } - - const nonce = 'b6d826b4-72cb-4c14-a6ca-235a2d8e9060' - - const credential: CredentialEntity = { - uid: sha256('0x501d5c2ce1ef208aadf9131a98baa593258cfa06'), - userId: '68182475-4365-4c4d-a7bd-295daad634c9', - alg: Alg.ES256K, - pubKey: '0x501d5c2ce1ef208aadf9131a98baa593258cfa06' - } - - beforeAll(async () => { - module = await Test.createTestingModule({ - imports: [ - ConfigModule.forRoot({ - load: [load], - isGlobal: true - }), - PersistenceModule, - QueueModule.forRoot(), - OrchestrationModule, - EntityStoreModule - ] - }).compile() - - testPrismaService = module.get(TestPrismaService) - userRepository = module.get(UserRepository) - authCredentialRepository = module.get(CredentialRepository) - - app = module.createNestApplication() - - await app.init() - }) - - afterAll(async () => { - await testPrismaService.truncateAll() - await module.close() - await app.close() - }) - - beforeEach(async () => { - await testPrismaService.getClient().organization.create({ data: org }) - }) - - afterEach(async () => { - await testPrismaService.truncateAll() - }) - - describe(`POST ${API_RESOURCE_USER_ENTITY}`, () => { - it('creates user entity with credential', async () => { - const payload = { - authentication, - approvals, - request: { - action: Action.CREATE_USER, - nonce, - user: { - ...user, - credential - } - } - } - - const { status, body } = await request(app.getHttpServer()) - .post(API_RESOURCE_USER_ENTITY) - .set(REQUEST_HEADER_ORG_ID, org.id) - .send(payload) - - const actualUser = await userRepository.findById(user.uid) - const actualCredential = await authCredentialRepository.findById(credential.uid) - - expect(status).toEqual(HttpStatus.CREATED) - expect(body).toEqual({ user }) - - expect(actualUser).toEqual(user) - expect(actualCredential).toEqual(credential) - }) - - it('creates user entity without credential', async () => { - const payload = { - authentication, - approvals, - request: { - action: Action.CREATE_USER, - nonce, - user - } - } - - const { status, body } = await request(app.getHttpServer()) - .post(API_RESOURCE_USER_ENTITY) - .set(REQUEST_HEADER_ORG_ID, org.id) - .send(payload) - - const actualUser = await userRepository.findById(user.uid) - const actualCredential = await authCredentialRepository.findById(credential.uid) - - expect(status).toEqual(HttpStatus.CREATED) - expect(body).toEqual({ user }) - - expect(actualUser).toEqual(user) - expect(actualCredential).toEqual(null) - }) - - it('responds with error on user entity duplication', async () => { - const payload = { - authentication, - approvals, - request: { - action: Action.CREATE_USER, - nonce, - user - } - } - - const { status: firstResponseStatus, body: firstResponseBody } = await request(app.getHttpServer()) - .post(API_RESOURCE_USER_ENTITY) - .set(REQUEST_HEADER_ORG_ID, org.id) - .send(payload) - - const { status: secondResponseStatus, body: secondResponseBody } = await request(app.getHttpServer()) - .post(API_RESOURCE_USER_ENTITY) - .set(REQUEST_HEADER_ORG_ID, org.id) - .send(payload) - - expect(firstResponseBody).toEqual({ user }) - expect(firstResponseStatus).toEqual(HttpStatus.CREATED) - - expect(secondResponseBody).toEqual({ - statusCode: HttpStatus.INTERNAL_SERVER_ERROR, - message: 'Internal server error' - }) - expect(secondResponseStatus).toEqual(HttpStatus.INTERNAL_SERVER_ERROR) - }) - }) - - describe(`PATCH ${API_RESOURCE_USER_ENTITY}/:uid`, () => { - it('updates user entity', async () => { - const create = { - authentication, - approvals, - request: { - action: Action.CREATE_USER, - nonce, - user - } - } - - const update = { - authentication, - approvals, - request: { - action: Action.UPDATE_USER, - nonce, - user: { - ...user, - role: UserRole.MANAGER - } - } - } - - const { status: createResponseStatus } = await request(app.getHttpServer()) - .post(API_RESOURCE_USER_ENTITY) - .set(REQUEST_HEADER_ORG_ID, org.id) - .send(create) - - const { status: updateResponseStatus, body: updateResponseBody } = await request(app.getHttpServer()) - .patch(`${API_RESOURCE_USER_ENTITY}/${user.uid}`) - .set(REQUEST_HEADER_ORG_ID, org.id) - .send(update) - - expect(createResponseStatus).toEqual(HttpStatus.CREATED) - - expect(updateResponseBody).toEqual({ - user: { - uid: user.uid, - role: update.request.user.role - } - }) - expect(updateResponseStatus).toEqual(HttpStatus.OK) - }) - }) -}) diff --git a/apps/armory/src/store/entity/__test__/e2e/wallet-group.spec.ts b/apps/armory/src/store/entity/__test__/e2e/wallet-group.spec.ts deleted file mode 100644 index 5216eb920..000000000 --- a/apps/armory/src/store/entity/__test__/e2e/wallet-group.spec.ts +++ /dev/null @@ -1,122 +0,0 @@ -import { AccountType, Action, OrganizationEntity, Signature, WalletEntity } from '@narval/policy-engine-shared' -import { HttpStatus, INestApplication } from '@nestjs/common' -import { ConfigModule } from '@nestjs/config' -import { Test, TestingModule } from '@nestjs/testing' -import request from 'supertest' -import { generateSignature } from '../../../../__test__/fixture/authorization-request.fixture' -import { load } from '../../../../armory.config' -import { REQUEST_HEADER_ORG_ID } from '../../../../armory.constant' -import { OrchestrationModule } from '../../../../orchestration/orchestration.module' -import { PersistenceModule } from '../../../../shared/module/persistence/persistence.module' -import { TestPrismaService } from '../../../../shared/module/persistence/service/test-prisma.service' -import { QueueModule } from '../../../../shared/module/queue/queue.module' -import { EntityStoreModule } from '../../entity-store.module' -import { OrganizationRepository } from '../../persistence/repository/organization.repository' -import { WalletGroupRepository } from '../../persistence/repository/wallet-group.repository' -import { WalletRepository } from '../../persistence/repository/wallet.repository' - -const API_RESOURCE_USER_ENTITY = '/store/wallet-groups' - -describe('Wallet Group Entity', () => { - let app: INestApplication - let module: TestingModule - let testPrismaService: TestPrismaService - let orgRepository: OrganizationRepository - let walletGroupRepository: WalletGroupRepository - let walletRepository: WalletRepository - - const organization: OrganizationEntity = { - uid: 'ac1374c2-fd62-4b6e-bd49-a4afcdcb91cc' - } - - const authentication: Signature = generateSignature() - - const approvals: Signature[] = [generateSignature(), generateSignature()] - - const nonce = 'b6d826b4-72cb-4c14-a6ca-235a2d8e9060' - - const wallet: WalletEntity = { - uid: 'a5c1fd4e-b021-4fad-b5a6-256b434916ef', - address: '0x648edbd0e1bd5f15d58481bc7f034a790f9741fe', - accountType: AccountType.EOA, - chainId: 1 - } - - const groupId = '2a1509ad-ea87-422e-bebd-974547cd4fee' - - beforeAll(async () => { - module = await Test.createTestingModule({ - imports: [ - ConfigModule.forRoot({ - load: [load], - isGlobal: true - }), - PersistenceModule, - QueueModule.forRoot(), - OrchestrationModule, - EntityStoreModule - ] - }).compile() - - testPrismaService = module.get(TestPrismaService) - orgRepository = module.get(OrganizationRepository) - walletRepository = module.get(WalletRepository) - walletGroupRepository = module.get(WalletGroupRepository) - - app = module.createNestApplication() - - await app.init() - }) - - afterAll(async () => { - await testPrismaService.truncateAll() - await module.close() - await app.close() - }) - - beforeEach(async () => { - await orgRepository.create(organization.uid) - await walletRepository.create(organization.uid, wallet) - }) - - afterEach(async () => { - await testPrismaService.truncateAll() - }) - - describe(`POST ${API_RESOURCE_USER_ENTITY}`, () => { - it('assigns a wallet to a group', async () => { - const payload = { - authentication, - approvals, - request: { - action: Action.ASSIGN_WALLET_GROUP, - nonce, - data: { - groupId, - walletId: wallet.uid - } - } - } - - const { status, body } = await request(app.getHttpServer()) - .post(API_RESOURCE_USER_ENTITY) - .set(REQUEST_HEADER_ORG_ID, organization.uid) - .send(payload) - - const actualGroup = await walletGroupRepository.findById(groupId) - - expect(body).toEqual({ - data: { - groupId, - walletId: wallet.uid - } - }) - expect(status).toEqual(HttpStatus.CREATED) - - expect(actualGroup).toEqual({ - uid: groupId, - wallets: [wallet.uid] - }) - }) - }) -}) diff --git a/apps/armory/src/store/entity/__test__/e2e/wallet.spec.ts b/apps/armory/src/store/entity/__test__/e2e/wallet.spec.ts deleted file mode 100644 index 97401e471..000000000 --- a/apps/armory/src/store/entity/__test__/e2e/wallet.spec.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { AccountType, Action, OrganizationEntity, Signature } from '@narval/policy-engine-shared' -import { HttpStatus, INestApplication } from '@nestjs/common' -import { ConfigModule } from '@nestjs/config' -import { Test, TestingModule } from '@nestjs/testing' -import request from 'supertest' -import { generateSignature } from '../../../../__test__/fixture/authorization-request.fixture' -import { load } from '../../../../armory.config' -import { REQUEST_HEADER_ORG_ID } from '../../../../armory.constant' -import { OrchestrationModule } from '../../../../orchestration/orchestration.module' -import { PersistenceModule } from '../../../../shared/module/persistence/persistence.module' -import { TestPrismaService } from '../../../../shared/module/persistence/service/test-prisma.service' -import { QueueModule } from '../../../../shared/module/queue/queue.module' -import { EntityStoreModule } from '../../entity-store.module' -import { OrganizationRepository } from '../../persistence/repository/organization.repository' -import { WalletRepository } from '../../persistence/repository/wallet.repository' - -const API_RESOURCE_USER_ENTITY = '/store/wallets' - -describe('Wallet Entity', () => { - let app: INestApplication - let module: TestingModule - let testPrismaService: TestPrismaService - let orgRepository: OrganizationRepository - let walletRepository: WalletRepository - - const organization: OrganizationEntity = { - uid: 'ac1374c2-fd62-4b6e-bd49-a4afcdcb91cc' - } - - const nonce = 'b6d826b4-72cb-4c14-a6ca-235a2d8e9060' - - const authentication: Signature = generateSignature() - - const approvals: Signature[] = [generateSignature(), generateSignature()] - - beforeAll(async () => { - module = await Test.createTestingModule({ - imports: [ - ConfigModule.forRoot({ - load: [load], - isGlobal: true - }), - PersistenceModule, - QueueModule.forRoot(), - OrchestrationModule, - EntityStoreModule - ] - }).compile() - - testPrismaService = module.get(TestPrismaService) - orgRepository = module.get(OrganizationRepository) - walletRepository = module.get(WalletRepository) - - app = module.createNestApplication() - - await app.init() - }) - - afterAll(async () => { - await testPrismaService.truncateAll() - await module.close() - await app.close() - }) - - beforeEach(async () => { - await orgRepository.create(organization.uid) - }) - - afterEach(async () => { - await testPrismaService.truncateAll() - }) - - describe(`POST ${API_RESOURCE_USER_ENTITY}`, () => { - it('creates a new wallet entity', async () => { - const wallet = { - uid: 'a5c1fd4e-b021-4fad-b5a6-256b434916ef', - address: '0x648edbd0e1bd5f15d58481bc7f034a790f9741fe', - accountType: AccountType.EOA, - chainId: 1 - } - - const payload = { - authentication, - approvals, - request: { - action: Action.REGISTER_WALLET, - nonce, - wallet - } - } - - const { status, body } = await request(app.getHttpServer()) - .post(API_RESOURCE_USER_ENTITY) - .set(REQUEST_HEADER_ORG_ID, organization.uid) - .send(payload) - - const actualWallet = await walletRepository.findById(wallet.uid) - - expect(body).toEqual({ wallet }) - expect(status).toEqual(HttpStatus.CREATED) - expect(actualWallet).toEqual(wallet) - }) - }) -}) diff --git a/apps/armory/src/store/entity/core/service/address-book.service.ts b/apps/armory/src/store/entity/core/service/address-book.service.ts deleted file mode 100644 index 4a0b4203a..000000000 --- a/apps/armory/src/store/entity/core/service/address-book.service.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { AddressBookAccountEntity, CreateAddressBookAccountRequest } from '@narval/policy-engine-shared' -import { Injectable } from '@nestjs/common' -import { AddressBookRepository } from '../../persistence/repository/address-book.repository' - -@Injectable() -export class AddressBookService { - constructor(private addressBookRepository: AddressBookRepository) {} - - create(orgId: string, data: CreateAddressBookAccountRequest): Promise { - return this.addressBookRepository.create(orgId, data.request.account) - } -} diff --git a/apps/armory/src/store/entity/core/service/credential.service.ts b/apps/armory/src/store/entity/core/service/credential.service.ts deleted file mode 100644 index 5250f8969..000000000 --- a/apps/armory/src/store/entity/core/service/credential.service.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { CreateCredentialRequest, CredentialEntity } from '@narval/policy-engine-shared' -import { Injectable } from '@nestjs/common' -import { CredentialRepository } from '../../persistence/repository/credential.repository' - -@Injectable() -export class CredentialService { - constructor(private credentialRepository: CredentialRepository) {} - - create(orgId: string, data: CreateCredentialRequest): Promise { - return this.credentialRepository.create(orgId, data.request.credential) - } -} diff --git a/apps/armory/src/store/entity/core/service/entity.service.ts b/apps/armory/src/store/entity/core/service/entity.service.ts deleted file mode 100644 index a7a9facb9..000000000 --- a/apps/armory/src/store/entity/core/service/entity.service.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { Entities } from '@narval/policy-engine-shared' -import { Injectable } from '@nestjs/common' -import { AddressBookRepository } from '../../persistence/repository/address-book.repository' -import { CredentialRepository } from '../../persistence/repository/credential.repository' -import { TokenRepository } from '../../persistence/repository/token.repository' -import { UserGroupRepository } from '../../persistence/repository/user-group.repository' -import { UserRepository } from '../../persistence/repository/user.repository' -import { WalletGroupRepository } from '../../persistence/repository/wallet-group.repository' -import { WalletRepository } from '../../persistence/repository/wallet.repository' - -@Injectable() -export class EntityService { - constructor( - private addressBookRepository: AddressBookRepository, - private credentialRepository: CredentialRepository, - private tokenRepository: TokenRepository, - private userGroupRepository: UserGroupRepository, - private userRepository: UserRepository, - private walletGroupRepository: WalletGroupRepository, - private walletRepository: WalletRepository - ) {} - - async getEntities(orgId: string): Promise { - const [addressBook, credentials, tokens, userGroups, users, walletGroups, wallets] = await Promise.all([ - this.addressBookRepository.findByOrgId(orgId), - this.credentialRepository.findByOrgId(orgId), - this.tokenRepository.findByOrgId(orgId), - this.userGroupRepository.findByOrgId(orgId), - this.userRepository.findByOrgId(orgId), - this.walletGroupRepository.findByOrgId(orgId), - this.walletRepository.findByOrgId(orgId) - ]) - - return { - addressBook, - credentials, - tokens, - userGroups, - users, - walletGroups, - wallets - } - } -} diff --git a/apps/armory/src/store/entity/core/service/organization.service.ts b/apps/armory/src/store/entity/core/service/organization.service.ts deleted file mode 100644 index e5a0a61b5..000000000 --- a/apps/armory/src/store/entity/core/service/organization.service.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { - CreateOrganizationRequest, - CredentialEntity, - OrganizationEntity, - UserEntity, - UserRole -} from '@narval/policy-engine-shared' -import { Injectable } from '@nestjs/common' -import { OrganizationRepository } from '../../persistence/repository/organization.repository' -import { UserRepository } from '../../persistence/repository/user.repository' - -@Injectable() -export class OrganizationService { - constructor( - private orgRepository: OrganizationRepository, - private userRepository: UserRepository - ) {} - - async create(input: CreateOrganizationRequest): Promise<{ - organization: OrganizationEntity - rootUser: UserEntity - rootCredential: CredentialEntity - }> { - const { uid, credential } = input.request.organization - - const rootUser: UserEntity = { - uid: credential.userId, - role: UserRole.ROOT - } - - await this.userRepository.create(uid, rootUser, credential) - - const organization = await this.orgRepository.create(uid) - - return { - organization, - rootUser, - rootCredential: credential - } - } -} diff --git a/apps/armory/src/store/entity/core/service/token.service.ts b/apps/armory/src/store/entity/core/service/token.service.ts deleted file mode 100644 index fdbc864a2..000000000 --- a/apps/armory/src/store/entity/core/service/token.service.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { RegisterTokensRequest, TokenEntity } from '@narval/policy-engine-shared' -import { Injectable } from '@nestjs/common' -import { TokenRepository } from '../../persistence/repository/token.repository' - -@Injectable() -export class TokenService { - constructor(private tokenRepository: TokenRepository) {} - - register(orgId: string, request: RegisterTokensRequest): Promise { - return this.tokenRepository.create(orgId, request.request.tokens) - } -} diff --git a/apps/armory/src/store/entity/core/service/user-group.service.ts b/apps/armory/src/store/entity/core/service/user-group.service.ts deleted file mode 100644 index a839d3333..000000000 --- a/apps/armory/src/store/entity/core/service/user-group.service.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { AssignUserGroupRequest } from '@narval/policy-engine-shared' -import { Injectable } from '@nestjs/common' -import { UserGroupRepository } from '../../persistence/repository/user-group.repository' - -@Injectable() -export class UserGroupService { - constructor(private userGroupRepository: UserGroupRepository) {} - - async assign(orgId: string, input: AssignUserGroupRequest): Promise { - const { groupId, userId } = input.request.data - const group = await this.userGroupRepository.findById(groupId) - - // if (!group) { - // await this.userGroupRepository.create(orgId, { uid: groupId }) - // } - - // if (group) { - // await this.userGroupRepository.update({ - // ...group, - // users: group.users.concat(userId) - // }) - // } else { - // await this.userGroupRepository.create(orgId, { - // uid: groupId, - // users: [userId] - // }) - // } - - return true - } -} diff --git a/apps/armory/src/store/entity/core/service/user.service.ts b/apps/armory/src/store/entity/core/service/user.service.ts deleted file mode 100644 index 00bf124df..000000000 --- a/apps/armory/src/store/entity/core/service/user.service.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { CreateUserRequest, UserEntity, UserRole, UserWalletEntity } from '@narval/policy-engine-shared' -import { Injectable } from '@nestjs/common' -import { UserWalletRepository } from '../../persistence/repository/user-wallet.repository' -import { UserRepository } from '../../persistence/repository/user.repository' - -@Injectable() -export class UserService { - constructor( - private userRepository: UserRepository, - private userWalletRepository: UserWalletRepository - ) {} - - create(orgId: string, input: CreateUserRequest): Promise { - const { user } = input.request - - return this.userRepository.create(orgId, user, user.credential) - } - - delete(uid: string): Promise { - return this.userRepository.delete(uid) - } - - async grantRole(uid: string, role: UserRole): Promise { - return this.userRepository.update({ - uid, - role - }) - } - - async assignWallet(orgId: string, assignment: UserWalletEntity): Promise { - return this.userWalletRepository.create(orgId, assignment) - } -} diff --git a/apps/armory/src/store/entity/core/service/wallet.service.ts b/apps/armory/src/store/entity/core/service/wallet.service.ts deleted file mode 100644 index a24a397ae..000000000 --- a/apps/armory/src/store/entity/core/service/wallet.service.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { - AssignWalletGroupRequest, - RegisterWalletRequest, - WalletEntity, - WalletGroupMemberEntity -} from '@narval/policy-engine-shared' -import { Injectable } from '@nestjs/common' -import { WalletGroupRepository } from '../../persistence/repository/wallet-group.repository' -import { WalletRepository } from '../../persistence/repository/wallet.repository' - -@Injectable() -export class WalletService { - constructor( - private walletRepository: WalletRepository, - private walletGroupRepository: WalletGroupRepository - ) {} - - async create(orgId: string, input: RegisterWalletRequest): Promise { - return this.walletRepository.create(orgId, input.request.wallet) - } - - async assignGroup(orgId: string, input: AssignWalletGroupRequest): Promise { - const { groupId, walletId } = input.request.data - - await this.walletGroupRepository.create(orgId, { uid: groupId }) - - return { groupId, walletId } - } -} diff --git a/apps/armory/src/store/entity/entity-store.constant.ts b/apps/armory/src/store/entity/entity-store.constant.ts deleted file mode 100644 index eaf3e2f67..000000000 --- a/apps/armory/src/store/entity/entity-store.constant.ts +++ /dev/null @@ -1,2 +0,0 @@ -export const API_PREFIX = '/store' -export const API_TAG = 'Entity Store' diff --git a/apps/armory/src/store/entity/entity-store.module.ts b/apps/armory/src/store/entity/entity-store.module.ts deleted file mode 100644 index d7df5b32c..000000000 --- a/apps/armory/src/store/entity/entity-store.module.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { ClassSerializerInterceptor, Module, ValidationPipe } from '@nestjs/common' -import { ConfigModule } from '@nestjs/config' -import { APP_INTERCEPTOR, APP_PIPE } from '@nestjs/core' -import { load } from '../../armory.config' -import { OrchestrationModule } from '../../orchestration/orchestration.module' -import { PersistenceModule } from '../../shared/module/persistence/persistence.module' -import { AddressBookService } from './core/service/address-book.service' -import { CredentialService } from './core/service/credential.service' -import { EntityService } from './core/service/entity.service' -import { OrganizationService } from './core/service/organization.service' -import { TokenService } from './core/service/token.service' -import { UserGroupService } from './core/service/user-group.service' -import { UserService } from './core/service/user.service' -import { WalletService } from './core/service/wallet.service' -import { AddressBookController } from './http/rest/controller/address-book.controller' -import { CredentialController } from './http/rest/controller/credential.controller' -import { EntityController } from './http/rest/controller/entity.controller' -import { OrganizationController } from './http/rest/controller/organization.controller' -import { TokenController } from './http/rest/controller/token.controller' -import { UserGroupController } from './http/rest/controller/user-group.controller' -import { UserWalletController } from './http/rest/controller/user-wallet.controller' -import { UserController } from './http/rest/controller/user.controller' -import { WalletGroupController } from './http/rest/controller/wallet-group.controller' -import { WalletController } from './http/rest/controller/wallet.controller' -import { EntityStoreSeed } from './persistence/entity-store.seed' -import { AddressBookRepository } from './persistence/repository/address-book.repository' -import { CredentialRepository } from './persistence/repository/credential.repository' -import { OrganizationRepository } from './persistence/repository/organization.repository' -import { TokenRepository } from './persistence/repository/token.repository' -import { UserGroupRepository } from './persistence/repository/user-group.repository' -import { UserWalletRepository } from './persistence/repository/user-wallet.repository' -import { UserRepository } from './persistence/repository/user.repository' -import { WalletGroupRepository } from './persistence/repository/wallet-group.repository' -import { WalletRepository } from './persistence/repository/wallet.repository' - -@Module({ - imports: [ConfigModule.forRoot({ load: [load] }), PersistenceModule, OrchestrationModule], - controllers: [ - AddressBookController, - CredentialController, - EntityController, - OrganizationController, - TokenController, - UserController, - UserGroupController, - UserWalletController, - WalletController, - WalletGroupController - ], - providers: [ - AddressBookRepository, - AddressBookService, - CredentialRepository, - CredentialService, - EntityService, - EntityStoreSeed, - OrganizationRepository, - OrganizationService, - TokenRepository, - TokenService, - UserGroupRepository, - UserGroupService, - UserRepository, - UserService, - UserWalletRepository, - WalletGroupRepository, - WalletRepository, - WalletService, - { - provide: APP_INTERCEPTOR, - useClass: ClassSerializerInterceptor - }, - { - provide: APP_PIPE, - useClass: ValidationPipe - } - ] -}) -export class EntityStoreModule {} diff --git a/apps/armory/src/store/entity/http/rest/controller/address-book.controller.ts b/apps/armory/src/store/entity/http/rest/controller/address-book.controller.ts deleted file mode 100644 index 1901fba1b..000000000 --- a/apps/armory/src/store/entity/http/rest/controller/address-book.controller.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { Body, Controller, HttpStatus, Post } from '@nestjs/common' -import { ApiHeader, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger' -import { REQUEST_HEADER_ORG_ID } from '../../../../../armory.constant' -import { OrgId } from '../../../../../shared/decorator/org-id.decorator' -import { AddressBookService } from '../../../core/service/address-book.service' -import { API_PREFIX, API_TAG } from '../../../entity-store.constant' -import { CreateAddressBookAccountRequestDto } from '../dto/create-address-book-request.dto' -import { CreateAddressBookAccountResponseDto } from '../dto/create-address-book-response.dto' - -@Controller(`${API_PREFIX}/address-book`) -@ApiTags(API_TAG) -export class AddressBookController { - constructor(private addressBookService: AddressBookService) {} - - @Post() - @ApiOperation({ - summary: 'Registers an account in the address book entity' - }) - @ApiHeader({ - name: REQUEST_HEADER_ORG_ID - }) - @ApiResponse({ - status: HttpStatus.CREATED, - type: CreateAddressBookAccountResponseDto - }) - async registerAccount( - @OrgId() orgId: string, - @Body() body: CreateAddressBookAccountRequestDto - ): Promise { - const account = await this.addressBookService.create(orgId, body) - - return new CreateAddressBookAccountResponseDto({ account }) - } -} diff --git a/apps/armory/src/store/entity/http/rest/controller/credential.controller.ts b/apps/armory/src/store/entity/http/rest/controller/credential.controller.ts deleted file mode 100644 index bbd770ecf..000000000 --- a/apps/armory/src/store/entity/http/rest/controller/credential.controller.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Body, Controller, HttpStatus, Post } from '@nestjs/common' -import { ApiHeader, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger' -import { REQUEST_HEADER_ORG_ID } from '../../../../../armory.constant' -import { OrgId } from '../../../../../shared/decorator/org-id.decorator' -import { CredentialService } from '../../../core/service/credential.service' -import { API_PREFIX, API_TAG } from '../../../entity-store.constant' -import { CreateCredentialRequestDto } from '../dto/create-credential-request.dto' -import { CreateCredentialResponseDto } from '../dto/create-credential-response.dto' - -@Controller(`${API_PREFIX}/credentials`) -@ApiTags(API_TAG) -export class CredentialController { - constructor(private credentialService: CredentialService) {} - - @Post() - @ApiOperation({ - summary: 'Registers a new user credential' - }) - @ApiHeader({ - name: REQUEST_HEADER_ORG_ID - }) - @ApiResponse({ - status: HttpStatus.CREATED, - type: CreateCredentialResponseDto - }) - async create(@OrgId() orgId: string, @Body() body: CreateCredentialRequestDto): Promise { - const credential = await this.credentialService.create(orgId, body) - - return new CreateCredentialResponseDto({ credential }) - } -} diff --git a/apps/armory/src/store/entity/http/rest/controller/entity.controller.ts b/apps/armory/src/store/entity/http/rest/controller/entity.controller.ts deleted file mode 100644 index b8fa45077..000000000 --- a/apps/armory/src/store/entity/http/rest/controller/entity.controller.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Controller, Get, HttpStatus } from '@nestjs/common' -import { ApiHeader, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger' -import { REQUEST_HEADER_ORG_ID } from '../../../../../armory.constant' -import { OrgId } from '../../../../../shared/decorator/org-id.decorator' -import { EntityService } from '../../../core/service/entity.service' -import { API_PREFIX, API_TAG } from '../../../entity-store.constant' -import { EntitiesDto } from '../dto/entities.dto' - -@Controller(`${API_PREFIX}/entities`) -@ApiTags(API_TAG) -export class EntityController { - constructor(private entityService: EntityService) {} - - @Get() - @ApiOperation({ - summary: "Returns the organization's entities" - }) - @ApiHeader({ - name: REQUEST_HEADER_ORG_ID - }) - @ApiResponse({ - status: HttpStatus.OK, - type: EntitiesDto - }) - async getEntities(@OrgId() orgId: string): Promise { - const entities = await this.entityService.getEntities(orgId) - - return new EntitiesDto(entities) - } -} diff --git a/apps/armory/src/store/entity/http/rest/controller/organization.controller.ts b/apps/armory/src/store/entity/http/rest/controller/organization.controller.ts deleted file mode 100644 index ef2eebcc3..000000000 --- a/apps/armory/src/store/entity/http/rest/controller/organization.controller.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Body, Controller, HttpStatus, Post } from '@nestjs/common' -import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger' -import { OrganizationService } from '../../../core/service/organization.service' -import { API_PREFIX, API_TAG } from '../../../entity-store.constant' -import { CreateOrganizationRequestDto } from '../dto/create-organization-request.dto' -import { CreateOrganizationResponseDto } from '../dto/create-organization-response.dto' - -@Controller(`${API_PREFIX}/organizations`) -@ApiTags(API_TAG) -export class OrganizationController { - constructor(private orgService: OrganizationService) {} - - @Post() - @ApiOperation({ - summary: 'Creates a new organization and root user' - }) - @ApiResponse({ - status: HttpStatus.CREATED, - type: CreateOrganizationResponseDto - }) - async create(@Body() body: CreateOrganizationRequestDto): Promise { - const { organization, rootCredential, rootUser } = await this.orgService.create(body) - - return new CreateOrganizationResponseDto({ - organization, - rootCredential, - rootUser - }) - } -} diff --git a/apps/armory/src/store/entity/http/rest/controller/token.controller.ts b/apps/armory/src/store/entity/http/rest/controller/token.controller.ts deleted file mode 100644 index f3face93b..000000000 --- a/apps/armory/src/store/entity/http/rest/controller/token.controller.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Body, Controller, HttpStatus, Post } from '@nestjs/common' -import { ApiHeader, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger' -import { REQUEST_HEADER_ORG_ID } from '../../../../../armory.constant' -import { OrgId } from '../../../../../shared/decorator/org-id.decorator' -import { TokenService } from '../../../core/service/token.service' -import { API_PREFIX, API_TAG } from '../../../entity-store.constant' -import { RegisterTokensRequestDto } from '../dto/register-tokens-request.dto' -import { RegisterTokensResponseDto } from '../dto/register-tokens-response.dto' - -@Controller(`${API_PREFIX}/tokens`) -@ApiTags(API_TAG) -export class TokenController { - constructor(private tokenService: TokenService) {} - - @Post() - @ApiOperation({ - summary: 'Registers a token entity.' - }) - @ApiHeader({ - name: REQUEST_HEADER_ORG_ID - }) - @ApiResponse({ - status: HttpStatus.CREATED, - type: RegisterTokensResponseDto - }) - async register(@OrgId() orgId: string, @Body() body: RegisterTokensRequestDto): Promise { - const tokens = await this.tokenService.register(orgId, body) - - return new RegisterTokensResponseDto({ tokens }) - } -} diff --git a/apps/armory/src/store/entity/http/rest/controller/user-group.controller.ts b/apps/armory/src/store/entity/http/rest/controller/user-group.controller.ts deleted file mode 100644 index c2081faf8..000000000 --- a/apps/armory/src/store/entity/http/rest/controller/user-group.controller.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Body, Controller, HttpStatus, Post } from '@nestjs/common' -import { ApiHeader, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger' -import { REQUEST_HEADER_ORG_ID } from '../../../../../armory.constant' -import { OrgId } from '../../../../../shared/decorator/org-id.decorator' -import { UserGroupService } from '../../../core/service/user-group.service' -import { API_PREFIX, API_TAG } from '../../../entity-store.constant' -import { AssignUserGroupRequestDto } from '../dto/assign-user-group-request.dto' -import { AssignUserGroupResponseDto } from '../dto/assign-user-group-response.dto' - -@Controller(`${API_PREFIX}/user-groups`) -@ApiTags(API_TAG) -export class UserGroupController { - constructor(private userGroupService: UserGroupService) {} - - @Post() - @ApiOperation({ - summary: "Assigns a user to a group. If the group doesn't exist, creates it first" - }) - @ApiHeader({ - name: REQUEST_HEADER_ORG_ID - }) - @ApiResponse({ - status: HttpStatus.CREATED, - type: AssignUserGroupResponseDto - }) - async assign(@OrgId() orgId: string, @Body() body: AssignUserGroupRequestDto): Promise { - const { userId, groupId } = body.request.data - - await this.userGroupService.assign(orgId, body) - - return new AssignUserGroupResponseDto({ - data: { userId, groupId } - }) - } -} diff --git a/apps/armory/src/store/entity/http/rest/controller/user-wallet.controller.ts b/apps/armory/src/store/entity/http/rest/controller/user-wallet.controller.ts deleted file mode 100644 index b3343d329..000000000 --- a/apps/armory/src/store/entity/http/rest/controller/user-wallet.controller.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Body, Controller, HttpStatus, Post } from '@nestjs/common' -import { ApiHeader, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger' -import { REQUEST_HEADER_ORG_ID } from '../../../../../armory.constant' -import { OrgId } from '../../../../../shared/decorator/org-id.decorator' -import { UserService } from '../../../core/service/user.service' -import { API_PREFIX, API_TAG } from '../../../entity-store.constant' -import { AssignUserWalletRequestDto } from '../dto/assign-user-wallet-request.dto' -import { AssignUserWalletResponseDto } from '../dto/assign-user-wallet-response.dto' - -@Controller(`${API_PREFIX}/user-wallets`) -@ApiTags(API_TAG) -export class UserWalletController { - constructor(private userService: UserService) {} - - @Post() - @ApiOperation({ - summary: 'Assigns a wallet to a user' - }) - @ApiHeader({ - name: REQUEST_HEADER_ORG_ID - }) - @ApiResponse({ - status: HttpStatus.CREATED, - type: AssignUserWalletResponseDto - }) - async assign(@OrgId() orgId: string, @Body() body: AssignUserWalletRequestDto) { - const { data } = body.request - - await this.userService.assignWallet(orgId, body.request.data) - - return new AssignUserWalletResponseDto({ data }) - } -} diff --git a/apps/armory/src/store/entity/http/rest/controller/user.controller.ts b/apps/armory/src/store/entity/http/rest/controller/user.controller.ts deleted file mode 100644 index 47e0cb5be..000000000 --- a/apps/armory/src/store/entity/http/rest/controller/user.controller.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { Body, Controller, HttpStatus, Patch, Post } from '@nestjs/common' -import { ApiHeader, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger' -import { REQUEST_HEADER_ORG_ID } from '../../../../../armory.constant' -import { OrgId } from '../../../../../shared/decorator/org-id.decorator' -import { UserService } from '../../../core/service/user.service' -import { API_PREFIX, API_TAG } from '../../../entity-store.constant' -import { CreateUserRequestDto } from '../dto/create-user-request.dto' -import { CreateUserResponseDto } from '../dto/create-user-response.dto' -import { UpdateUserRequestDto } from '../dto/update-user-request.dto' -import { UpdateUserResponseDto } from '../dto/update-user-response.dto' - -@Controller(`${API_PREFIX}/users`) -@ApiTags(API_TAG) -export class UserController { - constructor(private userService: UserService) {} - - @Post() - @ApiOperation({ - summary: 'Creates a new user entity' - }) - @ApiHeader({ - name: REQUEST_HEADER_ORG_ID - }) - @ApiResponse({ - status: HttpStatus.CREATED, - type: CreateUserResponseDto - }) - async create(@OrgId() orgId: string, @Body() body: CreateUserRequestDto): Promise { - const { uid, role } = body.request.user - - await this.userService.create(orgId, body) - - return new CreateUserResponseDto({ - user: { uid, role } - }) - } - - @Patch('/:uid') - @ApiOperation({ - summary: 'Updates an existing user' - }) - @ApiHeader({ - name: REQUEST_HEADER_ORG_ID - }) - @ApiResponse({ - status: HttpStatus.OK, - type: UpdateUserResponseDto - }) - async update(@OrgId() orgId: string, @Body() body: UpdateUserRequestDto): Promise { - const { uid, role } = body.request.user - - await this.userService.grantRole(uid, role) - - return new UpdateUserResponseDto({ - user: { uid, role } - }) - } -} diff --git a/apps/armory/src/store/entity/http/rest/controller/wallet-group.controller.ts b/apps/armory/src/store/entity/http/rest/controller/wallet-group.controller.ts deleted file mode 100644 index 7a53bcbae..000000000 --- a/apps/armory/src/store/entity/http/rest/controller/wallet-group.controller.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { Body, Controller, HttpStatus, Post } from '@nestjs/common' -import { ApiHeader, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger' -import { REQUEST_HEADER_ORG_ID } from '../../../../../armory.constant' -import { OrgId } from '../../../../../shared/decorator/org-id.decorator' -import { WalletService } from '../../../core/service/wallet.service' -import { API_PREFIX, API_TAG } from '../../../entity-store.constant' -import { AssignWalletGroupRequestDto } from '../dto/assign-wallet-group-request.dto' -import { AssignWalletGroupResponseDto } from '../dto/assign-wallet-group-response.dto' - -@Controller(`${API_PREFIX}/wallet-groups`) -@ApiTags(API_TAG) -export class WalletGroupController { - constructor(private walletService: WalletService) {} - - @Post() - @ApiOperation({ - summary: "Assigns a wallet to a group. If the group doesn't exist, creates it first" - }) - @ApiHeader({ - name: REQUEST_HEADER_ORG_ID - }) - @ApiResponse({ - status: HttpStatus.CREATED, - type: AssignWalletGroupResponseDto - }) - async assign( - @OrgId() orgId: string, - @Body() body: AssignWalletGroupRequestDto - ): Promise { - const membership = await this.walletService.assignGroup(orgId, body) - - return new AssignWalletGroupResponseDto({ data: membership }) - } -} diff --git a/apps/armory/src/store/entity/http/rest/controller/wallet.controller.ts b/apps/armory/src/store/entity/http/rest/controller/wallet.controller.ts deleted file mode 100644 index 371893d5a..000000000 --- a/apps/armory/src/store/entity/http/rest/controller/wallet.controller.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Body, Controller, HttpStatus, Post } from '@nestjs/common' -import { ApiHeader, ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger' -import { REQUEST_HEADER_ORG_ID } from '../../../../../armory.constant' -import { OrgId } from '../../../../../shared/decorator/org-id.decorator' -import { WalletService } from '../../../core/service/wallet.service' -import { API_PREFIX, API_TAG } from '../../../entity-store.constant' -import { RegisterWalletRequestDto } from '../dto/register-wallet-request.dto' -import { RegisterWalletResponseDto } from '../dto/register-wallet-response.dto' - -@Controller(`${API_PREFIX}/wallets`) -@ApiTags(API_TAG) -export class WalletController { - constructor(private walletService: WalletService) {} - - @Post() - @ApiOperation({ - summary: 'Registers wallet as an entity' - }) - @ApiHeader({ - name: REQUEST_HEADER_ORG_ID - }) - @ApiResponse({ - status: HttpStatus.CREATED, - type: RegisterWalletResponseDto - }) - async register(@OrgId() orgId: string, @Body() body: RegisterWalletRequestDto): Promise { - const wallet = await this.walletService.create(orgId, body) - - return new RegisterWalletResponseDto({ wallet }) - } -} diff --git a/apps/armory/src/store/entity/http/rest/dto/address-book-account.dto.ts b/apps/armory/src/store/entity/http/rest/dto/address-book-account.dto.ts deleted file mode 100644 index 95fe6b4a1..000000000 --- a/apps/armory/src/store/entity/http/rest/dto/address-book-account.dto.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { AccountClassification, Address } from '@narval/policy-engine-shared' -import { ApiProperty } from '@nestjs/swagger' -import { IsEnum, IsEthereumAddress, IsNotEmpty, IsNumber, IsString } from 'class-validator' - -export class AddressBookAccountDto { - @IsString() - @IsNotEmpty() - uid: string - - @IsEnum(AccountClassification) - @ApiProperty({ enum: AccountClassification }) - classification: AccountClassification - - @IsEthereumAddress() - @ApiProperty({ - format: 'address', - type: String - }) - address: Address - - @IsNumber() - chainId: number -} diff --git a/apps/armory/src/store/entity/http/rest/dto/assign-user-group-request.dto.ts b/apps/armory/src/store/entity/http/rest/dto/assign-user-group-request.dto.ts deleted file mode 100644 index 1f7338031..000000000 --- a/apps/armory/src/store/entity/http/rest/dto/assign-user-group-request.dto.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Action, BaseActionDto, BaseActionRequestDto } from '@narval/policy-engine-shared' -import { ApiProperty } from '@nestjs/swagger' -import { Type } from 'class-transformer' -import { IsDefined, Matches, ValidateNested } from 'class-validator' -import { UserGroupMembershipDto } from './user-group-membership.dto' - -class AssignUserGroupActionDto extends BaseActionDto { - @Matches(Action.ASSIGN_USER_GROUP) - @ApiProperty({ - enum: [Action.ASSIGN_USER_GROUP], - default: Action.ASSIGN_USER_GROUP - }) - action: typeof Action.ASSIGN_USER_GROUP - - @IsDefined() - @Type(() => UserGroupMembershipDto) - @ValidateNested() - @ApiProperty() - data: UserGroupMembershipDto -} - -export class AssignUserGroupRequestDto extends BaseActionRequestDto { - @IsDefined() - @Type(() => AssignUserGroupActionDto) - @ValidateNested() - @ApiProperty() - request: AssignUserGroupActionDto -} diff --git a/apps/armory/src/store/entity/http/rest/dto/assign-user-group-response.dto.ts b/apps/armory/src/store/entity/http/rest/dto/assign-user-group-response.dto.ts deleted file mode 100644 index f6ba30084..000000000 --- a/apps/armory/src/store/entity/http/rest/dto/assign-user-group-response.dto.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger' -import { Type } from 'class-transformer' -import { IsDefined, ValidateNested } from 'class-validator' -import { UserGroupMembershipDto } from './user-group-membership.dto' - -export class AssignUserGroupResponseDto { - @IsDefined() - @Type(() => UserGroupMembershipDto) - @ValidateNested() - @ApiProperty() - data: UserGroupMembershipDto - - constructor(partial: Partial) { - Object.assign(this, partial) - } -} diff --git a/apps/armory/src/store/entity/http/rest/dto/assign-user-wallet-request.dto.ts b/apps/armory/src/store/entity/http/rest/dto/assign-user-wallet-request.dto.ts deleted file mode 100644 index 9f6bbf4e9..000000000 --- a/apps/armory/src/store/entity/http/rest/dto/assign-user-wallet-request.dto.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Action, BaseActionDto, BaseActionRequestDto } from '@narval/policy-engine-shared' -import { ApiProperty } from '@nestjs/swagger' -import { Type } from 'class-transformer' -import { IsDefined, Matches, ValidateNested } from 'class-validator' -import { UserWalletDto } from './user-wallet.dto' - -class AssignUserWalletActionDto extends BaseActionDto { - @Matches(Action.ASSIGN_USER_WALLET) - @ApiProperty({ - enum: [Action.ASSIGN_USER_WALLET], - default: Action.ASSIGN_USER_WALLET - }) - action: typeof Action.ASSIGN_USER_WALLET - - @IsDefined() - @Type(() => UserWalletDto) - @ValidateNested() - @ApiProperty() - data: UserWalletDto -} - -export class AssignUserWalletRequestDto extends BaseActionRequestDto { - @IsDefined() - @Type(() => AssignUserWalletActionDto) - @ValidateNested() - @ApiProperty() - request: AssignUserWalletActionDto -} diff --git a/apps/armory/src/store/entity/http/rest/dto/assign-user-wallet-response.dto.ts b/apps/armory/src/store/entity/http/rest/dto/assign-user-wallet-response.dto.ts deleted file mode 100644 index 8843250d3..000000000 --- a/apps/armory/src/store/entity/http/rest/dto/assign-user-wallet-response.dto.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger' -import { Type } from 'class-transformer' -import { IsDefined, ValidateNested } from 'class-validator' -import { UserWalletDto } from './user-wallet.dto' - -export class AssignUserWalletResponseDto { - @IsDefined() - @Type(() => UserWalletDto) - @ValidateNested() - @ApiProperty() - data: UserWalletDto - - constructor(partial: Partial) { - Object.assign(this, partial) - } -} diff --git a/apps/armory/src/store/entity/http/rest/dto/assign-wallet-group-request.dto.ts b/apps/armory/src/store/entity/http/rest/dto/assign-wallet-group-request.dto.ts deleted file mode 100644 index 14333540c..000000000 --- a/apps/armory/src/store/entity/http/rest/dto/assign-wallet-group-request.dto.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Action, BaseActionDto, BaseActionRequestDto } from '@narval/policy-engine-shared' -import { ApiProperty } from '@nestjs/swagger' -import { Type } from 'class-transformer' -import { IsDefined, Matches, ValidateNested } from 'class-validator' -import { WalletGroupMembershipDto } from './wallet-group-membership.dto' - -class AssignWalletGroupActionDto extends BaseActionDto { - @Matches(Action.ASSIGN_WALLET_GROUP) - @ApiProperty({ - enum: [Action.ASSIGN_WALLET_GROUP], - default: Action.ASSIGN_WALLET_GROUP - }) - action: typeof Action.ASSIGN_WALLET_GROUP - - @IsDefined() - @Type(() => WalletGroupMembershipDto) - @ValidateNested() - @ApiProperty() - data: WalletGroupMembershipDto -} - -export class AssignWalletGroupRequestDto extends BaseActionRequestDto { - @IsDefined() - @Type(() => AssignWalletGroupActionDto) - @ValidateNested() - @ApiProperty() - request: AssignWalletGroupActionDto -} diff --git a/apps/armory/src/store/entity/http/rest/dto/assign-wallet-group-response.dto.ts b/apps/armory/src/store/entity/http/rest/dto/assign-wallet-group-response.dto.ts deleted file mode 100644 index afbcb33ae..000000000 --- a/apps/armory/src/store/entity/http/rest/dto/assign-wallet-group-response.dto.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger' -import { Type } from 'class-transformer' -import { IsDefined, ValidateNested } from 'class-validator' -import { WalletGroupMembershipDto } from './wallet-group-membership.dto' - -export class AssignWalletGroupResponseDto { - @IsDefined() - @Type(() => WalletGroupMembershipDto) - @ValidateNested() - @ApiProperty() - data: WalletGroupMembershipDto - - constructor(partial: Partial) { - Object.assign(this, partial) - } -} diff --git a/apps/armory/src/store/entity/http/rest/dto/auth-credential.dto.ts b/apps/armory/src/store/entity/http/rest/dto/auth-credential.dto.ts deleted file mode 100644 index d84500cee..000000000 --- a/apps/armory/src/store/entity/http/rest/dto/auth-credential.dto.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Alg } from '@narval/policy-engine-shared' -import { ApiProperty } from '@nestjs/swagger' -import { IsEnum, IsNotEmpty, IsString } from 'class-validator' - -export class AuthCredentialDto { - @IsString() - @IsNotEmpty() - @ApiProperty() - uid: string - - @IsString() - @IsNotEmpty() - @ApiProperty() - pubKey: string - - @IsEnum(Alg) - @ApiProperty({ enum: Alg }) - alg: Alg - - @IsString() - @IsNotEmpty() - @ApiProperty() - userId: string -} diff --git a/apps/armory/src/store/entity/http/rest/dto/create-address-book-request.dto.ts b/apps/armory/src/store/entity/http/rest/dto/create-address-book-request.dto.ts deleted file mode 100644 index 274a6a8bc..000000000 --- a/apps/armory/src/store/entity/http/rest/dto/create-address-book-request.dto.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Action, BaseActionDto, BaseActionRequestDto } from '@narval/policy-engine-shared' -import { ApiProperty } from '@nestjs/swagger' -import { Type } from 'class-transformer' -import { IsDefined, Matches, ValidateNested } from 'class-validator' -import { AddressBookAccountDto } from './address-book-account.dto' - -class CreateAddressBookAccountActionDto extends BaseActionDto { - @Matches(Action.CREATE_ADDRESS_BOOK_ACCOUNT) - @ApiProperty({ - enum: [Action.CREATE_ADDRESS_BOOK_ACCOUNT], - default: Action.CREATE_ADDRESS_BOOK_ACCOUNT - }) - action: typeof Action.CREATE_ADDRESS_BOOK_ACCOUNT - - @IsDefined() - @Type(() => AddressBookAccountDto) - @ValidateNested() - @ApiProperty({ - type: AddressBookAccountDto - }) - account: AddressBookAccountDto -} - -export class CreateAddressBookAccountRequestDto extends BaseActionRequestDto { - @IsDefined() - @Type(() => CreateAddressBookAccountActionDto) - @ValidateNested() - @ApiProperty({ - type: CreateAddressBookAccountActionDto - }) - request: CreateAddressBookAccountActionDto -} diff --git a/apps/armory/src/store/entity/http/rest/dto/create-address-book-response.dto.ts b/apps/armory/src/store/entity/http/rest/dto/create-address-book-response.dto.ts deleted file mode 100644 index 46b4f663d..000000000 --- a/apps/armory/src/store/entity/http/rest/dto/create-address-book-response.dto.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger' -import { Type } from 'class-transformer' -import { IsDefined, ValidateNested } from 'class-validator' -import { AddressBookAccountDto } from './address-book-account.dto' - -export class CreateAddressBookAccountResponseDto { - @IsDefined() - @Type(() => AddressBookAccountDto) - @ValidateNested() - @ApiProperty() - account: AddressBookAccountDto - - constructor(partial: Partial) { - Object.assign(this, partial) - } -} diff --git a/apps/armory/src/store/entity/http/rest/dto/create-credential-request.dto.ts b/apps/armory/src/store/entity/http/rest/dto/create-credential-request.dto.ts deleted file mode 100644 index 1763a33f1..000000000 --- a/apps/armory/src/store/entity/http/rest/dto/create-credential-request.dto.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Action, BaseActionDto, BaseActionRequestDto } from '@narval/policy-engine-shared' -import { ApiProperty } from '@nestjs/swagger' -import { Type } from 'class-transformer' -import { IsDefined, Matches, ValidateNested } from 'class-validator' -import { AuthCredentialDto } from './auth-credential.dto' - -class CreateCredentialActionDto extends BaseActionDto { - @Matches(Action.CREATE_CREDENTIAL) - @ApiProperty({ - enum: [Action.CREATE_CREDENTIAL], - default: Action.CREATE_CREDENTIAL - }) - action: typeof Action.CREATE_CREDENTIAL - - @IsDefined() - @Type(() => AuthCredentialDto) - @ValidateNested() - @ApiProperty() - credential: AuthCredentialDto -} - -export class CreateCredentialRequestDto extends BaseActionRequestDto { - @IsDefined() - @Type(() => CreateCredentialActionDto) - @ValidateNested() - @ApiProperty() - request: CreateCredentialActionDto -} diff --git a/apps/armory/src/store/entity/http/rest/dto/create-credential-response.dto.ts b/apps/armory/src/store/entity/http/rest/dto/create-credential-response.dto.ts deleted file mode 100644 index df458e864..000000000 --- a/apps/armory/src/store/entity/http/rest/dto/create-credential-response.dto.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger' -import { Type } from 'class-transformer' -import { IsDefined, ValidateNested } from 'class-validator' -import { AuthCredentialDto } from './auth-credential.dto' - -export class CreateCredentialResponseDto { - @IsDefined() - @Type(() => AuthCredentialDto) - @ValidateNested() - @ApiProperty() - credential: AuthCredentialDto - - constructor(partial: Partial) { - Object.assign(this, partial) - } -} diff --git a/apps/armory/src/store/entity/http/rest/dto/create-organization-request.dto.ts b/apps/armory/src/store/entity/http/rest/dto/create-organization-request.dto.ts deleted file mode 100644 index 3f86cb109..000000000 --- a/apps/armory/src/store/entity/http/rest/dto/create-organization-request.dto.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Action, BaseActionDto, BaseActionRequestDto } from '@narval/policy-engine-shared' -import { ApiProperty } from '@nestjs/swagger' -import { Type } from 'class-transformer' -import { IsDefined, IsNotEmpty, IsString, Matches, ValidateNested } from 'class-validator' -import { AuthCredentialDto } from './auth-credential.dto' - -class CreateOrganizationDataDto { - @IsString() - @IsNotEmpty() - @ApiProperty() - uid: string - - @IsDefined() - @Type(() => AuthCredentialDto) - @ValidateNested() - @ApiProperty() - credential: AuthCredentialDto -} - -class CreateOrganizationActionDto extends BaseActionDto { - @Matches(Action.CREATE_ORGANIZATION) - @ApiProperty({ - enum: [Action.CREATE_ORGANIZATION], - default: Action.CREATE_ORGANIZATION - }) - action: typeof Action.CREATE_ORGANIZATION - - @IsDefined() - @Type(() => CreateOrganizationDataDto) - @ValidateNested() - @ApiProperty() - organization: CreateOrganizationDataDto -} - -export class CreateOrganizationRequestDto extends BaseActionRequestDto { - @IsDefined() - @Type(() => CreateOrganizationActionDto) - @ValidateNested() - @ApiProperty() - request: CreateOrganizationActionDto -} diff --git a/apps/armory/src/store/entity/http/rest/dto/create-organization-response.dto.ts b/apps/armory/src/store/entity/http/rest/dto/create-organization-response.dto.ts deleted file mode 100644 index 2833e73a0..000000000 --- a/apps/armory/src/store/entity/http/rest/dto/create-organization-response.dto.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger' -import { Type } from 'class-transformer' -import { IsDefined, IsNotEmpty, IsString, ValidateNested } from 'class-validator' -import { AuthCredentialDto } from './auth-credential.dto' -import { UserDto } from './user.dto' - -class OrganizationDataDto { - @IsString() - @IsNotEmpty() - @ApiProperty() - uid: string -} - -export class CreateOrganizationResponseDto { - @IsDefined() - @Type(() => OrganizationDataDto) - @ValidateNested() - @ApiProperty() - organization: OrganizationDataDto - - @IsDefined() - @Type(() => AuthCredentialDto) - @ValidateNested() - @ApiProperty() - rootCredential: AuthCredentialDto - - @IsDefined() - @Type(() => UserDto) - @ValidateNested() - @ApiProperty() - rootUser: UserDto - - constructor(partial: Partial) { - Object.assign(this, partial) - } -} diff --git a/apps/armory/src/store/entity/http/rest/dto/create-user-request.dto.ts b/apps/armory/src/store/entity/http/rest/dto/create-user-request.dto.ts deleted file mode 100644 index 54029b200..000000000 --- a/apps/armory/src/store/entity/http/rest/dto/create-user-request.dto.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { Action, BaseActionDto, BaseActionRequestDto, UserRole } from '@narval/policy-engine-shared' -import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger' -import { Type } from 'class-transformer' -import { IsDefined, IsEnum, IsNotEmpty, IsOptional, IsString, Matches, ValidateNested } from 'class-validator' -import { AuthCredentialDto } from './auth-credential.dto' - -class CreateUserDataDto { - @IsString() - @IsNotEmpty() - @ApiProperty() - uid: string - - @IsEnum(UserRole) - @ApiProperty({ enum: UserRole }) - role: UserRole - - @IsOptional() - @Type(() => AuthCredentialDto) - @ValidateNested() - @ApiPropertyOptional() - credential?: AuthCredentialDto -} - -class CreateUserActionDto extends BaseActionDto { - @Matches(Action.CREATE_USER) - @ApiProperty({ - enum: [Action.CREATE_USER], - default: Action.CREATE_USER - }) - action: typeof Action.CREATE_USER - - @IsDefined() - @Type(() => CreateUserDataDto) - @ValidateNested() - @ApiProperty() - user: CreateUserDataDto -} - -export class CreateUserRequestDto extends BaseActionRequestDto { - @IsDefined() - @Type(() => CreateUserActionDto) - @ValidateNested() - @ApiProperty() - request: CreateUserActionDto -} diff --git a/apps/armory/src/store/entity/http/rest/dto/create-user-response.dto.ts b/apps/armory/src/store/entity/http/rest/dto/create-user-response.dto.ts deleted file mode 100644 index 0cdd74087..000000000 --- a/apps/armory/src/store/entity/http/rest/dto/create-user-response.dto.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger' -import { Type } from 'class-transformer' -import { IsDefined, ValidateNested } from 'class-validator' -import { UserDto } from './user.dto' - -export class CreateUserResponseDto { - @IsDefined() - @Type(() => UserDto) - @ValidateNested() - @ApiProperty() - user: UserDto - - constructor(partial: Partial) { - Object.assign(this, partial) - } -} diff --git a/apps/armory/src/store/entity/http/rest/dto/entities.dto.ts b/apps/armory/src/store/entity/http/rest/dto/entities.dto.ts deleted file mode 100644 index ca0a9aa94..000000000 --- a/apps/armory/src/store/entity/http/rest/dto/entities.dto.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { Type } from 'class-transformer' -import { ValidateNested } from 'class-validator' -import { AddressBookAccountDto } from './address-book-account.dto' -import { AuthCredentialDto } from './auth-credential.dto' -import { TokenDto } from './token.dto' -import { UserWalletDto } from './user-wallet.dto' -import { UserDto } from './user.dto' -import { WalletGroupDto } from './wallet-group.dto' -import { WalletDto } from './wallet.dto' - -export class EntitiesDto { - @Type(() => AddressBookAccountDto) - @ValidateNested({ each: true }) - addressBook: AddressBookAccountDto[] - - @Type(() => AuthCredentialDto) - @ValidateNested({ each: true }) - credentials: AuthCredentialDto[] - - @Type(() => TokenDto) - @ValidateNested({ each: true }) - tokens: TokenDto[] - - @Type(() => UserDto) - @ValidateNested({ each: true }) - users: UserDto[] - - @Type(() => UserWalletDto) - @ValidateNested({ each: true }) - userWallets: UserWalletDto[] - - @Type(() => WalletDto) - @ValidateNested({ each: true }) - wallets: WalletDto[] - - @Type(() => WalletDto) - @ValidateNested({ each: true }) - walletGroups: WalletGroupDto[] - - constructor(partial: Partial) { - Object.assign(this, partial) - } -} diff --git a/apps/armory/src/store/entity/http/rest/dto/register-tokens-request.dto.ts b/apps/armory/src/store/entity/http/rest/dto/register-tokens-request.dto.ts deleted file mode 100644 index c1bffaee0..000000000 --- a/apps/armory/src/store/entity/http/rest/dto/register-tokens-request.dto.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Action, BaseActionDto, BaseActionRequestDto } from '@narval/policy-engine-shared' -import { ApiProperty } from '@nestjs/swagger' -import { Type } from 'class-transformer' -import { ArrayNotEmpty, IsDefined, Matches, ValidateNested } from 'class-validator' -import { TokenDto } from './token.dto' - -class RegisterTokensActionDto extends BaseActionDto { - @Matches(Action.REGISTER_TOKENS) - @ApiProperty({ - enum: [Action.REGISTER_TOKENS], - default: Action.REGISTER_TOKENS - }) - action: typeof Action.REGISTER_TOKENS - - @ArrayNotEmpty() - @Type(() => TokenDto) - @ValidateNested({ each: true }) - @ApiProperty({ type: [TokenDto] }) - tokens: TokenDto[] -} - -export class RegisterTokensRequestDto extends BaseActionRequestDto { - @IsDefined() - @Type(() => RegisterTokensActionDto) - @ValidateNested() - @ApiProperty() - request: RegisterTokensActionDto -} diff --git a/apps/armory/src/store/entity/http/rest/dto/register-tokens-response.dto.ts b/apps/armory/src/store/entity/http/rest/dto/register-tokens-response.dto.ts deleted file mode 100644 index 824af5d18..000000000 --- a/apps/armory/src/store/entity/http/rest/dto/register-tokens-response.dto.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger' -import { Type } from 'class-transformer' -import { ArrayNotEmpty, ValidateNested } from 'class-validator' -import { TokenDto } from './token.dto' - -export class RegisterTokensResponseDto { - @ArrayNotEmpty() - @Type(() => TokenDto) - @ValidateNested({ each: true }) - @ApiProperty({ type: [TokenDto] }) - tokens: TokenDto[] - - constructor(partial: Partial) { - Object.assign(this, partial) - } -} diff --git a/apps/armory/src/store/entity/http/rest/dto/register-wallet-request.dto.ts b/apps/armory/src/store/entity/http/rest/dto/register-wallet-request.dto.ts deleted file mode 100644 index 1c2981e77..000000000 --- a/apps/armory/src/store/entity/http/rest/dto/register-wallet-request.dto.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { Action, BaseActionDto, BaseActionRequestDto } from '@narval/policy-engine-shared' -import { ApiProperty } from '@nestjs/swagger' -import { Type } from 'class-transformer' -import { IsDefined, Matches, ValidateNested } from 'class-validator' -import { WalletDto } from './wallet.dto' - -class RegisterWalletActionDto extends BaseActionDto { - @Matches(Action.REGISTER_WALLET) - @ApiProperty({ - enum: [Action.REGISTER_WALLET], - default: Action.REGISTER_WALLET - }) - action: typeof Action.REGISTER_WALLET - - @IsDefined() - @Type(() => WalletDto) - @ValidateNested() - @ApiProperty() - wallet: WalletDto -} - -export class RegisterWalletRequestDto extends BaseActionRequestDto { - @IsDefined() - @Type(() => RegisterWalletActionDto) - @ValidateNested() - @ApiProperty() - request: RegisterWalletActionDto -} diff --git a/apps/armory/src/store/entity/http/rest/dto/register-wallet-response.dto.ts b/apps/armory/src/store/entity/http/rest/dto/register-wallet-response.dto.ts deleted file mode 100644 index 3fcb24cbe..000000000 --- a/apps/armory/src/store/entity/http/rest/dto/register-wallet-response.dto.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger' -import { Type } from 'class-transformer' -import { IsDefined, ValidateNested } from 'class-validator' -import { WalletDto } from './wallet.dto' - -export class RegisterWalletResponseDto { - @IsDefined() - @Type(() => WalletDto) - @ValidateNested() - @ApiProperty() - wallet: WalletDto - - constructor(partial: Partial) { - Object.assign(this, partial) - } -} diff --git a/apps/armory/src/store/entity/http/rest/dto/request-signature.dto.ts b/apps/armory/src/store/entity/http/rest/dto/request-signature.dto.ts deleted file mode 100644 index b5cb1cc24..000000000 --- a/apps/armory/src/store/entity/http/rest/dto/request-signature.dto.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Alg } from '@narval/policy-engine-shared' -import { ApiProperty } from '@nestjs/swagger' -import { IsEnum, IsNotEmpty, IsString } from 'class-validator' - -export class RequestSignatureDto { - @IsString() - @IsNotEmpty() - @ApiProperty() - sig: string - - @IsEnum(Alg) - @ApiProperty({ enum: Alg }) - alg: Alg - - @IsString() - @IsNotEmpty() - @ApiProperty() - pubKey: string -} diff --git a/apps/armory/src/store/entity/http/rest/dto/token.dto.ts b/apps/armory/src/store/entity/http/rest/dto/token.dto.ts deleted file mode 100644 index 3ed746747..000000000 --- a/apps/armory/src/store/entity/http/rest/dto/token.dto.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Address } from '@narval/policy-engine-shared' -import { ApiProperty } from '@nestjs/swagger' -import { IsDefined, IsEthereumAddress, IsNotEmpty, IsNumber, IsString, Min } from 'class-validator' - -export class TokenDto { - @IsString() - @IsNotEmpty() - uid: string - - @IsEthereumAddress() - @ApiProperty({ - format: 'address', - type: String - }) - address: Address - - @IsNumber() - @IsDefined() - @Min(1) - chainId: number - - @IsString() - @IsNotEmpty() - symbol: string - - @IsNumber() - @IsDefined() - decimals: number - - constructor(partial: Partial) { - Object.assign(this, partial) - } -} diff --git a/apps/armory/src/store/entity/http/rest/dto/update-user-request.dto.ts b/apps/armory/src/store/entity/http/rest/dto/update-user-request.dto.ts deleted file mode 100644 index 2ff3d7731..000000000 --- a/apps/armory/src/store/entity/http/rest/dto/update-user-request.dto.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { Action, BaseActionDto, BaseActionRequestDto, UserRole } from '@narval/policy-engine-shared' -import { ApiProperty } from '@nestjs/swagger' -import { Type } from 'class-transformer' -import { IsDefined, IsEnum, IsNotEmpty, IsString, Matches, ValidateNested } from 'class-validator' - -class UpdateUserDataDto { - @IsString() - @IsNotEmpty() - @ApiProperty() - uid: string - - @IsEnum(UserRole) - @ApiProperty({ enum: UserRole }) - role: UserRole -} - -class UpdateUserActionDto extends BaseActionDto { - @Matches(Action.UPDATE_USER) - @ApiProperty({ - enum: [Action.UPDATE_USER], - default: Action.UPDATE_USER - }) - action: typeof Action.UPDATE_USER - - @IsDefined() - @Type(() => UpdateUserDataDto) - @ValidateNested() - @ApiProperty() - user: UpdateUserDataDto -} - -export class UpdateUserRequestDto extends BaseActionRequestDto { - @IsDefined() - @Type(() => UpdateUserActionDto) - @ValidateNested() - @ApiProperty() - request: UpdateUserActionDto -} diff --git a/apps/armory/src/store/entity/http/rest/dto/update-user-response.dto.ts b/apps/armory/src/store/entity/http/rest/dto/update-user-response.dto.ts deleted file mode 100644 index c31a6914f..000000000 --- a/apps/armory/src/store/entity/http/rest/dto/update-user-response.dto.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger' -import { Type } from 'class-transformer' -import { IsDefined, ValidateNested } from 'class-validator' -import { UserDto } from './user.dto' - -export class UpdateUserResponseDto { - @IsDefined() - @Type(() => UserDto) - @ValidateNested() - @ApiProperty() - user: UserDto - - constructor(partial: Partial) { - Object.assign(this, partial) - } -} diff --git a/apps/armory/src/store/entity/http/rest/dto/user-group-membership.dto.ts b/apps/armory/src/store/entity/http/rest/dto/user-group-membership.dto.ts deleted file mode 100644 index 2de46ce54..000000000 --- a/apps/armory/src/store/entity/http/rest/dto/user-group-membership.dto.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger' -import { IsNotEmpty, IsString } from 'class-validator' - -export class UserGroupMembershipDto { - @IsString() - @IsNotEmpty() - @ApiProperty() - userId: string - - @IsString() - @IsNotEmpty() - @ApiProperty() - groupId: string - - constructor(partial: Partial) { - Object.assign(this, partial) - } -} diff --git a/apps/armory/src/store/entity/http/rest/dto/user-wallet.dto.ts b/apps/armory/src/store/entity/http/rest/dto/user-wallet.dto.ts deleted file mode 100644 index 192ece581..000000000 --- a/apps/armory/src/store/entity/http/rest/dto/user-wallet.dto.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger' -import { IsNotEmpty, IsString } from 'class-validator' - -export class UserWalletDto { - @IsString() - @IsNotEmpty() - @ApiProperty() - walletId: string - - @IsString() - @IsNotEmpty() - @ApiProperty() - userId: string - - constructor(partial: Partial) { - Object.assign(this, partial) - } -} diff --git a/apps/armory/src/store/entity/http/rest/dto/user.dto.ts b/apps/armory/src/store/entity/http/rest/dto/user.dto.ts deleted file mode 100644 index 830660892..000000000 --- a/apps/armory/src/store/entity/http/rest/dto/user.dto.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { UserRole } from '@narval/policy-engine-shared' -import { ApiProperty } from '@nestjs/swagger' -import { IsEnum, IsNotEmpty, IsString } from 'class-validator' - -export class UserDto { - @IsString() - @IsNotEmpty() - @ApiProperty() - uid: string - - @IsEnum(UserRole) - @ApiProperty({ enum: UserRole }) - role: UserRole - - constructor(partial: Partial) { - Object.assign(this, partial) - } -} diff --git a/apps/armory/src/store/entity/http/rest/dto/wallet-group-membership.dto.ts b/apps/armory/src/store/entity/http/rest/dto/wallet-group-membership.dto.ts deleted file mode 100644 index a3cbdf285..000000000 --- a/apps/armory/src/store/entity/http/rest/dto/wallet-group-membership.dto.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger' -import { IsNotEmpty, IsString } from 'class-validator' - -export class WalletGroupMembershipDto { - @IsString() - @IsNotEmpty() - @ApiProperty() - walletId: string - - @IsString() - @IsNotEmpty() - @ApiProperty() - groupId: string - - constructor(partial: Partial) { - Object.assign(this, partial) - } -} diff --git a/apps/armory/src/store/entity/http/rest/dto/wallet-group.dto.ts b/apps/armory/src/store/entity/http/rest/dto/wallet-group.dto.ts deleted file mode 100644 index 72db551b6..000000000 --- a/apps/armory/src/store/entity/http/rest/dto/wallet-group.dto.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { IsArray, IsNotEmpty, IsString } from 'class-validator' - -export class WalletGroupDto { - @IsString() - @IsNotEmpty() - uid: string - - @IsArray() - wallets: string[] - - constructor(partial: Partial) { - Object.assign(this, partial) - } -} diff --git a/apps/armory/src/store/entity/http/rest/dto/wallet.dto.ts b/apps/armory/src/store/entity/http/rest/dto/wallet.dto.ts deleted file mode 100644 index 9e8f2af01..000000000 --- a/apps/armory/src/store/entity/http/rest/dto/wallet.dto.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { AccountType, Address } from '@narval/policy-engine-shared' -import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger' -import { IsEnum, IsEthereumAddress, IsNotEmpty, IsNumber, IsOptional, IsString } from 'class-validator' - -export class WalletDto { - @IsString() - @IsNotEmpty() - @ApiProperty() - uid: string - - @IsEnum(AccountType) - @ApiProperty({ enum: AccountType }) - accountType: AccountType - - @IsEthereumAddress() - @ApiProperty({ - type: String, - format: 'address' - }) - address: Address - - @IsNumber() - @IsOptional() - @ApiPropertyOptional() - chainId?: number - - constructor(partial: Partial) { - Object.assign(this, partial) - } -} diff --git a/apps/armory/src/store/entity/persistence/decode.util.ts b/apps/armory/src/store/entity/persistence/decode.util.ts deleted file mode 100644 index 4bd7d2d68..000000000 --- a/apps/armory/src/store/entity/persistence/decode.util.ts +++ /dev/null @@ -1,14 +0,0 @@ -export const decodeConstant = ( - response: T, - key: K, - validValues: V[] -): T & Record => { - if (!validValues.includes(response[key] as V)) { - throw new Error(`Invalid value for key ${key as string}: ${response[key]}`) - } - - return { - ...response, - [key]: response[key] as V - } as T & Record -} diff --git a/apps/armory/src/store/entity/persistence/entity-store.seed.ts b/apps/armory/src/store/entity/persistence/entity-store.seed.ts deleted file mode 100644 index 20b6e3e49..000000000 --- a/apps/armory/src/store/entity/persistence/entity-store.seed.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { FIXTURE } from '@narval/policy-engine-shared' -import { Injectable } from '@nestjs/common' -import { SeedService } from '../../../shared/module/persistence/service/seed.service' -import { AddressBookRepository } from './repository/address-book.repository' -import { CredentialRepository } from './repository/credential.repository' -import { TokenRepository } from './repository/token.repository' -import { UserGroupRepository } from './repository/user-group.repository' -import { UserWalletRepository } from './repository/user-wallet.repository' -import { UserRepository } from './repository/user.repository' -import { WalletGroupRepository } from './repository/wallet-group.repository' -import { WalletRepository } from './repository/wallet.repository' - -@Injectable() -export class EntityStoreSeed extends SeedService { - constructor( - private addressBookRepository: AddressBookRepository, - private credentialRepository: CredentialRepository, - private tokenRepository: TokenRepository, - private userGroupRepository: UserGroupRepository, - private userRepository: UserRepository, - private userWalletRepository: UserWalletRepository, - private walletGroupRepository: WalletGroupRepository, - private walletRepository: WalletRepository - ) { - super() - } - - override async germinate(): Promise { - const { ORGANIZATION } = FIXTURE - - await Promise.all(Object.values(FIXTURE.USER).map((entity) => this.userRepository.create(ORGANIZATION.uid, entity))) - - await Promise.all( - Object.values(FIXTURE.CREDENTIAL).map((entity) => this.credentialRepository.create(ORGANIZATION.uid, entity)) - ) - - await Promise.all( - Object.values(FIXTURE.WALLET).map((entity) => this.walletRepository.create(ORGANIZATION.uid, entity)) - ) - - await Promise.all( - Object.values(FIXTURE.WALLET_GROUP).map((entity) => this.walletGroupRepository.create(ORGANIZATION.uid, entity)) - ) - - await Promise.all( - Object.values(FIXTURE.USER_GROUP).map((entity) => this.userGroupRepository.create(ORGANIZATION.uid, entity)) - ) - - // await Promise.all( - // compact( - // Object.values(FIXTURE.WALLET).map(({ uid, assignees }) => { - // if (assignees?.length) { - // return assignees.map((userId) => - // this.userWalletRepository.create(ORGANIZATION.uid, { - // userId, - // walletId: uid - // }) - // ) - // } - // }) - // ) - // ) - - await Promise.all(FIXTURE.ADDRESS_BOOK.map((entity) => this.addressBookRepository.create(ORGANIZATION.uid, entity))) - - await this.tokenRepository.create(ORGANIZATION.uid, Object.values(FIXTURE.TOKEN)) - } -} diff --git a/apps/armory/src/store/entity/persistence/repository/address-book.repository.ts b/apps/armory/src/store/entity/persistence/repository/address-book.repository.ts deleted file mode 100644 index dfdf207f5..000000000 --- a/apps/armory/src/store/entity/persistence/repository/address-book.repository.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { AccountClassification, AddressBookAccountEntity, getAddress } from '@narval/policy-engine-shared' -import { Injectable } from '@nestjs/common' -import { AddressBookAccountEntity as Model } from '@prisma/client/armory' -import { PrismaService } from '../../../../shared/module/persistence/service/prisma.service' -import { decodeConstant } from '../decode.util' - -@Injectable() -export class AddressBookRepository { - constructor(private prismaService: PrismaService) {} - - async create(orgId: string, account: AddressBookAccountEntity): Promise { - await this.prismaService.addressBookAccountEntity.create({ - data: { orgId, ...account } - }) - - return account - } - - async findById(uid: string): Promise { - const model = await this.prismaService.addressBookAccountEntity.findUnique({ - where: { uid } - }) - - if (model) { - return this.decode(model) - } - - return null - } - - async findByOrgId(orgId: string): Promise { - const models = await this.prismaService.addressBookAccountEntity.findMany({ where: { orgId } }) - - return models.map(this.decode) - } - - private decode({ uid, address, chainId, classification }: Model): AddressBookAccountEntity { - return decodeConstant( - { - uid, - address: getAddress(address), - chainId, - classification - }, - 'classification', - Object.values(AccountClassification) - ) - } -} diff --git a/apps/armory/src/store/entity/persistence/repository/credential.repository.ts b/apps/armory/src/store/entity/persistence/repository/credential.repository.ts deleted file mode 100644 index bda96a57f..000000000 --- a/apps/armory/src/store/entity/persistence/repository/credential.repository.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { Alg, CredentialEntity } from '@narval/policy-engine-shared' -import { Injectable } from '@nestjs/common' -import { AuthCredentialEntity as Model } from '@prisma/client/armory' -import { omit } from 'lodash/fp' -import { PrismaService } from '../../../../shared/module/persistence/service/prisma.service' -import { decodeConstant } from '../decode.util' - -@Injectable() -export class CredentialRepository { - constructor(private prismaService: PrismaService) {} - - async create(orgId: string, credential: CredentialEntity): Promise { - await this.prismaService.authCredentialEntity.create({ - data: { - orgId, - uid: credential.uid, - pubKey: credential.pubKey, - alg: credential.alg, - userId: credential.userId - } - }) - - return credential - } - - async findById(uid: string): Promise { - const model = await this.prismaService.authCredentialEntity.findUnique({ - where: { uid } - }) - - if (model) { - return this.decode(model) - } - - return null - } - - async findByOrgId(orgId: string): Promise { - const models = await this.prismaService.authCredentialEntity.findMany({ - where: { orgId } - }) - - return models.map(this.decode) - } - - private decode(model: Model): CredentialEntity { - return decodeConstant(omit('orgId', model), 'alg', Object.values(Alg)) - } -} diff --git a/apps/armory/src/store/entity/persistence/repository/organization.repository.ts b/apps/armory/src/store/entity/persistence/repository/organization.repository.ts deleted file mode 100644 index 3489cfa44..000000000 --- a/apps/armory/src/store/entity/persistence/repository/organization.repository.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { OrganizationEntity } from '@narval/policy-engine-shared' -import { Injectable } from '@nestjs/common' -import { PrismaService } from '../../../../shared/module/persistence/service/prisma.service' - -@Injectable() -export class OrganizationRepository { - constructor(private prismaService: PrismaService) {} - - async create(uid: string): Promise { - await this.prismaService.organizationEntity.create({ - data: { uid } - }) - - return { uid } - } - - async findById(uid: string): Promise { - return this.prismaService.organizationEntity.findUnique({ where: { uid } }) - } -} diff --git a/apps/armory/src/store/entity/persistence/repository/token.repository.ts b/apps/armory/src/store/entity/persistence/repository/token.repository.ts deleted file mode 100644 index b15b13bbb..000000000 --- a/apps/armory/src/store/entity/persistence/repository/token.repository.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { TokenEntity, getAddress } from '@narval/policy-engine-shared' -import { Injectable } from '@nestjs/common' -import { pick } from 'lodash/fp' -import { PrismaService } from '../../../../shared/module/persistence/service/prisma.service' - -@Injectable() -export class TokenRepository { - constructor(private prismaService: PrismaService) {} - - async create(orgId: string, tokens: TokenEntity[]): Promise { - await this.prismaService.tokenEntity.createMany({ - data: tokens.map((token) => ({ orgId, ...token })), - skipDuplicates: true - }) - - return tokens - } - - async findByOrgId(orgId: string): Promise { - const entities = await this.prismaService.tokenEntity.findMany({ - where: { orgId } - }) - - return entities.map((entity) => ({ - ...pick(['uid', 'address', 'symbol', 'chainId', 'decimals'], entity), - address: getAddress(entity.address) - })) - } -} diff --git a/apps/armory/src/store/entity/persistence/repository/user-group.repository.ts b/apps/armory/src/store/entity/persistence/repository/user-group.repository.ts deleted file mode 100644 index ab48754db..000000000 --- a/apps/armory/src/store/entity/persistence/repository/user-group.repository.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { UserGroupEntity } from '@narval/policy-engine-shared' -import { Injectable } from '@nestjs/common' -import { UserGroupEntity as GroupModel, UserGroupMemberEntity as MemberModel } from '@prisma/client/armory' -import { PrismaService } from '../../../../shared/module/persistence/service/prisma.service' - -type Model = GroupModel & { - members: MemberModel[] -} - -@Injectable() -export class UserGroupRepository { - constructor(private prismaService: PrismaService) {} - - async create(orgId: string, userGroup: UserGroupEntity): Promise { - await this.prismaService.userGroupEntity.create({ - data: { - orgId, - uid: userGroup.uid - } - }) - - return userGroup - } - - async findById(uid: string): Promise { - const model = await this.prismaService.userGroupEntity.findUnique({ - where: { uid }, - include: { - members: true - } - }) - - if (model) { - return this.decode(model) - } - - return null - } - - async findByOrgId(orgId: string): Promise { - const models = await this.prismaService.userGroupEntity.findMany({ - where: { orgId }, - include: { - members: true - } - }) - - return models.map(this.decode) - } - - private decode(model: Model): UserGroupEntity { - return { uid: model.uid } - } -} diff --git a/apps/armory/src/store/entity/persistence/repository/user-wallet.repository.ts b/apps/armory/src/store/entity/persistence/repository/user-wallet.repository.ts deleted file mode 100644 index 5caf8e369..000000000 --- a/apps/armory/src/store/entity/persistence/repository/user-wallet.repository.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { UserWalletEntity } from '@narval/policy-engine-shared' -import { Injectable } from '@nestjs/common' -import { PrismaService } from '../../../../shared/module/persistence/service/prisma.service' - -@Injectable() -export class UserWalletRepository { - constructor(private prismaService: PrismaService) {} - - async create(orgId: string, userWallet: UserWalletEntity): Promise { - await this.prismaService.userWalletEntity.create({ - data: { - orgId, - ...userWallet - } - }) - - return userWallet - } - - async findByOrgId(orgId: string): Promise { - return this.prismaService.userWalletEntity.findMany({ - where: { orgId } - }) - } -} diff --git a/apps/armory/src/store/entity/persistence/repository/user.repository.ts b/apps/armory/src/store/entity/persistence/repository/user.repository.ts deleted file mode 100644 index 558babaa8..000000000 --- a/apps/armory/src/store/entity/persistence/repository/user.repository.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { CredentialEntity, UserEntity, UserRole } from '@narval/policy-engine-shared' -import { Injectable } from '@nestjs/common' -import { UserEntity as UserModel } from '@prisma/client/armory' -import { omit } from 'lodash/fp' -import { SetRequired } from 'type-fest' -import { PrismaService } from '../../../../shared/module/persistence/service/prisma.service' -import { decodeConstant } from '../decode.util' - -@Injectable() -export class UserRepository { - constructor(private prismaService: PrismaService) {} - - async create(orgId: string, user: UserEntity, credential?: CredentialEntity): Promise { - const result = await this.prismaService.$transaction(async (tx) => { - const entity: UserEntity = await tx.userEntity - .create({ - data: { - uid: user.uid, - role: user.role, - orgId - } - }) - .then((d) => decodeConstant(d, 'role', Object.values(UserRole))) - - if (credential) { - await tx.authCredentialEntity.create({ - data: { - orgId, - uid: credential.uid, - pubKey: credential.pubKey, - alg: credential.alg, - userId: user.uid - } - }) - } - - return entity - }) - - return result - } - - async delete(uid: string): Promise { - await this.prismaService.$transaction(async (tx) => { - await tx.userEntity.delete({ - where: { - uid - } - }) - - await tx.authCredentialEntity.deleteMany({ - where: { - userId: uid - } - }) - - await tx.userGroupMemberEntity.deleteMany({ - where: { - userId: uid - } - }) - }) - - return true - } - - async update(user: SetRequired, 'uid'>): Promise { - const entity = await this.prismaService.userEntity.update({ - where: { - uid: user.uid - }, - data: user - }) - - return this.decode(entity) - } - - async findById(uid: string): Promise { - const entity = await this.prismaService.userEntity.findUnique({ - where: { uid } - }) - - if (entity) { - return this.decode(entity) - } - - return null - } - - async findByOrgId(orgId: string): Promise { - const entities = await this.prismaService.userEntity.findMany({ where: { orgId } }) - - return entities.map(this.decode) - } - - private decode(model: UserModel): UserEntity { - return decodeConstant(omit(['orgId'], model), 'role', Object.values(UserRole)) - } -} diff --git a/apps/armory/src/store/entity/persistence/repository/wallet-group.repository.ts b/apps/armory/src/store/entity/persistence/repository/wallet-group.repository.ts deleted file mode 100644 index 3168df6c4..000000000 --- a/apps/armory/src/store/entity/persistence/repository/wallet-group.repository.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { WalletGroupEntity } from '@narval/policy-engine-shared' -import { Injectable } from '@nestjs/common' -import { WalletGroupEntity as GroupModel, WalletGroupMemberEntity as MemberModel } from '@prisma/client/armory' -import { PrismaService } from '../../../../shared/module/persistence/service/prisma.service' - -type Model = GroupModel & { - members: MemberModel[] -} - -@Injectable() -export class WalletGroupRepository { - constructor(private prismaService: PrismaService) {} - - async create(orgId: string, walletGroup: WalletGroupEntity): Promise { - const group = await this.prismaService.walletGroupEntity.findUnique({ - where: { uid: walletGroup.uid } - }) - - if (!group) { - await this.prismaService.walletGroupEntity.create({ - data: { - orgId, - uid: walletGroup.uid - } - }) - } - - return walletGroup - } - - async findById(uid: string): Promise { - const model = await this.prismaService.walletGroupEntity.findUnique({ - where: { uid }, - include: { - members: true - } - }) - - if (model) { - return this.decode(model) - } - - return null - } - - async findByOrgId(orgId: string): Promise { - const models = await this.prismaService.walletGroupEntity.findMany({ - where: { orgId }, - include: { - members: true - } - }) - - return models.map(this.decode) - } - - private decode(model: Model): WalletGroupEntity { - return { uid: model.uid } - } -} diff --git a/apps/armory/src/store/entity/persistence/repository/wallet.repository.ts b/apps/armory/src/store/entity/persistence/repository/wallet.repository.ts deleted file mode 100644 index ccb40d2a9..000000000 --- a/apps/armory/src/store/entity/persistence/repository/wallet.repository.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { AccountType, WalletEntity, getAddress } from '@narval/policy-engine-shared' -import { Injectable } from '@nestjs/common' -import { WalletEntity as WalletModel } from '@prisma/client/armory' -import { PrismaService } from '../../../../shared/module/persistence/service/prisma.service' -import { decodeConstant } from '../decode.util' - -@Injectable() -export class WalletRepository { - constructor(private prismaService: PrismaService) {} - - async create(orgId: string, wallet: WalletEntity): Promise { - await this.prismaService.walletEntity.create({ - data: { - orgId, - uid: wallet.uid, - address: wallet.address, - accountType: wallet.accountType, - chainId: wallet.chainId - } - }) - - return wallet - } - - async findById(uid: string): Promise { - const model = await this.prismaService.walletEntity.findUnique({ where: { uid } }) - - if (model) { - return this.decode(model) - } - - return null - } - - async findByOrgId(orgId: string): Promise { - const models = await this.prismaService.walletEntity.findMany({ - where: { orgId } - }) - - return models.map(this.decode) - } - - private decode({ uid, address, accountType, chainId }: WalletModel): WalletEntity { - return decodeConstant( - { - uid, - address: getAddress(address), - accountType, - chainId: chainId || undefined - }, - 'accountType', - Object.values(AccountType) - ) - } -} diff --git a/apps/armory/src/store/store.module.ts b/apps/armory/src/store/store.module.ts deleted file mode 100644 index 9d26ffef5..000000000 --- a/apps/armory/src/store/store.module.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { Module } from '@nestjs/common' -import { EntityStoreModule } from './entity/entity-store.module' - -@Module({ - imports: [EntityStoreModule] -}) -export class StoreModule {} From f34ac5dfd230e873f6aacd72b275ffbe51151528 Mon Sep 17 00:00:00 2001 From: William Calderipe Date: Tue, 27 Feb 2024 17:37:33 +0100 Subject: [PATCH 5/9] Delete storage module --- .../__test__/e2e/entity-storage.spec.ts | 82 ------------------- .../exception/entity-validation.exception.ts | 13 --- .../core/exception/storage.exception.ts | 3 - .../core/repository/entity.repository.ts | 8 -- .../__test__/unit/entity.service.spec.ts | 58 ------------- .../storage/core/service/entity.service.ts | 22 ----- .../rest/controller/storage.controller.ts | 23 ------ .../http/rest/dto/address-book-account.dto.ts | 23 ------ .../storage/http/rest/dto/credential.dto.ts | 24 ------ .../src/storage/http/rest/dto/entities.dto.ts | 68 --------------- .../src/storage/http/rest/dto/token.dto.ts | 33 -------- .../rest/dto/update-entities-request.dto.ts | 10 --- .../http/rest/dto/user-group-member.dto.ts | 18 ---- .../storage/http/rest/dto/user-group.dto.ts | 13 --- .../storage/http/rest/dto/user-wallet.dto.ts | 18 ---- .../src/storage/http/rest/dto/user.dto.ts | 18 ---- .../http/rest/dto/wallet-group-member.dto.ts | 18 ---- .../storage/http/rest/dto/wallet-group.dto.ts | 11 --- .../src/storage/http/rest/dto/wallet.dto.ts | 30 ------- .../repository/in-memory-entity.repository.ts | 20 ----- apps/armory/src/storage/storage.module.ts | 26 ------ 21 files changed, 539 deletions(-) delete mode 100644 apps/armory/src/storage/__test__/e2e/entity-storage.spec.ts delete mode 100644 apps/armory/src/storage/core/exception/entity-validation.exception.ts delete mode 100644 apps/armory/src/storage/core/exception/storage.exception.ts delete mode 100644 apps/armory/src/storage/core/repository/entity.repository.ts delete mode 100644 apps/armory/src/storage/core/service/__test__/unit/entity.service.spec.ts delete mode 100644 apps/armory/src/storage/core/service/entity.service.ts delete mode 100644 apps/armory/src/storage/http/rest/controller/storage.controller.ts delete mode 100644 apps/armory/src/storage/http/rest/dto/address-book-account.dto.ts delete mode 100644 apps/armory/src/storage/http/rest/dto/credential.dto.ts delete mode 100644 apps/armory/src/storage/http/rest/dto/entities.dto.ts delete mode 100644 apps/armory/src/storage/http/rest/dto/token.dto.ts delete mode 100644 apps/armory/src/storage/http/rest/dto/update-entities-request.dto.ts delete mode 100644 apps/armory/src/storage/http/rest/dto/user-group-member.dto.ts delete mode 100644 apps/armory/src/storage/http/rest/dto/user-group.dto.ts delete mode 100644 apps/armory/src/storage/http/rest/dto/user-wallet.dto.ts delete mode 100644 apps/armory/src/storage/http/rest/dto/user.dto.ts delete mode 100644 apps/armory/src/storage/http/rest/dto/wallet-group-member.dto.ts delete mode 100644 apps/armory/src/storage/http/rest/dto/wallet-group.dto.ts delete mode 100644 apps/armory/src/storage/http/rest/dto/wallet.dto.ts delete mode 100644 apps/armory/src/storage/persistence/repository/in-memory-entity.repository.ts delete mode 100644 apps/armory/src/storage/storage.module.ts diff --git a/apps/armory/src/storage/__test__/e2e/entity-storage.spec.ts b/apps/armory/src/storage/__test__/e2e/entity-storage.spec.ts deleted file mode 100644 index fb6190c09..000000000 --- a/apps/armory/src/storage/__test__/e2e/entity-storage.spec.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { FIXTURE, OrganizationEntity } from '@narval/policy-engine-shared' -import { HttpStatus, INestApplication } from '@nestjs/common' -import { Test, TestingModule } from '@nestjs/testing' -import request from 'supertest' -import { REQUEST_HEADER_ORG_ID } from '../../../armory.constant' -// import { TestPrismaService } from '../../../shared/module/persistence/service/test-prisma.service' -import { EntityRepository } from '../../core/repository/entity.repository' -import { StorageModule } from '../../storage.module' - -const ENDPOINT = '/storage/entities' - -describe('Entity Storage', () => { - let app: INestApplication - let module: TestingModule - let entityRepository: EntityRepository - // let testPrismaService: TestPrismaService - - const organization: OrganizationEntity = { - uid: 'ac1374c2-fd62-4b6e-bd49-a4afcdcb91cc' - } - - beforeAll(async () => { - module = await Test.createTestingModule({ - imports: [StorageModule] - }).compile() - - // testPrismaService = module.get(TestPrismaService) - - entityRepository = module.get(EntityRepository) - - app = module.createNestApplication() - - await app.init() - }) - - afterAll(async () => { - // await testPrismaService.truncateAll() - await module.close() - await app.close() - }) - - beforeEach(async () => {}) - - afterEach(async () => { - // await testPrismaService.truncateAll() - }) - - describe(`PUT ${ENDPOINT}`, () => { - it('puts a new entities set for the organization', async () => { - const payload = { - entities: FIXTURE.ENTITIES - } - - const { status, body } = await request(app.getHttpServer()) - .put(ENDPOINT) - .set(REQUEST_HEADER_ORG_ID, organization.uid) - .send(payload) - - console.log(payload) - - expect(body).toEqual(payload) - expect(status).toEqual(HttpStatus.OK) - }) - }) - - describe(`GET ${ENDPOINT}`, () => { - it('responds with the organization entities', async () => { - await entityRepository.put(organization.uid, FIXTURE.ENTITIES) - - console.log(entityRepository) - - const { status, body } = await request(app.getHttpServer()) - .get(ENDPOINT) - .set(REQUEST_HEADER_ORG_ID, organization.uid) - - expect(body).toEqual({ - entities: FIXTURE.ENTITIES - }) - expect(status).toEqual(HttpStatus.OK) - }) - }) -}) diff --git a/apps/armory/src/storage/core/exception/entity-validation.exception.ts b/apps/armory/src/storage/core/exception/entity-validation.exception.ts deleted file mode 100644 index ff4cd1f5d..000000000 --- a/apps/armory/src/storage/core/exception/entity-validation.exception.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { EntityUtil } from '@narval/policy-engine-shared' -import { HttpStatus } from '@nestjs/common' -import { StorageException } from './storage.exception' - -export class EntityValidationException extends StorageException { - constructor(issues: EntityUtil.ValidationIssue[]) { - super({ - message: 'Entity validation failed', - suggestedHttpStatusCode: HttpStatus.UNPROCESSABLE_ENTITY, - context: { issues } - }) - } -} diff --git a/apps/armory/src/storage/core/exception/storage.exception.ts b/apps/armory/src/storage/core/exception/storage.exception.ts deleted file mode 100644 index 4a30fba3e..000000000 --- a/apps/armory/src/storage/core/exception/storage.exception.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { ApplicationException } from '../../../shared/exception/application.exception' - -export class StorageException extends ApplicationException {} diff --git a/apps/armory/src/storage/core/repository/entity.repository.ts b/apps/armory/src/storage/core/repository/entity.repository.ts deleted file mode 100644 index 4ae599bab..000000000 --- a/apps/armory/src/storage/core/repository/entity.repository.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Entities } from '@narval/policy-engine-shared' - -export const EntityRepository = Symbol('Storage:EntityRepository') - -export interface EntityRepository { - put(orgId: string, entities: Entities): Promise - findByOrgId(orgId: string): Promise -} diff --git a/apps/armory/src/storage/core/service/__test__/unit/entity.service.spec.ts b/apps/armory/src/storage/core/service/__test__/unit/entity.service.spec.ts deleted file mode 100644 index 46a0629d6..000000000 --- a/apps/armory/src/storage/core/service/__test__/unit/entity.service.spec.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { Entities, FIXTURE } from '@narval/policy-engine-shared' -import { Test } from '@nestjs/testing' -import { InMemoryEntityRepository } from '../../../../persistence/repository/in-memory-entity.repository' -import { EntityValidationException } from '../../../exception/entity-validation.exception' -import { EntityRepository } from '../../../repository/entity.repository' -import { EntityService } from '../../entity.service' - -describe(EntityService.name, () => { - let service: EntityService - - const orgId = 'test-org-id' - - const emptyEntities: Entities = { - addressBook: [], - credentials: [], - tokens: [], - userGroupMembers: [], - userGroups: [], - userWallets: [], - users: [], - walletGroupMembers: [], - walletGroups: [], - wallets: [] - } - - beforeEach(async () => { - const module = await Test.createTestingModule({ - providers: [ - EntityService, - { - provide: EntityRepository, - useClass: InMemoryEntityRepository - } - ] - }).compile() - - service = module.get(EntityService) - }) - - describe('put', () => { - it('throws EntityValidationException when validation fails', async () => { - await expect( - service.put(orgId, { - entities: { - ...emptyEntities, - userGroupMembers: [ - { - groupId: FIXTURE.USER_GROUP.Engineering.uid, - userId: FIXTURE.USER.Alice.uid - } - ], - users: [FIXTURE.USER.Alice] - } - }) - ).rejects.toThrow(EntityValidationException) - }) - }) -}) diff --git a/apps/armory/src/storage/core/service/entity.service.ts b/apps/armory/src/storage/core/service/entity.service.ts deleted file mode 100644 index 5bdc63906..000000000 --- a/apps/armory/src/storage/core/service/entity.service.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Entities, EntityUtil } from '@narval/policy-engine-shared' -import { Inject } from '@nestjs/common' -import { EntityValidationException } from '../exception/entity-validation.exception' -import { EntityRepository } from '../repository/entity.repository' - -export class EntityService { - constructor(@Inject(EntityRepository) private entityRepository: EntityRepository) {} - - async put(orgId: string, data: { entities: Entities }): Promise { - const result = EntityUtil.validate(data.entities) - - if (result.success) { - return this.entityRepository.put(orgId, data.entities) - } - - throw new EntityValidationException(result.issues) - } - - findByOrgId(orgId: string): Promise { - return this.entityRepository.findByOrgId(orgId) - } -} diff --git a/apps/armory/src/storage/http/rest/controller/storage.controller.ts b/apps/armory/src/storage/http/rest/controller/storage.controller.ts deleted file mode 100644 index 9b8540c98..000000000 --- a/apps/armory/src/storage/http/rest/controller/storage.controller.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { Body, Controller, Get, Put } from '@nestjs/common' -import { OrgId } from '../../../../shared/decorator/org-id.decorator' -import { EntityService } from '../../../core/service/entity.service' -import { UpdateEntitiesRequestDto } from '../dto/update-entities-request.dto' - -@Controller('/storage') -export class StorageController { - constructor(private entityService: EntityService) {} - - @Put('/entities') - async putEntities(@OrgId() orgId: string, @Body() body: UpdateEntitiesRequestDto) { - const entities = await this.entityService.put(orgId, body) - - return { entities } - } - - @Get('/entities') - async getEntities(@OrgId() orgId: string) { - const entities = await this.entityService.findByOrgId(orgId) - - return { entities } - } -} diff --git a/apps/armory/src/storage/http/rest/dto/address-book-account.dto.ts b/apps/armory/src/storage/http/rest/dto/address-book-account.dto.ts deleted file mode 100644 index 95fe6b4a1..000000000 --- a/apps/armory/src/storage/http/rest/dto/address-book-account.dto.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { AccountClassification, Address } from '@narval/policy-engine-shared' -import { ApiProperty } from '@nestjs/swagger' -import { IsEnum, IsEthereumAddress, IsNotEmpty, IsNumber, IsString } from 'class-validator' - -export class AddressBookAccountDto { - @IsString() - @IsNotEmpty() - uid: string - - @IsEnum(AccountClassification) - @ApiProperty({ enum: AccountClassification }) - classification: AccountClassification - - @IsEthereumAddress() - @ApiProperty({ - format: 'address', - type: String - }) - address: Address - - @IsNumber() - chainId: number -} diff --git a/apps/armory/src/storage/http/rest/dto/credential.dto.ts b/apps/armory/src/storage/http/rest/dto/credential.dto.ts deleted file mode 100644 index 2cc576a39..000000000 --- a/apps/armory/src/storage/http/rest/dto/credential.dto.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Alg } from '@narval/policy-engine-shared' -import { ApiProperty } from '@nestjs/swagger' -import { IsEnum, IsNotEmpty, IsString } from 'class-validator' - -export class CredentialDto { - @IsString() - @IsNotEmpty() - @ApiProperty() - uid: string - - @IsString() - @IsNotEmpty() - @ApiProperty() - pubKey: string - - @IsEnum(Alg) - @ApiProperty({ enum: Alg }) - alg: Alg - - @IsString() - @IsNotEmpty() - @ApiProperty() - userId: string -} diff --git a/apps/armory/src/storage/http/rest/dto/entities.dto.ts b/apps/armory/src/storage/http/rest/dto/entities.dto.ts deleted file mode 100644 index de8d42a9a..000000000 --- a/apps/armory/src/storage/http/rest/dto/entities.dto.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { Type } from 'class-transformer' -import { IsDefined, ValidateNested } from 'class-validator' -import { AddressBookAccountDto } from './address-book-account.dto' -import { CredentialDto } from './credential.dto' -import { TokenDto } from './token.dto' -import { UserGroupMemberDto } from './user-group-member.dto' -import { UserGroupDto } from './user-group.dto' -import { UserWalletDto } from './user-wallet.dto' -import { UserDto } from './user.dto' -import { WalletGroupMemberDto } from './wallet-group-member.dto' -import { WalletGroupDto } from './wallet-group.dto' -import { WalletDto } from './wallet.dto' - -export class EntitiesDto { - @IsDefined() - @Type(() => AddressBookAccountDto) - @ValidateNested({ each: true }) - addressBook: AddressBookAccountDto[] - - @IsDefined() - @Type(() => CredentialDto) - @ValidateNested({ each: true }) - credentials: CredentialDto[] - - @IsDefined() - @Type(() => TokenDto) - @ValidateNested({ each: true }) - tokens: TokenDto[] - - @IsDefined() - @Type(() => UserDto) - @ValidateNested({ each: true }) - users: UserDto[] - - @IsDefined() - @Type(() => UserGroupDto) - @ValidateNested({ each: true }) - userGroups: UserGroupDto[] - - @IsDefined() - @Type(() => UserGroupMemberDto) - @ValidateNested({ each: true }) - userGroupMembers: UserGroupMemberDto[] - - @IsDefined() - @Type(() => UserWalletDto) - @ValidateNested({ each: true }) - userWallets: UserWalletDto[] - - @IsDefined() - @Type(() => WalletDto) - @ValidateNested({ each: true }) - wallets: WalletDto[] - - @IsDefined() - @Type(() => WalletGroupDto) - @ValidateNested({ each: true }) - walletGroups: WalletGroupDto[] - - @IsDefined() - @Type(() => WalletGroupMemberDto) - @ValidateNested({ each: true }) - walletGroupMembers: WalletGroupMemberDto[] - - constructor(partial: Partial) { - Object.assign(this, partial) - } -} diff --git a/apps/armory/src/storage/http/rest/dto/token.dto.ts b/apps/armory/src/storage/http/rest/dto/token.dto.ts deleted file mode 100644 index 3ed746747..000000000 --- a/apps/armory/src/storage/http/rest/dto/token.dto.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Address } from '@narval/policy-engine-shared' -import { ApiProperty } from '@nestjs/swagger' -import { IsDefined, IsEthereumAddress, IsNotEmpty, IsNumber, IsString, Min } from 'class-validator' - -export class TokenDto { - @IsString() - @IsNotEmpty() - uid: string - - @IsEthereumAddress() - @ApiProperty({ - format: 'address', - type: String - }) - address: Address - - @IsNumber() - @IsDefined() - @Min(1) - chainId: number - - @IsString() - @IsNotEmpty() - symbol: string - - @IsNumber() - @IsDefined() - decimals: number - - constructor(partial: Partial) { - Object.assign(this, partial) - } -} diff --git a/apps/armory/src/storage/http/rest/dto/update-entities-request.dto.ts b/apps/armory/src/storage/http/rest/dto/update-entities-request.dto.ts deleted file mode 100644 index e575adef5..000000000 --- a/apps/armory/src/storage/http/rest/dto/update-entities-request.dto.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Type } from 'class-transformer' -import { IsDefined, ValidateNested } from 'class-validator' -import { EntitiesDto } from './entities.dto' - -export class UpdateEntitiesRequestDto { - @IsDefined() - @Type(() => EntitiesDto) - @ValidateNested() - entities: EntitiesDto -} diff --git a/apps/armory/src/storage/http/rest/dto/user-group-member.dto.ts b/apps/armory/src/storage/http/rest/dto/user-group-member.dto.ts deleted file mode 100644 index 59d05a42a..000000000 --- a/apps/armory/src/storage/http/rest/dto/user-group-member.dto.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger' -import { IsNotEmpty, IsString } from 'class-validator' - -export class UserGroupMemberDto { - @IsString() - @IsNotEmpty() - @ApiProperty() - groupId: string - - @IsString() - @IsNotEmpty() - @ApiProperty() - userId: string - - constructor(partial: Partial) { - Object.assign(this, partial) - } -} diff --git a/apps/armory/src/storage/http/rest/dto/user-group.dto.ts b/apps/armory/src/storage/http/rest/dto/user-group.dto.ts deleted file mode 100644 index 819804edc..000000000 --- a/apps/armory/src/storage/http/rest/dto/user-group.dto.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger' -import { IsNotEmpty, IsString } from 'class-validator' - -export class UserGroupDto { - @IsString() - @IsNotEmpty() - @ApiProperty() - uid: string - - constructor(partial: Partial) { - Object.assign(this, partial) - } -} diff --git a/apps/armory/src/storage/http/rest/dto/user-wallet.dto.ts b/apps/armory/src/storage/http/rest/dto/user-wallet.dto.ts deleted file mode 100644 index 192ece581..000000000 --- a/apps/armory/src/storage/http/rest/dto/user-wallet.dto.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger' -import { IsNotEmpty, IsString } from 'class-validator' - -export class UserWalletDto { - @IsString() - @IsNotEmpty() - @ApiProperty() - walletId: string - - @IsString() - @IsNotEmpty() - @ApiProperty() - userId: string - - constructor(partial: Partial) { - Object.assign(this, partial) - } -} diff --git a/apps/armory/src/storage/http/rest/dto/user.dto.ts b/apps/armory/src/storage/http/rest/dto/user.dto.ts deleted file mode 100644 index 830660892..000000000 --- a/apps/armory/src/storage/http/rest/dto/user.dto.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { UserRole } from '@narval/policy-engine-shared' -import { ApiProperty } from '@nestjs/swagger' -import { IsEnum, IsNotEmpty, IsString } from 'class-validator' - -export class UserDto { - @IsString() - @IsNotEmpty() - @ApiProperty() - uid: string - - @IsEnum(UserRole) - @ApiProperty({ enum: UserRole }) - role: UserRole - - constructor(partial: Partial) { - Object.assign(this, partial) - } -} diff --git a/apps/armory/src/storage/http/rest/dto/wallet-group-member.dto.ts b/apps/armory/src/storage/http/rest/dto/wallet-group-member.dto.ts deleted file mode 100644 index 54c5f4fbb..000000000 --- a/apps/armory/src/storage/http/rest/dto/wallet-group-member.dto.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { ApiProperty } from '@nestjs/swagger' -import { IsNotEmpty, IsString } from 'class-validator' - -export class WalletGroupMemberDto { - @IsString() - @IsNotEmpty() - @ApiProperty() - groupId: string - - @IsString() - @IsNotEmpty() - @ApiProperty() - walletId: string - - constructor(partial: Partial) { - Object.assign(this, partial) - } -} diff --git a/apps/armory/src/storage/http/rest/dto/wallet-group.dto.ts b/apps/armory/src/storage/http/rest/dto/wallet-group.dto.ts deleted file mode 100644 index 08d779bae..000000000 --- a/apps/armory/src/storage/http/rest/dto/wallet-group.dto.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { IsNotEmpty, IsString } from 'class-validator' - -export class WalletGroupDto { - @IsString() - @IsNotEmpty() - uid: string - - constructor(partial: Partial) { - Object.assign(this, partial) - } -} diff --git a/apps/armory/src/storage/http/rest/dto/wallet.dto.ts b/apps/armory/src/storage/http/rest/dto/wallet.dto.ts deleted file mode 100644 index 9e8f2af01..000000000 --- a/apps/armory/src/storage/http/rest/dto/wallet.dto.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { AccountType, Address } from '@narval/policy-engine-shared' -import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger' -import { IsEnum, IsEthereumAddress, IsNotEmpty, IsNumber, IsOptional, IsString } from 'class-validator' - -export class WalletDto { - @IsString() - @IsNotEmpty() - @ApiProperty() - uid: string - - @IsEnum(AccountType) - @ApiProperty({ enum: AccountType }) - accountType: AccountType - - @IsEthereumAddress() - @ApiProperty({ - type: String, - format: 'address' - }) - address: Address - - @IsNumber() - @IsOptional() - @ApiPropertyOptional() - chainId?: number - - constructor(partial: Partial) { - Object.assign(this, partial) - } -} diff --git a/apps/armory/src/storage/persistence/repository/in-memory-entity.repository.ts b/apps/armory/src/storage/persistence/repository/in-memory-entity.repository.ts deleted file mode 100644 index d17abd85c..000000000 --- a/apps/armory/src/storage/persistence/repository/in-memory-entity.repository.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Entities } from '@narval/policy-engine-shared' -import { Injectable } from '@nestjs/common' -import { EntityRepository } from '../../core/repository/entity.repository' - -@Injectable() -export class InMemoryEntityRepository implements EntityRepository { - private entities = new Map() - - async put(orgId: string, entities: Entities): Promise { - this.entities.set(orgId, entities) - - return entities - } - - async findByOrgId(orgId: string): Promise { - const entities = this.entities.get(orgId) - - return entities || null - } -} diff --git a/apps/armory/src/storage/storage.module.ts b/apps/armory/src/storage/storage.module.ts deleted file mode 100644 index 2fa8be906..000000000 --- a/apps/armory/src/storage/storage.module.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { ClassSerializerInterceptor, Module, ValidationPipe } from '@nestjs/common' -import { APP_INTERCEPTOR, APP_PIPE } from '@nestjs/core' -import { EntityRepository } from './core/repository/entity.repository' -import { EntityService } from './core/service/entity.service' -import { StorageController } from './http/rest/controller/storage.controller' -import { InMemoryEntityRepository } from './persistence/repository/in-memory-entity.repository' - -@Module({ - controllers: [StorageController], - providers: [ - EntityService, - { - provide: EntityRepository, - useClass: InMemoryEntityRepository - }, - { - provide: APP_INTERCEPTOR, - useClass: ClassSerializerInterceptor - }, - { - provide: APP_PIPE, - useClass: ValidationPipe - } - ] -}) -export class StorageModule {} From 855acd0ba590220a85d42547c8f9e018a06b949b Mon Sep 17 00:00:00 2001 From: William Calderipe Date: Tue, 27 Feb 2024 17:41:28 +0100 Subject: [PATCH 6/9] Delete store module schema --- .../module/persistence/schema/schema.prisma | 128 ------------------ 1 file changed, 128 deletions(-) diff --git a/apps/armory/src/shared/module/persistence/schema/schema.prisma b/apps/armory/src/shared/module/persistence/schema/schema.prisma index 980d6c551..1917a5a7a 100644 --- a/apps/armory/src/shared/module/persistence/schema/schema.prisma +++ b/apps/armory/src/shared/module/persistence/schema/schema.prisma @@ -119,131 +119,3 @@ model Feed { @@map("feed") } - -// -// Store Module -// - -model OrganizationEntity { - uid String @id - - @@map("organization_entity") -} - -// TODO (@wcalderipe, 12/02/24): Evaluate the location of this model. The -// Identity Provider (IdP) seems the right place. -model AuthCredentialEntity { - orgId String @map("org_id") - - uid String @id - pubKey String @map("pub_key") - alg String - userId String @map("user_id") - - @@map("auth_credential_entity") -} - -model UserEntity { - orgId String @map("org_id") - - uid String @id - role String - - wallets UserWalletEntity[] - groups UserGroupMemberEntity[] - - @@map("user_entity") -} - -model UserGroupEntity { - orgId String @map("org_id") - - uid String @id - - members UserGroupMemberEntity[] - - @@map("user_group_entity") -} - -model UserGroupMemberEntity { - userId String @map("user_uid") - groupId String @map("user_group_uid") - - user UserEntity @relation(fields: [userId], references: [uid], onDelete: Cascade, onUpdate: Cascade) - group UserGroupEntity @relation(fields: [groupId], references: [uid], onDelete: Cascade, onUpdate: Cascade) - - @@id([userId, groupId]) - @@map("user_group_member_entity") -} - -model WalletEntity { - orgId String @map("org_id") - - uid String @id - address String - accountType String @map("account_type") - /// Chain ID is only needed for chain-specific wallets (smart accounts). - chainId Int? @map("chain_id") - - groups WalletGroupMemberEntity[] - users UserWalletEntity[] - - @@map("wallet_entity") -} - -model WalletGroupEntity { - orgId String @map("org_id") - - uid String @id - - members WalletGroupMemberEntity[] - - @@map("wallet_group_entity") -} - -model WalletGroupMemberEntity { - walletId String @map("wallet_uid") - groupId String @map("wallet_group_uid") - - wallet WalletEntity @relation(fields: [walletId], references: [uid], onDelete: Cascade, onUpdate: Cascade) - group WalletGroupEntity @relation(fields: [groupId], references: [uid], onDelete: Cascade, onUpdate: Cascade) - - @@id([walletId, groupId]) - @@map("wallet_group_member_entity") -} - -model UserWalletEntity { - orgId String @map("org_id") - - userId String @map("user_id") - walletId String @map("wallet_id") - - wallet WalletEntity @relation(fields: [walletId], references: [uid], onDelete: Cascade, onUpdate: Cascade) - user UserEntity @relation(fields: [userId], references: [uid], onDelete: Cascade, onUpdate: Cascade) - - @@id([userId, walletId]) - @@map("user_wallet_entity") -} - -model AddressBookAccountEntity { - orgId String @map("org_id") - - uid String @id - address String - chainId Int @map("chain_id") - classification String - - @@map("address_book_account_entity") -} - -model TokenEntity { - orgId String @map("org_id") - - uid String @id - address String - symbol String - chainId Int @map("chain_id") - decimals Int - - @@map("token_entity") -} From 678139e3c28549bf024c6fd524a7ea0a08aea3ed Mon Sep 17 00:00:00 2001 From: William Calderipe Date: Wed, 28 Feb 2024 15:44:44 +0100 Subject: [PATCH 7/9] Fix entity types --- apps/armory/src/armory.module.ts | 4 +- .../service/authorization-request.service.ts | 4 +- .../app/opa/__test__/unit/opa.service.spec.ts | 104 ++++++++++++++++++ apps/policy-engine/src/app/opa/opa.service.ts | 36 +++++- .../app/persistence/repository/mock_data.ts | 6 +- .../src/opa/template/mockData.ts | 4 +- .../src/shared/types/entities.types.ts | 3 - .../src/lib/dev.fixture.ts | 7 +- 8 files changed, 149 insertions(+), 19 deletions(-) create mode 100644 apps/policy-engine/src/app/opa/__test__/unit/opa.service.spec.ts diff --git a/apps/armory/src/armory.module.ts b/apps/armory/src/armory.module.ts index ee2e38319..15a224ac3 100644 --- a/apps/armory/src/armory.module.ts +++ b/apps/armory/src/armory.module.ts @@ -4,7 +4,6 @@ import { APP_INTERCEPTOR } from '@nestjs/core' import { load } from './armory.config' import { OrchestrationModule } from './orchestration/orchestration.module' import { QueueModule } from './shared/module/queue/queue.module' -import { StoreModule } from './store/store.module' import { TransferTrackingModule } from './transfer-tracking/transfer-tracking.module' @Module({ @@ -15,8 +14,7 @@ import { TransferTrackingModule } from './transfer-tracking/transfer-tracking.mo }), QueueModule.forRoot(), OrchestrationModule, - TransferTrackingModule, - StoreModule + TransferTrackingModule ], providers: [ { diff --git a/apps/armory/src/orchestration/core/service/authorization-request.service.ts b/apps/armory/src/orchestration/core/service/authorization-request.service.ts index e8d416f4f..81e4c0e0f 100644 --- a/apps/armory/src/orchestration/core/service/authorization-request.service.ts +++ b/apps/armory/src/orchestration/core/service/authorization-request.service.ts @@ -45,7 +45,7 @@ export class AuthorizationRequestService { private priceService: PriceService, private feedService: FeedService, private clusterService: ClusterService - ) {} + ) { } async create(input: CreateAuthorizationRequest): Promise { const now = new Date() @@ -103,7 +103,7 @@ export class AuthorizationRequestService { } // eslint-disable-next-line @typescript-eslint/no-unused-vars - async complete(id: string) {} + async complete(id: string) { } async evaluate(input: AuthorizationRequest): Promise { if (input.status === AuthorizationRequestStatus.PROCESSING) { diff --git a/apps/policy-engine/src/app/opa/__test__/unit/opa.service.spec.ts b/apps/policy-engine/src/app/opa/__test__/unit/opa.service.spec.ts new file mode 100644 index 000000000..c57948b41 --- /dev/null +++ b/apps/policy-engine/src/app/opa/__test__/unit/opa.service.spec.ts @@ -0,0 +1,104 @@ +import { FIXTURE } from '@narval/policy-engine-shared' +import { Test } from '@nestjs/testing' +import { mock } from 'jest-mock-extended' +import { EntityRepository } from '../../../persistence/repository/entity.repository' +import { OpaService } from '../../opa.service' + +describe(OpaService.name, () => { + let service: OpaService + + const addressBookAccountOne = FIXTURE.ADDRESS_BOOK[0] + const addressBookAccountTwo = FIXTURE.ADDRESS_BOOK[1] + + const tokenOne = FIXTURE.TOKEN.usdc1 + const tokenTwo = FIXTURE.TOKEN.usdc137 + + const userGroupOne = FIXTURE.USER_GROUP.Engineering + const userGroupTwo = FIXTURE.USER_GROUP.Treasury + + const userOne = FIXTURE.USER.Alice + const userTwo = FIXTURE.USER.Bob + + const walletOne = FIXTURE.WALLET.Engineering + const walletTwo = FIXTURE.WALLET.Testing + + const walletGroupOne = FIXTURE.WALLET_GROUP.Engineering + const walletGroupTwo = FIXTURE.WALLET_GROUP.Treasury + + beforeEach(async () => { + const entityRepositoryMock = mock() + entityRepositoryMock.fetch.mockResolvedValue({ + addressBook: [addressBookAccountOne, addressBookAccountTwo], + credentials: [], + tokens: [tokenOne, tokenTwo], + userGroupMembers: [ + { + userId: userOne.uid, + groupId: userGroupOne.uid + } + ], + userGroups: [userGroupOne, userGroupTwo], + userWallets: [], + users: [userOne, userTwo], + walletGroupMembers: [ + { + walletId: walletOne.uid, + groupId: walletGroupOne.uid + } + ], + walletGroups: [walletGroupOne, walletGroupTwo], + wallets: [walletOne, walletTwo] + }) + + const module = await Test.createTestingModule({ + providers: [ + OpaService, + { + provide: EntityRepository, + useValue: entityRepositoryMock + } + ] + }).compile() + + service = module.get(OpaService) + }) + + describe('fetchEntityData', () => { + it('resolves with data formated for the engine', async () => { + const data = await service.fetchEntityData() + + expect(data).toEqual({ + entities: { + addressBook: { + [addressBookAccountOne.uid]: addressBookAccountOne, + [addressBookAccountTwo.uid]: addressBookAccountTwo + }, + tokens: { + [tokenOne.uid]: tokenOne, + [tokenTwo.uid]: tokenTwo + }, + userGroups: { + [userGroupOne.uid]: { + uid: userGroupOne.uid, + users: [userOne.uid] + } + }, + users: { + [userOne.uid]: userOne, + [userTwo.uid]: userTwo + }, + walletGroups: { + [walletGroupOne.uid]: { + uid: walletGroupOne.uid, + wallets: [walletOne.uid] + } + }, + wallets: { + [walletOne.uid]: walletOne, + [walletTwo.uid]: walletTwo + } + } + }) + }) + }) +}) diff --git a/apps/policy-engine/src/app/opa/opa.service.ts b/apps/policy-engine/src/app/opa/opa.service.ts index 1952409b5..e13121885 100644 --- a/apps/policy-engine/src/app/opa/opa.service.ts +++ b/apps/policy-engine/src/app/opa/opa.service.ts @@ -6,7 +6,7 @@ import Handlebars from 'handlebars' import { indexBy } from 'lodash/fp' import path from 'path' import { v4 as uuid } from 'uuid' -import { RegoData } from '../../shared/types/entities.types' +import { RegoData, UserGroup, WalletGroup } from '../../shared/types/entities.types' import { Policy } from '../../shared/types/policy.type' import { OpaResult, RegoInput } from '../../shared/types/rego' import { criterionToString, reasonToString } from '../../shared/utils/opa.utils' @@ -74,17 +74,43 @@ export class OpaService implements OnApplicationBootstrap { return { fileId, policies } } - private async fetchEntityData(): Promise { + async fetchEntityData(): Promise { const entities = await this.entityRepository.fetch(FIXTURE.ORGANIZATION.uid) + const userGroups = entities.userGroupMembers.reduce((groups, { userId, groupId }) => { + const group = groups.get(groupId) + + if (group) { + return groups.set(groupId, { + uid: groupId, + users: group.users.concat(userId) + }) + } else { + return groups.set(groupId, { uid: groupId, users: [userId] }) + } + }, new Map()) + + const walletGroups = entities.walletGroupMembers.reduce((groups, { walletId, groupId }) => { + const group = groups.get(groupId) + + if (group) { + return groups.set(groupId, { + uid: groupId, + wallets: group.wallets.concat(walletId) + }) + } else { + return groups.set(groupId, { uid: groupId, wallets: [walletId] }) + } + }, new Map()) + const data: RegoData = { entities: { addressBook: indexBy('uid', entities.addressBook), + tokens: indexBy('uid', entities.tokens), users: indexBy('uid', entities.users), - userGroups: indexBy('uid', entities.userGroups), + userGroups: Object.fromEntries(userGroups), wallets: indexBy('uid', entities.wallets), - walletGroups: indexBy('uid', entities.walletGroups), - tokens: indexBy('uid', entities.tokens) + walletGroups: Object.fromEntries(walletGroups) } } diff --git a/apps/policy-engine/src/app/persistence/repository/mock_data.ts b/apps/policy-engine/src/app/persistence/repository/mock_data.ts index a2fad1878..93d768b1d 100644 --- a/apps/policy-engine/src/app/persistence/repository/mock_data.ts +++ b/apps/policy-engine/src/app/persistence/repository/mock_data.ts @@ -13,8 +13,8 @@ export const ONE_ETH = BigInt('1000000000000000000') export const generateInboundRequest = async (): Promise => { const txRequest: TransactionRequest = { - from: FIXTURE.WALLET.engineering1.address, - to: FIXTURE.WALLET.treasury.address, + from: FIXTURE.WALLET.Engineering.address, + to: FIXTURE.WALLET.Treasury.address, chainId: 137, value: toHex(ONE_ETH), data: '0x00000000', @@ -26,7 +26,7 @@ export const generateInboundRequest = async (): Promise => { action: Action.SIGN_TRANSACTION, nonce: 'random-nonce-111', transactionRequest: txRequest, - resourceId: FIXTURE.WALLET.engineering1.uid + resourceId: FIXTURE.WALLET.Engineering.uid } const message = hashRequest(request) diff --git a/apps/policy-engine/src/opa/template/mockData.ts b/apps/policy-engine/src/opa/template/mockData.ts index 786738f14..20e7e56e7 100644 --- a/apps/policy-engine/src/opa/template/mockData.ts +++ b/apps/policy-engine/src/opa/template/mockData.ts @@ -24,7 +24,7 @@ export const examplePermitPolicy: Policy = { }, { criterion: Criterion.CHECK_WALLET_ID, - args: [FIXTURE.WALLET.engineering1.address] + args: [FIXTURE.WALLET.Engineering.address] }, { criterion: Criterion.CHECK_INTENT_TYPE, @@ -84,7 +84,7 @@ export const exampleForbidPolicy: Policy = { }, { criterion: Criterion.CHECK_WALLET_ID, - args: [FIXTURE.WALLET.engineering1.address] + args: [FIXTURE.WALLET.Engineering.address] }, { criterion: Criterion.CHECK_INTENT_TYPE, diff --git a/apps/policy-engine/src/shared/types/entities.types.ts b/apps/policy-engine/src/shared/types/entities.types.ts index 8e3dbe6de..515aa2f60 100644 --- a/apps/policy-engine/src/shared/types/entities.types.ts +++ b/apps/policy-engine/src/shared/types/entities.types.ts @@ -1,8 +1,5 @@ import { AccountClassification, AccountType, Address, UserRole } from '@narval/policy-engine-shared' -// TODO: Move these to shared? - -// ENTITIES: user, user group, wallet, wallet group, and address book. export type Organization = { uid: string } diff --git a/packages/policy-engine-shared/src/lib/dev.fixture.ts b/packages/policy-engine-shared/src/lib/dev.fixture.ts index 5a5b7b0c3..3c3623849 100644 --- a/packages/policy-engine-shared/src/lib/dev.fixture.ts +++ b/packages/policy-engine-shared/src/lib/dev.fixture.ts @@ -31,12 +31,17 @@ export const ORGANIZATION: OrganizationEntity = { uid: '7d704a62-d15e-4382-a826-1eb41563043b' } +// See doc/prefixed-test-ethereum-accounts.md export const UNSAFE_PRIVATE_KEY: Record = { // 0x000966c8bf232032cd23f9002c4513dfea2531be Root: '0x4d377dba5424a7c1545a3c7b0522592927d49d2600a66f12e07a3977bafd79ab', + // 0xaaa8ee1cbaa1856f4550c6fc24abb16c5c9b2a43 Alice: '0x454c9f13f6591f6482b17bdb6a671a7294500c7dd126111ce1643b03b6aeb354', + // 0xbbb7be636c3ad8cf9d08ba8bdba4abd2ef29bd23 Bob: '0x569a6614716a76fdb9cf21b842d012add85e680b51fd4fb773109a93c6c4f307', + // 0xccc1472fce4ec74a1e3f9653776acfc790cd0743 Carol: '0x33be709d0e3ffcd9ffa3d983d3fe3a55c34ab4eb4db2577847667262094f1786', + // 0xddd26a02e7c54e8dc373b9d2dcb309ecdeca815d Dave: '0x82a0cf4f0fdfd42d93ff328b73bfdbc9c8b4f95f5aedfae82059753fc08a180f' } @@ -233,7 +238,7 @@ export const ADDRESS_BOOK: AddressBookAccountEntity[] = [ } ] -export const TOKEN: Record = { +export const TOKEN: Record<`${string}1` | `${string}137`, TokenEntity> = { usdc1: { uid: 'eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', From 67df6d1b872693568dd54d32a84ff3b76beb8fa6 Mon Sep 17 00:00:00 2001 From: William Calderipe Date: Wed, 28 Feb 2024 15:50:42 +0100 Subject: [PATCH 8/9] Rename uid to id for all entities --- .../src/shared/module/persistence/seed.ts | 2 +- .../app/opa/__test__/unit/opa.service.spec.ts | 36 +++--- apps/policy-engine/src/app/opa/opa.service.ts | 18 +-- .../repository/entity.repository.ts | 2 +- .../app/persistence/repository/mock_data.ts | 2 +- .../src/opa/template/mockData.ts | 4 +- .../src/shared/types/entities.types.ts | 12 +- .../src/lib/dev.fixture.ts | 104 +++++++++--------- .../src/lib/type/entity.type.ts | 16 +-- .../src/lib/util/entity.util.ts | 38 +++---- 10 files changed, 117 insertions(+), 117 deletions(-) diff --git a/apps/armory/src/shared/module/persistence/seed.ts b/apps/armory/src/shared/module/persistence/seed.ts index cc7862267..a3c1e7597 100644 --- a/apps/armory/src/shared/module/persistence/seed.ts +++ b/apps/armory/src/shared/module/persistence/seed.ts @@ -10,7 +10,7 @@ const prisma = new PrismaClient() const orgs: Organization[] = [ { - id: FIXTURE.ORGANIZATION.uid, + id: FIXTURE.ORGANIZATION.id, name: 'Dev', createdAt: now, updatedAt: now diff --git a/apps/policy-engine/src/app/opa/__test__/unit/opa.service.spec.ts b/apps/policy-engine/src/app/opa/__test__/unit/opa.service.spec.ts index c57948b41..ed3976f82 100644 --- a/apps/policy-engine/src/app/opa/__test__/unit/opa.service.spec.ts +++ b/apps/policy-engine/src/app/opa/__test__/unit/opa.service.spec.ts @@ -33,8 +33,8 @@ describe(OpaService.name, () => { tokens: [tokenOne, tokenTwo], userGroupMembers: [ { - userId: userOne.uid, - groupId: userGroupOne.uid + userId: userOne.id, + groupId: userGroupOne.id } ], userGroups: [userGroupOne, userGroupTwo], @@ -42,8 +42,8 @@ describe(OpaService.name, () => { users: [userOne, userTwo], walletGroupMembers: [ { - walletId: walletOne.uid, - groupId: walletGroupOne.uid + walletId: walletOne.id, + groupId: walletGroupOne.id } ], walletGroups: [walletGroupOne, walletGroupTwo], @@ -70,32 +70,32 @@ describe(OpaService.name, () => { expect(data).toEqual({ entities: { addressBook: { - [addressBookAccountOne.uid]: addressBookAccountOne, - [addressBookAccountTwo.uid]: addressBookAccountTwo + [addressBookAccountOne.id]: addressBookAccountOne, + [addressBookAccountTwo.id]: addressBookAccountTwo }, tokens: { - [tokenOne.uid]: tokenOne, - [tokenTwo.uid]: tokenTwo + [tokenOne.id]: tokenOne, + [tokenTwo.id]: tokenTwo }, userGroups: { - [userGroupOne.uid]: { - uid: userGroupOne.uid, - users: [userOne.uid] + [userGroupOne.id]: { + id: userGroupOne.id, + users: [userOne.id] } }, users: { - [userOne.uid]: userOne, - [userTwo.uid]: userTwo + [userOne.id]: userOne, + [userTwo.id]: userTwo }, walletGroups: { - [walletGroupOne.uid]: { - uid: walletGroupOne.uid, - wallets: [walletOne.uid] + [walletGroupOne.id]: { + id: walletGroupOne.id, + wallets: [walletOne.id] } }, wallets: { - [walletOne.uid]: walletOne, - [walletTwo.uid]: walletTwo + [walletOne.id]: walletOne, + [walletTwo.id]: walletTwo } } }) diff --git a/apps/policy-engine/src/app/opa/opa.service.ts b/apps/policy-engine/src/app/opa/opa.service.ts index e13121885..7b576b780 100644 --- a/apps/policy-engine/src/app/opa/opa.service.ts +++ b/apps/policy-engine/src/app/opa/opa.service.ts @@ -75,18 +75,18 @@ export class OpaService implements OnApplicationBootstrap { } async fetchEntityData(): Promise { - const entities = await this.entityRepository.fetch(FIXTURE.ORGANIZATION.uid) + const entities = await this.entityRepository.fetch(FIXTURE.ORGANIZATION.id) const userGroups = entities.userGroupMembers.reduce((groups, { userId, groupId }) => { const group = groups.get(groupId) if (group) { return groups.set(groupId, { - uid: groupId, + id: groupId, users: group.users.concat(userId) }) } else { - return groups.set(groupId, { uid: groupId, users: [userId] }) + return groups.set(groupId, { id: groupId, users: [userId] }) } }, new Map()) @@ -95,21 +95,21 @@ export class OpaService implements OnApplicationBootstrap { if (group) { return groups.set(groupId, { - uid: groupId, + id: groupId, wallets: group.wallets.concat(walletId) }) } else { - return groups.set(groupId, { uid: groupId, wallets: [walletId] }) + return groups.set(groupId, { id: groupId, wallets: [walletId] }) } }, new Map()) const data: RegoData = { entities: { - addressBook: indexBy('uid', entities.addressBook), - tokens: indexBy('uid', entities.tokens), - users: indexBy('uid', entities.users), + addressBook: indexBy('id', entities.addressBook), + tokens: indexBy('id', entities.tokens), + users: indexBy('id', entities.users), userGroups: Object.fromEntries(userGroups), - wallets: indexBy('uid', entities.wallets), + wallets: indexBy('id', entities.wallets), walletGroups: Object.fromEntries(walletGroups) } } diff --git a/apps/policy-engine/src/app/persistence/repository/entity.repository.ts b/apps/policy-engine/src/app/persistence/repository/entity.repository.ts index 27e1b0485..b3f180abf 100644 --- a/apps/policy-engine/src/app/persistence/repository/entity.repository.ts +++ b/apps/policy-engine/src/app/persistence/repository/entity.repository.ts @@ -43,7 +43,7 @@ export class EntityRepository implements OnApplicationBootstrap { // from. It depends on the deployment model: standalone engine per // organization or cluster with multi tenant. if (!this.entities) { - const entities = await this.fetch(FIXTURE.ORGANIZATION.uid) + const entities = await this.fetch(FIXTURE.ORGANIZATION.id) this.entities = entities } diff --git a/apps/policy-engine/src/app/persistence/repository/mock_data.ts b/apps/policy-engine/src/app/persistence/repository/mock_data.ts index 93d768b1d..2f8de73af 100644 --- a/apps/policy-engine/src/app/persistence/repository/mock_data.ts +++ b/apps/policy-engine/src/app/persistence/repository/mock_data.ts @@ -26,7 +26,7 @@ export const generateInboundRequest = async (): Promise => { action: Action.SIGN_TRANSACTION, nonce: 'random-nonce-111', transactionRequest: txRequest, - resourceId: FIXTURE.WALLET.Engineering.uid + resourceId: FIXTURE.WALLET.Engineering.id } const message = hashRequest(request) diff --git a/apps/policy-engine/src/opa/template/mockData.ts b/apps/policy-engine/src/opa/template/mockData.ts index 20e7e56e7..4ef2227ea 100644 --- a/apps/policy-engine/src/opa/template/mockData.ts +++ b/apps/policy-engine/src/opa/template/mockData.ts @@ -49,7 +49,7 @@ export const examplePermitPolicy: Policy = { approvalCount: 2, countPrincipal: false, approvalEntityType: EntityType.User, - entityIds: [FIXTURE.USER.Bob.uid, FIXTURE.USER.Carol.uid] + entityIds: [FIXTURE.USER.Bob.id, FIXTURE.USER.Carol.id] }, { approvalCount: 1, @@ -80,7 +80,7 @@ export const exampleForbidPolicy: Policy = { }, { criterion: Criterion.CHECK_PRINCIPAL_ID, - args: [FIXTURE.USER.Alice.uid] + args: [FIXTURE.USER.Alice.id] }, { criterion: Criterion.CHECK_WALLET_ID, diff --git a/apps/policy-engine/src/shared/types/entities.types.ts b/apps/policy-engine/src/shared/types/entities.types.ts index 515aa2f60..c0e798c7e 100644 --- a/apps/policy-engine/src/shared/types/entities.types.ts +++ b/apps/policy-engine/src/shared/types/entities.types.ts @@ -5,17 +5,17 @@ export type Organization = { } export type User = { - uid: string // Pubkey + id: string // Pubkey role: UserRole } export type UserGroup = { - uid: string + id: string users: string[] // userIds } export type Wallet = { - uid: string + id: string address: Address accountType: AccountType chainId?: number @@ -23,19 +23,19 @@ export type Wallet = { } export type WalletGroup = { - uid: string + id: string wallets: string[] // walletIds } export type AddressBookAccount = { - uid: string + id: string address: Address chainId: number classification: AccountClassification } export type Token = { - uid: string + id: string address: Address symbol: string chainId: number diff --git a/packages/policy-engine-shared/src/lib/dev.fixture.ts b/packages/policy-engine-shared/src/lib/dev.fixture.ts index 3c3623849..8234b9cbf 100644 --- a/packages/policy-engine-shared/src/lib/dev.fixture.ts +++ b/packages/policy-engine-shared/src/lib/dev.fixture.ts @@ -28,7 +28,7 @@ type Groups = (typeof GROUPS)[number] type Wallets = (typeof WALLETS)[number] export const ORGANIZATION: OrganizationEntity = { - uid: '7d704a62-d15e-4382-a826-1eb41563043b' + id: '7d704a62-d15e-4382-a826-1eb41563043b' } // See doc/prefixed-test-ethereum-accounts.md @@ -55,102 +55,102 @@ export const ACCOUNT: Record = { export const USER: Record = { Root: { - uid: 'test-root-user-uid', + id: 'test-root-user-uid', role: UserRole.ROOT }, Alice: { - uid: 'test-alice-user-uid', + id: 'test-alice-user-uid', role: UserRole.ADMIN }, Bob: { - uid: 'test-bob-user-uid', + id: 'test-bob-user-uid', role: UserRole.ADMIN }, Carol: { - uid: 'test-carol-user-uid', + id: 'test-carol-user-uid', role: UserRole.MANAGER }, Dave: { - uid: 'test-dave-user-uid', + id: 'test-dave-user-uid', role: UserRole.MEMBER } } export const CREDENTIAL: Record = { Root: { - uid: sha256(ACCOUNT.Root.address).toLowerCase(), + id: sha256(ACCOUNT.Root.address).toLowerCase(), pubKey: ACCOUNT.Root.address, alg: Alg.ES256K, - userId: USER.Root.uid + userId: USER.Root.id }, Alice: { - uid: sha256(ACCOUNT.Alice.address).toLowerCase(), + id: sha256(ACCOUNT.Alice.address).toLowerCase(), pubKey: ACCOUNT.Alice.address, alg: Alg.ES256K, - userId: USER.Alice.uid + userId: USER.Alice.id }, Bob: { - uid: sha256(ACCOUNT.Bob.address).toLowerCase(), + id: sha256(ACCOUNT.Bob.address).toLowerCase(), pubKey: ACCOUNT.Bob.address, alg: Alg.ES256K, - userId: USER.Bob.uid + userId: USER.Bob.id }, Carol: { - uid: sha256(ACCOUNT.Carol.address).toLowerCase(), + id: sha256(ACCOUNT.Carol.address).toLowerCase(), pubKey: ACCOUNT.Carol.address, alg: Alg.ES256K, - userId: USER.Carol.uid + userId: USER.Carol.id }, Dave: { - uid: sha256(ACCOUNT.Dave.address).toLowerCase(), + id: sha256(ACCOUNT.Dave.address).toLowerCase(), pubKey: ACCOUNT.Dave.address, alg: Alg.ES256K, - userId: USER.Dave.uid + userId: USER.Dave.id } } export const USER_GROUP: Record = { Engineering: { - uid: 'test-engineering-user-group-uid' + id: 'test-engineering-user-group-uid' }, Treasury: { - uid: 'test-treasury-user-group-uid' + id: 'test-treasury-user-group-uid' } } export const USER_GROUP_MEMBER: UserGroupMemberEntity[] = [ { - groupId: USER_GROUP.Engineering.uid, - userId: USER.Alice.uid + groupId: USER_GROUP.Engineering.id, + userId: USER.Alice.id }, { - groupId: USER_GROUP.Engineering.uid, - userId: USER.Carol.uid + groupId: USER_GROUP.Engineering.id, + userId: USER.Carol.id }, { - groupId: USER_GROUP.Treasury.uid, - userId: USER.Bob.uid + groupId: USER_GROUP.Treasury.id, + userId: USER.Bob.id } ] export const WALLET: Record = { Testing: { - uid: 'eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e', + id: 'eip155:eoa:0xddcf208f219a6e6af072f2cfdc615b2c1805f98e', address: '0xddcf208f219a6e6af072f2cfdc615b2c1805f98e', accountType: AccountType.EOA }, Engineering: { - uid: 'eip155:eoa:0x22228d0504d4f3363a5b7fda1f5fff1c7bca8ad4', + id: 'eip155:eoa:0x22228d0504d4f3363a5b7fda1f5fff1c7bca8ad4', address: '0x22228d0504d4f3363a5b7fda1f5fff1c7bca8ad4', accountType: AccountType.EOA }, Treasury: { - uid: 'eip155:eoa:0x90d03a8971a2faa19a9d7ffdcbca28fe826a289b', // Prod guild 58 - treasury wallet + id: 'eip155:eoa:0x90d03a8971a2faa19a9d7ffdcbca28fe826a289b', // Prod guild 58 - treasury wallet address: '0x90d03a8971a2faa19a9d7ffdcbca28fe826a289b', accountType: AccountType.EOA }, Operation: { - uid: 'eip155:eoa:0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4', + id: 'eip155:eoa:0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4', address: '0x08a08d0504d4f3363a5b7fda1f5fff1c7bca8ad4', accountType: AccountType.EOA } @@ -158,80 +158,80 @@ export const WALLET: Record = { export const WALLET_GROUP: Record = { Engineering: { - uid: 'test-engineering-wallet-group-uid' + id: 'test-engineering-wallet-group-uid' }, Treasury: { - uid: 'test-treasury-wallet-group-uid' + id: 'test-treasury-wallet-group-uid' } } export const WALLET_GROUP_MEMBER: WalletGroupMemberEntity[] = [ { - groupId: WALLET_GROUP.Engineering.uid, - walletId: WALLET.Engineering.uid + groupId: WALLET_GROUP.Engineering.id, + walletId: WALLET.Engineering.id }, { - groupId: WALLET_GROUP.Engineering.uid, - walletId: WALLET.Testing.uid + groupId: WALLET_GROUP.Engineering.id, + walletId: WALLET.Testing.id }, { - groupId: WALLET_GROUP.Treasury.uid, - walletId: WALLET.Treasury.uid + groupId: WALLET_GROUP.Treasury.id, + walletId: WALLET.Treasury.id }, { - groupId: WALLET_GROUP.Treasury.uid, - walletId: WALLET.Operation.uid + groupId: WALLET_GROUP.Treasury.id, + walletId: WALLET.Operation.id } ] export const USER_WALLET: UserWalletEntity[] = [ { - walletId: WALLET.Operation.uid, - userId: USER.Alice.uid + walletId: WALLET.Operation.id, + userId: USER.Alice.id }, { - walletId: WALLET.Testing.uid, - userId: USER.Alice.uid + walletId: WALLET.Testing.id, + userId: USER.Alice.id }, { - walletId: WALLET.Treasury.uid, - userId: USER.Alice.uid + walletId: WALLET.Treasury.id, + userId: USER.Alice.id } ] export const ADDRESS_BOOK: AddressBookAccountEntity[] = [ { - uid: `eip155:137:${WALLET.Testing.address}`, + id: `eip155:137:${WALLET.Testing.address}`, address: WALLET.Testing.address, chainId: 137, classification: AccountClassification.WALLET }, { - uid: `eip155:1:${WALLET.Engineering.address}`, + id: `eip155:1:${WALLET.Engineering.address}`, address: WALLET.Engineering.address, chainId: 1, classification: AccountClassification.WALLET }, { - uid: `eip155:137:${WALLET.Engineering.address}`, + id: `eip155:137:${WALLET.Engineering.address}`, address: WALLET.Treasury.address, chainId: 137, classification: AccountClassification.WALLET }, { - uid: `eip155:137:${WALLET.Engineering.address}`, + id: `eip155:137:${WALLET.Engineering.address}`, address: WALLET.Engineering.address, chainId: 137, classification: AccountClassification.WALLET }, { - uid: `eip155:1:${WALLET.Treasury.address}`, + id: `eip155:1:${WALLET.Treasury.address}`, address: WALLET.Treasury.address, chainId: 1, classification: AccountClassification.WALLET }, { - uid: `eip155:137:${WALLET.Operation.address}`, + id: `eip155:137:${WALLET.Operation.address}`, address: WALLET.Operation.address, chainId: 137, classification: AccountClassification.WALLET @@ -240,14 +240,14 @@ export const ADDRESS_BOOK: AddressBookAccountEntity[] = [ export const TOKEN: Record<`${string}1` | `${string}137`, TokenEntity> = { usdc1: { - uid: 'eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', + id: 'eip155:1/erc20:0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', address: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', chainId: 1, symbol: 'USDC', decimals: 6 }, usdc137: { - uid: 'eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174', + id: 'eip155:137/erc20:0x2791bca1f2de4661ed88a30c99a7a9449aa84174', address: '0x2791bca1f2de4661ed88a30c99a7a9449aa84174', chainId: 137, symbol: 'USDC', diff --git a/packages/policy-engine-shared/src/lib/type/entity.type.ts b/packages/policy-engine-shared/src/lib/type/entity.type.ts index d26242597..16c22fbce 100644 --- a/packages/policy-engine-shared/src/lib/type/entity.type.ts +++ b/packages/policy-engine-shared/src/lib/type/entity.type.ts @@ -27,23 +27,23 @@ export const AccountClassification = { export type AccountClassification = (typeof AccountClassification)[keyof typeof AccountClassification] export type CredentialEntity = { - uid: string + id: string pubKey: string alg: Alg userId: string } export type OrganizationEntity = { - uid: string + id: string } export type UserEntity = { - uid: string + id: string role: UserRole } export type UserGroupEntity = { - uid: string + id: string } export type UserWalletEntity = { @@ -57,14 +57,14 @@ export type UserGroupMemberEntity = { } export type WalletEntity = { - uid: string + id: string address: Address accountType: AccountType chainId?: number } export type WalletGroupEntity = { - uid: string + id: string } export type WalletGroupMemberEntity = { @@ -73,14 +73,14 @@ export type WalletGroupMemberEntity = { } export type AddressBookAccountEntity = { - uid: string + id: string address: Address chainId: number classification: AccountClassification } export type TokenEntity = { - uid: string + id: string address: Address symbol: string chainId: number diff --git a/packages/policy-engine-shared/src/lib/util/entity.util.ts b/packages/policy-engine-shared/src/lib/util/entity.util.ts index c86c80222..7ff928bd6 100644 --- a/packages/policy-engine-shared/src/lib/util/entity.util.ts +++ b/packages/policy-engine-shared/src/lib/util/entity.util.ts @@ -16,8 +16,8 @@ export type ValidationOption = { } const validateUserGroupMemberIntegrity: Validator = (entities: Entities): ValidationIssue[] => { - const users = indexBy('uid', entities.users) - const userGroups = indexBy('uid', entities.userGroups) + const users = indexBy('id', entities.users) + const userGroups = indexBy('id', entities.userGroups) const userIssues: ValidationIssue[] = entities.userGroupMembers .filter(({ userId }) => !users[userId]) @@ -37,8 +37,8 @@ const validateUserGroupMemberIntegrity: Validator = (entities: Entities): Valida } const validateWalletGroupMemberIntegrity: Validator = (entities: Entities): ValidationIssue[] => { - const wallets = indexBy('uid', entities.wallets) - const walletGroups = indexBy('uid', entities.walletGroups) + const wallets = indexBy('id', entities.wallets) + const walletGroups = indexBy('id', entities.walletGroups) const walletIssues: ValidationIssue[] = entities.walletGroupMembers .filter(({ walletId }) => !wallets[walletId]) @@ -58,8 +58,8 @@ const validateWalletGroupMemberIntegrity: Validator = (entities: Entities): Vali } const validateUserWalletIntegrity: Validator = (entities: Entities): ValidationIssue[] => { - const wallets = indexBy('uid', entities.wallets) - const users = indexBy('uid', entities.users) + const wallets = indexBy('id', entities.wallets) + const users = indexBy('id', entities.users) const userIssues: ValidationIssue[] = entities.userWallets .filter(({ userId }) => !users[userId]) @@ -81,31 +81,31 @@ const validateUserWalletIntegrity: Validator = (entities: Entities): ValidationI const validateUniqueIdDuplication: Validator = (entities: Entities): ValidationIssue[] => { const code = 'UNIQUE_IDENTIFIER_DUPLICATION' - const findIssues = (values: T, message: (uid: string) => string): ValidationIssue[] => { + const findIssues = (values: T, message: (uid: string) => string): ValidationIssue[] => { return map( (uid) => ({ code, message: message(uid) }), - keys(pickBy((count: number) => count > 1, countBy('uid', values))) + keys(pickBy((count: number) => count > 1, countBy('id', values))) ) } return flatten([ - findIssues(entities.addressBook, (uid) => `The address book account ${uid} is duplicated`), - findIssues(entities.credentials, (uid) => `The credential ${uid} is duplicated`), - findIssues(entities.tokens, (uid) => `The token ${uid} is duplicated`), - findIssues(entities.userGroups, (uid) => `The user group ${uid} is duplicated`), - findIssues(entities.users, (uid) => `The user ${uid} is duplicated`), - findIssues(entities.walletGroups, (uid) => `The wallet group ${uid} is duplicated`), - findIssues(entities.wallets, (uid) => `The wallet ${uid} is duplicated`) + findIssues(entities.addressBook, (id) => `The address book account ${id} is duplicated`), + findIssues(entities.credentials, (id) => `The credential ${id} is duplicated`), + findIssues(entities.tokens, (id) => `The token ${id} is duplicated`), + findIssues(entities.userGroups, (id) => `The user group ${id} is duplicated`), + findIssues(entities.users, (id) => `The user ${id} is duplicated`), + findIssues(entities.walletGroups, (id) => `The wallet group ${id} is duplicated`), + findIssues(entities.wallets, (id) => `The wallet ${id} is duplicated`) ]) } const validateAddressBookUniqueIdFormat: Validator = (entities: Entities): ValidationIssue[] => { return entities.addressBook - .filter(({ uid }) => !isAccountId(uid)) - .map(({ uid }) => { + .filter(({ id: uid }) => !isAccountId(uid)) + .map(({ id: uid }) => { return { code: 'INVALID_UID_FORMAT', message: `address book account uid ${uid} is not a valid account id` @@ -115,8 +115,8 @@ const validateAddressBookUniqueIdFormat: Validator = (entities: Entities): Valid const validateTokenUniqueIdFormat: Validator = (entities: Entities): ValidationIssue[] => { return entities.tokens - .filter(({ uid }) => !isAssetId(uid)) - .map(({ uid }) => { + .filter(({ id: uid }) => !isAssetId(uid)) + .map(({ id: uid }) => { return { code: 'INVALID_UID_FORMAT', message: `token uid ${uid} is not a valid asset id` From 6583f758ef1f3ef044cba6fad21707894b024d4d Mon Sep 17 00:00:00 2001 From: William Calderipe Date: Wed, 28 Feb 2024 16:14:17 +0100 Subject: [PATCH 9/9] Add test for dev fixture Refactor message of entity validation issues --- .../src/lib/__test__/unit/dev.fixture.spec.ts | 8 +++ .../src/lib/dev.fixture.ts | 6 -- .../util/__test__/unit/entity.util.spec.ts | 64 +++++++++---------- .../src/lib/util/entity.util.ts | 30 ++++----- 4 files changed, 55 insertions(+), 53 deletions(-) create mode 100644 packages/policy-engine-shared/src/lib/__test__/unit/dev.fixture.spec.ts diff --git a/packages/policy-engine-shared/src/lib/__test__/unit/dev.fixture.spec.ts b/packages/policy-engine-shared/src/lib/__test__/unit/dev.fixture.spec.ts new file mode 100644 index 000000000..a41b316e2 --- /dev/null +++ b/packages/policy-engine-shared/src/lib/__test__/unit/dev.fixture.spec.ts @@ -0,0 +1,8 @@ +import { ENTITIES } from '../../dev.fixture' +import { validate } from '../../util/entity.util' + +describe('dev fixture', () => { + it('defines valid entities', () => { + expect(validate(ENTITIES)).toEqual({ success: true }) + }) +}) diff --git a/packages/policy-engine-shared/src/lib/dev.fixture.ts b/packages/policy-engine-shared/src/lib/dev.fixture.ts index 8234b9cbf..e0a12b579 100644 --- a/packages/policy-engine-shared/src/lib/dev.fixture.ts +++ b/packages/policy-engine-shared/src/lib/dev.fixture.ts @@ -218,12 +218,6 @@ export const ADDRESS_BOOK: AddressBookAccountEntity[] = [ chainId: 137, classification: AccountClassification.WALLET }, - { - id: `eip155:137:${WALLET.Engineering.address}`, - address: WALLET.Engineering.address, - chainId: 137, - classification: AccountClassification.WALLET - }, { id: `eip155:1:${WALLET.Treasury.address}`, address: WALLET.Treasury.address, diff --git a/packages/policy-engine-shared/src/lib/util/__test__/unit/entity.util.spec.ts b/packages/policy-engine-shared/src/lib/util/__test__/unit/entity.util.spec.ts index 38a07bd34..28cc836d6 100644 --- a/packages/policy-engine-shared/src/lib/util/__test__/unit/entity.util.spec.ts +++ b/packages/policy-engine-shared/src/lib/util/__test__/unit/entity.util.spec.ts @@ -22,8 +22,8 @@ describe('validate', () => { ...emptyEntities, userGroupMembers: [ { - groupId: USER_GROUP.Engineering.uid, - userId: USER.Alice.uid + groupId: USER_GROUP.Engineering.id, + userId: USER.Alice.id } ], users: [USER.Alice] @@ -35,7 +35,7 @@ describe('validate', () => { { code: 'ENTITY_NOT_FOUND', message: - "Couldn't create the user group member because the group test-engineering-user-group-uid is undefined" + "couldn't create the user group member because the group test-engineering-user-group-uid is undefined" } ] }) @@ -47,8 +47,8 @@ describe('validate', () => { userGroups: [USER_GROUP.Engineering], userGroupMembers: [ { - groupId: USER_GROUP.Engineering.uid, - userId: USER.Alice.uid + groupId: USER_GROUP.Engineering.id, + userId: USER.Alice.id } ] }) @@ -59,7 +59,7 @@ describe('validate', () => { { code: 'ENTITY_NOT_FOUND', message: - "Couldn't create the user group member for group test-engineering-user-group-uid because the user test-alice-user-uid is undefined" + "couldn't create the user group member for group test-engineering-user-group-uid because the user test-alice-user-uid is undefined" } ] }) @@ -71,8 +71,8 @@ describe('validate', () => { wallets: [WALLET.Engineering], walletGroupMembers: [ { - walletId: WALLET.Engineering.uid, - groupId: WALLET_GROUP.Engineering.uid + walletId: WALLET.Engineering.id, + groupId: WALLET_GROUP.Engineering.id } ] }) @@ -83,7 +83,7 @@ describe('validate', () => { { code: 'ENTITY_NOT_FOUND', message: - "Couldn't create the wallet group member because the group test-engineering-wallet-group-uid is undefined" + "couldn't create the wallet group member because the group test-engineering-wallet-group-uid is undefined" } ] }) @@ -95,8 +95,8 @@ describe('validate', () => { walletGroups: [WALLET_GROUP.Engineering], walletGroupMembers: [ { - walletId: WALLET.Engineering.uid, - groupId: WALLET_GROUP.Engineering.uid + walletId: WALLET.Engineering.id, + groupId: WALLET_GROUP.Engineering.id } ] }) @@ -107,7 +107,7 @@ describe('validate', () => { { code: 'ENTITY_NOT_FOUND', message: - "Couldn't create the wallet group member for group test-engineering-wallet-group-uid because the wallet eip155:eoa:0x22228d0504d4f3363a5b7fda1f5fff1c7bca8ad4 is undefined" + "couldn't create the wallet group member for group test-engineering-wallet-group-uid because the wallet eip155:eoa:0x22228d0504d4f3363a5b7fda1f5fff1c7bca8ad4 is undefined" } ] }) @@ -119,8 +119,8 @@ describe('validate', () => { wallets: [WALLET.Engineering], userWallets: [ { - userId: USER.Alice.uid, - walletId: WALLET.Engineering.uid + userId: USER.Alice.id, + walletId: WALLET.Engineering.id } ] }) @@ -130,7 +130,7 @@ describe('validate', () => { issues: [ { code: 'ENTITY_NOT_FOUND', - message: `Couldn't assign the wallet ${WALLET.Engineering.uid} because the user ${USER.Alice.uid} is undefined` + message: `couldn't assign the wallet ${WALLET.Engineering.id} because the user ${USER.Alice.id} is undefined` } ] }) @@ -142,8 +142,8 @@ describe('validate', () => { users: [USER.Alice], userWallets: [ { - userId: USER.Alice.uid, - walletId: WALLET.Engineering.uid + userId: USER.Alice.id, + walletId: WALLET.Engineering.id } ] }) @@ -153,7 +153,7 @@ describe('validate', () => { issues: [ { code: 'ENTITY_NOT_FOUND', - message: `Couldn't assign the wallet ${WALLET.Engineering.uid} because it's undefined` + message: `couldn't assign the wallet ${WALLET.Engineering.id} because it's undefined` } ] }) @@ -172,7 +172,7 @@ describe('validate', () => { issues: [ { code: 'UNIQUE_IDENTIFIER_DUPLICATION', - message: `The address book account ${ADDRESS_BOOK[0].uid} is duplicated` + message: `the address book account ${ADDRESS_BOOK[0].id} is duplicated` } ] }) @@ -189,7 +189,7 @@ describe('validate', () => { issues: [ { code: 'UNIQUE_IDENTIFIER_DUPLICATION', - message: `The credential ${CREDENTIAL.Alice.uid} is duplicated` + message: `the credential ${CREDENTIAL.Alice.id} is duplicated` } ] }) @@ -206,7 +206,7 @@ describe('validate', () => { issues: [ { code: 'UNIQUE_IDENTIFIER_DUPLICATION', - message: `The token ${TOKEN.usdc1.uid} is duplicated` + message: `the token ${TOKEN.usdc1.id} is duplicated` } ] }) @@ -223,7 +223,7 @@ describe('validate', () => { issues: [ { code: 'UNIQUE_IDENTIFIER_DUPLICATION', - message: `The user group ${USER_GROUP.Engineering.uid} is duplicated` + message: `the user group ${USER_GROUP.Engineering.id} is duplicated` } ] }) @@ -240,7 +240,7 @@ describe('validate', () => { issues: [ { code: 'UNIQUE_IDENTIFIER_DUPLICATION', - message: `The user ${USER.Alice.uid} is duplicated` + message: `the user ${USER.Alice.id} is duplicated` } ] }) @@ -257,7 +257,7 @@ describe('validate', () => { issues: [ { code: 'UNIQUE_IDENTIFIER_DUPLICATION', - message: `The wallet group ${WALLET_GROUP.Engineering.uid} is duplicated` + message: `the wallet group ${WALLET_GROUP.Engineering.id} is duplicated` } ] }) @@ -274,21 +274,21 @@ describe('validate', () => { issues: [ { code: 'UNIQUE_IDENTIFIER_DUPLICATION', - message: `The wallet ${WALLET.Engineering.uid} is duplicated` + message: `the wallet ${WALLET.Engineering.id} is duplicated` } ] }) }) }) - describe('uid format', () => { - it('fails when address book account uid is not an account id', () => { + describe('id format', () => { + it('fails when address book account id is not an account id', () => { const invalidAccountId = '16aba381-c54a-4f72-89bd-bd1e7c46ed29' const result = validate({ ...emptyEntities, addressBook: [ { - uid: invalidAccountId, + id: invalidAccountId, address: WALLET.Engineering.address, chainId: 137, classification: AccountClassification.WALLET @@ -302,20 +302,20 @@ describe('validate', () => { issues: [ { code: 'INVALID_UID_FORMAT', - message: `address book account uid ${invalidAccountId} is not a valid account id` + message: `address book account id ${invalidAccountId} is not a valid account id` } ] }) }) - it('fails when token uid is not an asset id', () => { + it('fails when token id is not an asset id', () => { const invalidAccountId = '16aba381-c54a-4f72-89bd-bd1e7c46ed29' const result = validate({ ...emptyEntities, tokens: [ { ...TOKEN.usdc1, - uid: invalidAccountId + id: invalidAccountId }, TOKEN.usdc137 ] @@ -326,7 +326,7 @@ describe('validate', () => { issues: [ { code: 'INVALID_UID_FORMAT', - message: `token uid ${invalidAccountId} is not a valid asset id` + message: `token id ${invalidAccountId} is not a valid asset id` } ] }) diff --git a/packages/policy-engine-shared/src/lib/util/entity.util.ts b/packages/policy-engine-shared/src/lib/util/entity.util.ts index 7ff928bd6..be265df34 100644 --- a/packages/policy-engine-shared/src/lib/util/entity.util.ts +++ b/packages/policy-engine-shared/src/lib/util/entity.util.ts @@ -23,14 +23,14 @@ const validateUserGroupMemberIntegrity: Validator = (entities: Entities): Valida .filter(({ userId }) => !users[userId]) .map(({ userId, groupId }) => ({ code: 'ENTITY_NOT_FOUND', - message: `Couldn't create the user group member for group ${groupId} because the user ${userId} is undefined` + message: `couldn't create the user group member for group ${groupId} because the user ${userId} is undefined` })) const groupIssues: ValidationIssue[] = entities.userGroupMembers .filter(({ groupId }) => !userGroups[groupId]) .map(({ groupId }) => ({ code: 'ENTITY_NOT_FOUND', - message: `Couldn't create the user group member because the group ${groupId} is undefined` + message: `couldn't create the user group member because the group ${groupId} is undefined` })) return [...userIssues, ...groupIssues] @@ -44,14 +44,14 @@ const validateWalletGroupMemberIntegrity: Validator = (entities: Entities): Vali .filter(({ walletId }) => !wallets[walletId]) .map(({ walletId, groupId }) => ({ code: 'ENTITY_NOT_FOUND', - message: `Couldn't create the wallet group member for group ${groupId} because the wallet ${walletId} is undefined` + message: `couldn't create the wallet group member for group ${groupId} because the wallet ${walletId} is undefined` })) const groupIssues: ValidationIssue[] = entities.walletGroupMembers .filter(({ groupId }) => !walletGroups[groupId]) .map(({ groupId }) => ({ code: 'ENTITY_NOT_FOUND', - message: `Couldn't create the wallet group member because the group ${groupId} is undefined` + message: `couldn't create the wallet group member because the group ${groupId} is undefined` })) return [...walletIssues, ...groupIssues] @@ -65,14 +65,14 @@ const validateUserWalletIntegrity: Validator = (entities: Entities): ValidationI .filter(({ userId }) => !users[userId]) .map(({ userId, walletId }) => ({ code: 'ENTITY_NOT_FOUND', - message: `Couldn't assign the wallet ${walletId} because the user ${userId} is undefined` + message: `couldn't assign the wallet ${walletId} because the user ${userId} is undefined` })) const walletIssues: ValidationIssue[] = entities.userWallets .filter(({ walletId }) => !wallets[walletId]) .map(({ walletId }) => ({ code: 'ENTITY_NOT_FOUND', - message: `Couldn't assign the wallet ${walletId} because it's undefined` + message: `couldn't assign the wallet ${walletId} because it's undefined` })) return [...userIssues, ...walletIssues] @@ -92,13 +92,13 @@ const validateUniqueIdDuplication: Validator = (entities: Entities): ValidationI } return flatten([ - findIssues(entities.addressBook, (id) => `The address book account ${id} is duplicated`), - findIssues(entities.credentials, (id) => `The credential ${id} is duplicated`), - findIssues(entities.tokens, (id) => `The token ${id} is duplicated`), - findIssues(entities.userGroups, (id) => `The user group ${id} is duplicated`), - findIssues(entities.users, (id) => `The user ${id} is duplicated`), - findIssues(entities.walletGroups, (id) => `The wallet group ${id} is duplicated`), - findIssues(entities.wallets, (id) => `The wallet ${id} is duplicated`) + findIssues(entities.addressBook, (id) => `the address book account ${id} is duplicated`), + findIssues(entities.credentials, (id) => `the credential ${id} is duplicated`), + findIssues(entities.tokens, (id) => `the token ${id} is duplicated`), + findIssues(entities.userGroups, (id) => `the user group ${id} is duplicated`), + findIssues(entities.users, (id) => `the user ${id} is duplicated`), + findIssues(entities.walletGroups, (id) => `the wallet group ${id} is duplicated`), + findIssues(entities.wallets, (id) => `the wallet ${id} is duplicated`) ]) } @@ -108,7 +108,7 @@ const validateAddressBookUniqueIdFormat: Validator = (entities: Entities): Valid .map(({ id: uid }) => { return { code: 'INVALID_UID_FORMAT', - message: `address book account uid ${uid} is not a valid account id` + message: `address book account id ${uid} is not a valid account id` } }) } @@ -119,7 +119,7 @@ const validateTokenUniqueIdFormat: Validator = (entities: Entities): ValidationI .map(({ id: uid }) => { return { code: 'INVALID_UID_FORMAT', - message: `token uid ${uid} is not a valid asset id` + message: `token id ${uid} is not a valid asset id` } }) }