diff --git a/examples/bri-3/.vscode/settings.json b/examples/bri-3/.vscode/settings.json new file mode 100644 index 000000000..55712c19f --- /dev/null +++ b/examples/bri-3/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "typescript.tsdk": "node_modules/typescript/lib" +} \ No newline at end of file diff --git a/examples/bri-3/prisma/migrations/20240411211906_add_circuitinputstranslationschema_to_workstep/migration.sql b/examples/bri-3/prisma/migrations/20240411211906_add_circuitinputstranslationschema_to_workstep/migration.sql new file mode 100644 index 000000000..a3955ad69 --- /dev/null +++ b/examples/bri-3/prisma/migrations/20240411211906_add_circuitinputstranslationschema_to_workstep/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Workstep" ADD COLUMN "circuitInputsTranslationSchema" JSONB; diff --git a/examples/bri-3/prisma/schema.prisma b/examples/bri-3/prisma/schema.prisma index 94387d0a0..9d21cc2ad 100644 --- a/examples/bri-3/prisma/schema.prisma +++ b/examples/bri-3/prisma/schema.prisma @@ -70,6 +70,7 @@ model Workstep { workgroupId String securityPolicy String privacyPolicy String + circuitInputsTranslationSchema Json? workflow Workflow[] workgroup Workgroup @relation(fields: [workgroupId], references: [id]) } diff --git a/examples/bri-3/src/bri/communication/agents/messaging.agent.spec.ts b/examples/bri-3/src/bri/communication/agents/messaging.agent.spec.ts index f4e8bf14a..dfeb432b4 100644 --- a/examples/bri-3/src/bri/communication/agents/messaging.agent.spec.ts +++ b/examples/bri-3/src/bri/communication/agents/messaging.agent.spec.ts @@ -36,9 +36,7 @@ describe('Messaging Agent', () => { // Assert expect(validationErrors.length).toBe(1); - expect(validationErrors[0]).toEqual( - 'test is not valid JSON. Error: SyntaxError: Unexpected token e in JSON at position 1', - ); + expect(validationErrors[0]).toMatch(/^test is not valid JSON./); }); it('Should return error when validating correct JSON raw message with invalid UUID in id field', () => { diff --git a/examples/bri-3/src/bri/workgroup/worksteps/agents/worksteps.agent.ts b/examples/bri-3/src/bri/workgroup/worksteps/agents/worksteps.agent.ts index 19ba3a875..33b690038 100644 --- a/examples/bri-3/src/bri/workgroup/worksteps/agents/worksteps.agent.ts +++ b/examples/bri-3/src/bri/workgroup/worksteps/agents/worksteps.agent.ts @@ -1,13 +1,21 @@ -import { Injectable, NotFoundException } from '@nestjs/common'; +import { + BadRequestException, + Injectable, + NotFoundException, +} from '@nestjs/common'; import { Workstep } from '../models/workstep'; import { v4 } from 'uuid'; +import { CircuitInputsParserService } from '../../../zeroKnowledgeProof/services/circuit/circuitInputsParser/circuitInputParser.service'; import { NOT_FOUND_ERR_MESSAGE } from '../api/err.messages'; import { WorkstepStorageAgent } from './workstepsStorage.agent'; @Injectable() export class WorkstepAgent { - constructor(private storageAgent: WorkstepStorageAgent) {} + constructor( + private storageAgent: WorkstepStorageAgent, + private cips: CircuitInputsParserService, + ) {} public createNewWorkstep( name: string, @@ -57,6 +65,20 @@ export class WorkstepAgent { workstepToUpdate.updatePrivacyPolicy(privacyPolicy); } + public throwIfCircuitInputTranslationSchemaInvalid(schema): void { + const error = this.cips.validateCircuitInputTranslationSchema(schema); + if (error) { + throw new BadRequestException(error); + } + } + + public updateCircuitInputTranslationSchema( + workstepToUpdate: Workstep, + schema: string, + ): void { + workstepToUpdate.updateCircuitInputTranslationSchema(schema); + } + public async fetchDeleteCandidateAndThrowIfDeleteValidationFails( id: string, ): Promise { diff --git a/examples/bri-3/src/bri/workgroup/worksteps/api/dtos/request/updateCircuitInputsSchema.dto.spec.ts b/examples/bri-3/src/bri/workgroup/worksteps/api/dtos/request/updateCircuitInputsSchema.dto.spec.ts new file mode 100644 index 000000000..73abd2744 --- /dev/null +++ b/examples/bri-3/src/bri/workgroup/worksteps/api/dtos/request/updateCircuitInputsSchema.dto.spec.ts @@ -0,0 +1,40 @@ +import { plainToInstance } from 'class-transformer'; +import { validate } from 'class-validator'; +import { SHOULD_NOT_BE_EMPTY_VALIDATION_MESSAGE } from '../../../../../shared/constants'; +import { UpdateCircuitInputsSchemaDto } from './updateCircuitInputsSchema.dto'; + +describe('UpdateCircuitInputsSchemaDto', () => { + it('should return error in case schema not provided.', async () => { + // Arrange + const dto = { wrong: '1' }; + const setCircuitInputsSchemaDto = plainToInstance( + UpdateCircuitInputsSchemaDto, + dto, + ); + + // Act + const errors = await validate(setCircuitInputsSchemaDto); + + // Assert + expect(errors.length).toBe(1); + expect(errors[0].property).toEqual('schema'); + expect(errors[0].constraints?.isNotEmpty).toContain( + 'schema ' + SHOULD_NOT_BE_EMPTY_VALIDATION_MESSAGE, + ); + }); + + it('should return no error if all required properties provided.', async () => { + // Arrange + const dto = { schema: 'test' }; + const setCircuitInputsSchemaDto = plainToInstance( + UpdateCircuitInputsSchemaDto, + dto, + ); + + // Act + const errors = await validate(setCircuitInputsSchemaDto); + + // Assert + expect(errors.length).toBe(0); + }); +}); diff --git a/examples/bri-3/src/bri/workgroup/worksteps/api/dtos/request/updateCircuitInputsSchema.dto.ts b/examples/bri-3/src/bri/workgroup/worksteps/api/dtos/request/updateCircuitInputsSchema.dto.ts new file mode 100644 index 000000000..d31325226 --- /dev/null +++ b/examples/bri-3/src/bri/workgroup/worksteps/api/dtos/request/updateCircuitInputsSchema.dto.ts @@ -0,0 +1,6 @@ +import { IsNotEmpty } from 'class-validator'; + +export class UpdateCircuitInputsSchemaDto { + @IsNotEmpty() + schema: string; +} diff --git a/examples/bri-3/src/bri/workgroup/worksteps/api/dtos/response/workstep.dto.ts b/examples/bri-3/src/bri/workgroup/worksteps/api/dtos/response/workstep.dto.ts index 20235122b..dc2c27c7e 100644 --- a/examples/bri-3/src/bri/workgroup/worksteps/api/dtos/response/workstep.dto.ts +++ b/examples/bri-3/src/bri/workgroup/worksteps/api/dtos/response/workstep.dto.ts @@ -21,4 +21,7 @@ export class WorkstepDto { @AutoMap() privacyPolicy: string; + + @AutoMap() + circuitInputsTranslationSchema: string; } diff --git a/examples/bri-3/src/bri/workgroup/worksteps/api/worksteps.controller.spec.ts b/examples/bri-3/src/bri/workgroup/worksteps/api/worksteps.controller.spec.ts index 916229b27..a291dafc2 100644 --- a/examples/bri-3/src/bri/workgroup/worksteps/api/worksteps.controller.spec.ts +++ b/examples/bri-3/src/bri/workgroup/worksteps/api/worksteps.controller.spec.ts @@ -1,24 +1,26 @@ +import { classes } from '@automapper/classes'; +import { AutomapperModule } from '@automapper/nestjs'; import { NotFoundException } from '@nestjs/common'; import { CqrsModule } from '@nestjs/cqrs'; import { Test, TestingModule } from '@nestjs/testing'; +import { DeepMockProxy, mockDeep } from 'jest-mock-extended'; +import { validate as uuidValidate, version as uuidVersion } from 'uuid'; +import { uuid } from 'uuidv4'; +import { LoggingService } from '../../../../shared/logging/logging.service'; +import { CircuitInputsParserService } from '../../../zeroKnowledgeProof/services/circuit/circuitInputsParser/circuitInputParser.service'; import { WorkstepAgent } from '../agents/worksteps.agent'; +import { WorkstepStorageAgent } from '../agents/workstepsStorage.agent'; import { CreateWorkstepCommandHandler } from '../capabilities/createWorkstep/createWorkstepCommand.handler'; import { DeleteWorkstepCommandHandler } from '../capabilities/deleteWorkstep/deleteWorkstepCommand.handler'; import { GetAllWorkstepsQueryHandler } from '../capabilities/getAllWorksteps/getAllWorkstepsQuery.handler'; import { GetWorkstepByIdQueryHandler } from '../capabilities/getWorkstepById/getWorkstepByIdQuery.handler'; import { UpdateWorkstepCommandHandler } from '../capabilities/updateWorkstep/updateWorkstep.command.handler'; -import { WorkstepStorageAgent } from '../agents/workstepsStorage.agent'; +import { Workstep } from '../models/workstep'; +import { WorkstepProfile } from '../workstep.profile'; import { CreateWorkstepDto } from './dtos/request/createWorkstep.dto'; import { UpdateWorkstepDto } from './dtos/request/updateWorkstep.dto'; import { NOT_FOUND_ERR_MESSAGE } from './err.messages'; import { WorkstepController } from './worksteps.controller'; -import { validate as uuidValidate, version as uuidVersion } from 'uuid'; -import { WorkstepProfile } from '../workstep.profile'; -import { classes } from '@automapper/classes'; -import { AutomapperModule } from '@automapper/nestjs'; -import { mockDeep, DeepMockProxy } from 'jest-mock-extended'; -import { Workstep } from '../models/workstep'; -import { uuid } from 'uuidv4'; describe('WorkstepController', () => { let wController: WorkstepController; @@ -47,6 +49,8 @@ describe('WorkstepController', () => { controllers: [WorkstepController], providers: [ WorkstepAgent, + CircuitInputsParserService, + LoggingService, CreateWorkstepCommandHandler, UpdateWorkstepCommandHandler, DeleteWorkstepCommandHandler, diff --git a/examples/bri-3/src/bri/workgroup/worksteps/api/worksteps.controller.ts b/examples/bri-3/src/bri/workgroup/worksteps/api/worksteps.controller.ts index 9154d9ed5..269007514 100644 --- a/examples/bri-3/src/bri/workgroup/worksteps/api/worksteps.controller.ts +++ b/examples/bri-3/src/bri/workgroup/worksteps/api/worksteps.controller.ts @@ -9,11 +9,13 @@ import { } from '@nestjs/common'; import { CommandBus, QueryBus } from '@nestjs/cqrs'; import { CheckAuthz } from '../../../authz/guards/authz.decorator'; +import { UpdateCircuitInputsSchemaCommand } from '../capabilities/updateCircuitInputsSchema/updateCircuitInputsSchema.command'; import { CreateWorkstepCommand } from '../capabilities/createWorkstep/createWorkstep.command'; import { DeleteWorkstepCommand } from '../capabilities/deleteWorkstep/deleteWorkstep.command'; import { GetAllWorkstepsQuery } from '../capabilities/getAllWorksteps/getAllWorksteps.query'; import { GetWorkstepByIdQuery } from '../capabilities/getWorkstepById/getWorkstepById.query'; import { UpdateWorkstepCommand } from '../capabilities/updateWorkstep/updateWorkstep.command'; +import { UpdateCircuitInputsSchemaDto } from './dtos/request/updateCircuitInputsSchema.dto'; import { CreateWorkstepDto } from './dtos/request/createWorkstep.dto'; import { UpdateWorkstepDto } from './dtos/request/updateWorkstep.dto'; import { WorkstepDto } from './dtos/response/workstep.dto'; @@ -71,6 +73,17 @@ export class WorkstepController { ); } + @Put('/:id/circuitinputsschema') + @CheckAuthz({ action: 'update', type: 'Workstep' }) + async updateCircuitInputsSchemaCommand( + @Param('id') id: string, + @Body() requestDto: UpdateCircuitInputsSchemaDto, + ): Promise { + return await this.commandBus.execute( + new UpdateCircuitInputsSchemaCommand(id, requestDto.schema), + ); + } + @Delete('/:id') @CheckAuthz({ action: 'delete', type: 'Workstep' }) async deleteWorkstep(@Param('id') id: string): Promise { diff --git a/examples/bri-3/src/bri/workgroup/worksteps/capabilities/updateCircuitInputsSchema/updateCircuitInputsSchema.command.handler.ts b/examples/bri-3/src/bri/workgroup/worksteps/capabilities/updateCircuitInputsSchema/updateCircuitInputsSchema.command.handler.ts new file mode 100644 index 000000000..a204d71d7 --- /dev/null +++ b/examples/bri-3/src/bri/workgroup/worksteps/capabilities/updateCircuitInputsSchema/updateCircuitInputsSchema.command.handler.ts @@ -0,0 +1,39 @@ +import { CommandHandler, ICommandHandler } from '@nestjs/cqrs'; +import { WorkstepAgent } from '../../agents/worksteps.agent'; +import { WorkstepStorageAgent } from '../../agents/workstepsStorage.agent'; +import { UpdateCircuitInputsSchemaCommand } from './updateCircuitInputsSchema.command'; +import { InjectMapper } from '@automapper/nestjs'; +import { Mapper } from '@automapper/core'; +import { Workstep } from '../../models/workstep'; +import { WorkstepDto } from '../../api/dtos/response/workstep.dto'; + +@CommandHandler(UpdateCircuitInputsSchemaCommand) +export class UpdateCircuitInputsSchemaCommandHandler + implements ICommandHandler +{ + constructor( + @InjectMapper() private readonly mapper: Mapper, + private agent: WorkstepAgent, + private storageAgent: WorkstepStorageAgent, + ) {} + + async execute(command: UpdateCircuitInputsSchemaCommand) { + const workstepToUpdate = + await this.agent.fetchUpdateCandidateAndThrowIfUpdateValidationFails( + command.workstepId, + ); + + this.agent.throwIfCircuitInputTranslationSchemaInvalid(command.schema); + + this.agent.updateCircuitInputTranslationSchema( + workstepToUpdate, + command.schema, + ); + + const updatedWorkstep = await this.storageAgent.updateWorkstep( + workstepToUpdate, + ); + + return this.mapper.map(updatedWorkstep, Workstep, WorkstepDto); + } +} diff --git a/examples/bri-3/src/bri/workgroup/worksteps/capabilities/updateCircuitInputsSchema/updateCircuitInputsSchema.command.ts b/examples/bri-3/src/bri/workgroup/worksteps/capabilities/updateCircuitInputsSchema/updateCircuitInputsSchema.command.ts new file mode 100644 index 000000000..30d5de5b5 --- /dev/null +++ b/examples/bri-3/src/bri/workgroup/worksteps/capabilities/updateCircuitInputsSchema/updateCircuitInputsSchema.command.ts @@ -0,0 +1,6 @@ +export class UpdateCircuitInputsSchemaCommand { + constructor( + public readonly workstepId: string, + public readonly schema: string, + ) {} +} diff --git a/examples/bri-3/src/bri/workgroup/worksteps/models/workstep.ts b/examples/bri-3/src/bri/workgroup/worksteps/models/workstep.ts index 210d0996f..569e213bb 100644 --- a/examples/bri-3/src/bri/workgroup/worksteps/models/workstep.ts +++ b/examples/bri-3/src/bri/workgroup/worksteps/models/workstep.ts @@ -22,6 +22,9 @@ export class Workstep { @AutoMap() privacyPolicy: string; // TODO Implement simple privacy policy inhereted from workgroup #487 + @AutoMap() + circuitInputsTranslationSchema: string; + constructor( id: string, name: string, @@ -63,4 +66,8 @@ export class Workstep { public updatePrivacyPolicy(newPrivacyPolicy: string): void { this.privacyPolicy = newPrivacyPolicy; } + + public updateCircuitInputTranslationSchema(schema): void { + this.circuitInputsTranslationSchema = schema; + } } diff --git a/examples/bri-3/src/bri/workgroup/worksteps/worksteps.module.ts b/examples/bri-3/src/bri/workgroup/worksteps/worksteps.module.ts index 39f587ab5..4288c40b7 100644 --- a/examples/bri-3/src/bri/workgroup/worksteps/worksteps.module.ts +++ b/examples/bri-3/src/bri/workgroup/worksteps/worksteps.module.ts @@ -2,6 +2,7 @@ import { Module } from '@nestjs/common'; import { CqrsModule } from '@nestjs/cqrs'; import { LoggingModule } from '../../../../src/shared/logging/logging.module'; import { PrismaModule } from '../../../shared/prisma/prisma.module'; +import { ZeroKnowledgeProofModule } from '../../zeroKnowledgeProof/zeroKnowledgeProof.module'; import { WorkstepAgent } from './agents/worksteps.agent'; import { WorkstepStorageAgent } from './agents/workstepsStorage.agent'; import { WorkstepController } from './api/worksteps.controller'; @@ -9,6 +10,7 @@ import { CreateWorkstepCommandHandler } from './capabilities/createWorkstep/crea import { DeleteWorkstepCommandHandler } from './capabilities/deleteWorkstep/deleteWorkstepCommand.handler'; import { GetAllWorkstepsQueryHandler } from './capabilities/getAllWorksteps/getAllWorkstepsQuery.handler'; import { GetWorkstepByIdQueryHandler } from './capabilities/getWorkstepById/getWorkstepByIdQuery.handler'; +import { UpdateCircuitInputsSchemaCommandHandler } from './capabilities/updateCircuitInputsSchema/updateCircuitInputsSchema.command.handler'; import { UpdateWorkstepCommandHandler } from './capabilities/updateWorkstep/updateWorkstep.command.handler'; import { WorkstepProfile } from './workstep.profile'; @@ -16,6 +18,7 @@ export const CommandHandlers = [ CreateWorkstepCommandHandler, UpdateWorkstepCommandHandler, DeleteWorkstepCommandHandler, + UpdateCircuitInputsSchemaCommandHandler, ]; export const QueryHandlers = [ @@ -24,7 +27,7 @@ export const QueryHandlers = [ ]; @Module({ - imports: [CqrsModule, LoggingModule, PrismaModule], + imports: [CqrsModule, LoggingModule, PrismaModule, ZeroKnowledgeProofModule], controllers: [WorkstepController], providers: [ ...CommandHandlers, diff --git a/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/circuitInputsParser/circuitInputParser.service.spec.ts b/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/circuitInputsParser/circuitInputParser.service.spec.ts index b6f2d5ffe..de452a9af 100644 --- a/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/circuitInputsParser/circuitInputParser.service.spec.ts +++ b/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/circuitInputsParser/circuitInputParser.service.spec.ts @@ -10,6 +10,138 @@ beforeAll(async () => { cips = new CircuitInputsParserService(loggingServiceMock); }); +describe('validateCircuitInputTranslationSchema', () => { + it('Should return "Missing mapping array" if mapping array is missing', () => { + // Arrange + const schema = '{}'; + + // Act + const result = cips.validateCircuitInputTranslationSchema(schema); + + // Assert + expect(result).toEqual('Missing mapping array'); + }); + + it('Should return "{circuitInput}" if any required property has incorrect type', () => { + // Arrange + const schema = + '{"mapping": [{"circuitInput": 123, "description": "desc1", "payloadJsonPath": "path1", "dataType": "string"}]}'; + + // Act + const result = cips.validateCircuitInputTranslationSchema(schema); + + // Assert + expect(result).toEqual('123 not of type string'); + }); + + it('Should return "{description}" if any required property has incorrect type', () => { + // Arrange + const schema = + '{"mapping": [{"circuitInput": "123", "description": false, "payloadJsonPath": "path1", "dataType": "string"}]}'; + + // Act + const result = cips.validateCircuitInputTranslationSchema(schema); + + // Assert + expect(result).toEqual('false not of type string'); + }); + + it('Should return "{payloadJsonPath}" if any required property has incorrect type', () => { + // Arrange + const schema = + '{"mapping": [{"circuitInput": "123", "description": "desc", "payloadJsonPath": 12, "dataType": "string"}]}'; + + // Act + const result = cips.validateCircuitInputTranslationSchema(schema); + + // Assert + expect(result).toEqual('12 not of type string'); + }); + + it('Should return "{dataType}" if any required property has incorrect type', () => { + // Arrange + const schema = + '{"mapping": [{"circuitInput": "123", "description": "desc", "payloadJsonPath": "path1", "dataType": 232}]}'; + + // Act + const result = cips.validateCircuitInputTranslationSchema(schema); + + // Assert + expect(result).toEqual('232 not of type string'); + }); + + it('Should return "arrayType not defined properly for {circuitInput}" if dataType is array and arrayType is not defined properly', () => { + // Arrange + const schema = + '{"mapping": [{"circuitInput": "input1", "description": "desc1", "payloadJsonPath": "path1", "dataType": "array", "arrayType": 123}]}'; + + // Act + const result = cips.validateCircuitInputTranslationSchema(schema); + + // Assert + expect(result).toEqual('arrayType not defined properly for input1'); + }); + + it('Should return "defaultValue not of type {dataType} for {circuitInput}" if defaultValue type does not match dataType', () => { + // Arrange + const schema = + '{"mapping": [{"circuitInput": "input1", "description": "desc1", "payloadJsonPath": "path1", "dataType": "string", "defaultValue": 123}]}'; + + // Act + const result = cips.validateCircuitInputTranslationSchema(schema); + + // Assert + expect(result).toEqual('defaultValue not of type string for input1'); + }); + + it('Should return error if an error occurs during schema parsing', () => { + // Arrange + const schema = 'invalid JSON'; + + // Act + const result = cips.validateCircuitInputTranslationSchema(schema); + + // Assert + expect(result).toMatch(/^Unexpected token/); + }); + + it('Should return "" if basic valid schema passed in', () => { + // Arrange + const schema = + '{"mapping": [{"circuitInput": "input1", "description": "desc1", "payloadJsonPath": "path1", "dataType": "string"}]}'; + + // Act + const result = cips.validateCircuitInputTranslationSchema(schema); + + // Assert + expect(result).toEqual(''); + }); + + it('Should return "" if valid schema with default value passed in', () => { + // Arrange + const schema = + '{"mapping": [{"circuitInput": "input1", "description": "desc1", "payloadJsonPath": "path1", "dataType": "string", "defaultValue": "123"}]}'; + + // Act + const result = cips.validateCircuitInputTranslationSchema(schema); + + // Assert + expect(result).toEqual(''); + }); + + it('Should return "" if valid schema with arrayType in', () => { + // Arrange + const schema = + '{"mapping": [{"circuitInput": "input1", "description": "desc1", "payloadJsonPath": "path1", "dataType": "array", "arrayType": "string"}]}'; + + // Act + const result = cips.validateCircuitInputTranslationSchema(schema); + + // Assert + expect(result).toEqual(''); + }); +}); + describe('CircuitInputsParserService', () => { it('Should return null if empty CircuitInputsMapping passed in', () => { // Arrange diff --git a/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/circuitInputsParser/circuitInputParser.service.ts b/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/circuitInputsParser/circuitInputParser.service.ts index dc30953e0..63da30b5f 100644 --- a/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/circuitInputsParser/circuitInputParser.service.ts +++ b/examples/bri-3/src/bri/zeroKnowledgeProof/services/circuit/circuitInputsParser/circuitInputParser.service.ts @@ -5,6 +5,51 @@ import { LoggingService } from '../../../../../shared/logging/logging.service'; export class CircuitInputsParserService { constructor(private readonly logger: LoggingService) {} + public validateCircuitInputTranslationSchema(schema: string): string { + try { + const parsedData: CircuitInputsMapping = JSON.parse(schema); + + if (!parsedData.mapping || !Array.isArray(parsedData.mapping)) { + return `Missing mapping array`; + } + + for (const mapping of parsedData.mapping) { + if (typeof mapping.circuitInput !== 'string') { + return `${mapping.circuitInput} not of type string`; + } + + if (typeof mapping.description !== 'string') { + return `${mapping.description} not of type string`; + } + + if (typeof mapping.payloadJsonPath !== 'string') { + return `${mapping.payloadJsonPath} not of type string`; + } + + if (typeof mapping.dataType !== 'string') { + return `${mapping.dataType} not of type string`; + } + + if (mapping.dataType === 'array') { + if (!mapping.arrayType || typeof mapping.arrayType !== 'string') { + return `arrayType not defined properly for ${mapping.circuitInput}`; + } + } + + if ( + mapping.defaultValue && + typeof mapping.defaultValue !== mapping.dataType + ) { + return `defaultValue not of type ${mapping.dataType} for ${mapping.circuitInput}`; + } + } + + return ''; + } catch (error) { + return error.message; + } + } + public applyMappingToJSONPayload(payload: string, cim: CircuitInputsMapping) { const result: any = {}; diff --git a/examples/bri-3/src/bri/zeroKnowledgeProof/zeroKnowledgeProof.module.ts b/examples/bri-3/src/bri/zeroKnowledgeProof/zeroKnowledgeProof.module.ts index 8cc5b1689..93d983ec6 100644 --- a/examples/bri-3/src/bri/zeroKnowledgeProof/zeroKnowledgeProof.module.ts +++ b/examples/bri-3/src/bri/zeroKnowledgeProof/zeroKnowledgeProof.module.ts @@ -1,15 +1,17 @@ import { Module } from '@nestjs/common'; import { CqrsModule } from '@nestjs/cqrs'; +import { LoggingModule } from '../../shared/logging/logging.module'; import { CcsmStorageAgent } from './agents/ccsmStorage.agent'; -import { SnarkjsCircuitService } from './services/circuit/snarkjs/snarkjs.service'; import { EthereumService } from './services/blockchain/ethereum/ethereum.service'; -import { LoggingModule } from '../../shared/logging/logging.module'; +import { CircuitInputsParserService } from './services/circuit/circuitInputsParser/circuitInputParser.service'; +import { SnarkjsCircuitService } from './services/circuit/snarkjs/snarkjs.service'; @Module({ imports: [CqrsModule, LoggingModule], providers: [ CcsmStorageAgent, + CircuitInputsParserService, { provide: 'ICircuitService', useClass: SnarkjsCircuitService, @@ -19,6 +21,11 @@ import { LoggingModule } from '../../shared/logging/logging.module'; useClass: EthereumService, }, ], - exports: ['ICircuitService', 'IBlockchainService', CcsmStorageAgent], + exports: [ + 'ICircuitService', + 'IBlockchainService', + CcsmStorageAgent, + CircuitInputsParserService, + ], }) export class ZeroKnowledgeProofModule {} diff --git a/examples/bri-3/test/bri.postman_collection.json b/examples/bri-3/test/bri.postman_collection.json index 7c53836b4..4bd28350c 100644 --- a/examples/bri-3/test/bri.postman_collection.json +++ b/examples/bri-3/test/bri.postman_collection.json @@ -1,10 +1,8 @@ { "info": { - "_postman_id": "ba45f484-70a4-4516-825f-e9747aeaaabe", - "name": "bri Copy", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", - "_exporter_id": "11201020", - "_collection_link": "https://speeding-moon-127141.postman.co/workspace/Baseline~2b0609f4-7b8a-4f42-a245-7e537015edbc/collection/11201020-ba45f484-70a4-4516-825f-e9747aeaaabe?action=share&creator=11201020&source=collection_link" + "_postman_id": "23da0214-5606-4a7b-a410-297ae21c0d76", + "name": "bri", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" }, "item": [ { @@ -437,6 +435,36 @@ }, "response": [] }, + { + "name": "Set Circut Inputs Translation SchemaCopy", + "request": { + "method": "PUT", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"schema\": \"{\\\"mapping\\\": [{\\\"circuitInput\\\": \\\"input1\\\", \\\"description\\\": \\\"desc1\\\", \\\"payloadJsonPath\\\": \\\"path1\\\", \\\"dataType\\\": \\\"string\\\"}]}\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:3000/worksteps/ac5888b8-0306-40d4-9961-1cf1dcc31042/circuitinputsschema", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "3000", + "path": [ + "worksteps", + "ac5888b8-0306-40d4-9961-1cf1dcc31042", + "circuitinputsschema" + ] + } + }, + "response": [] + }, { "name": "Create Workstep", "request": { @@ -742,7 +770,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"name\": \"hello1\",\n \"administratorIds\": [\"2a74c458-8cf7-4209-8e54-82fa064efe25\"],\n \"securityPolicy\": \"sec1\",\n \"privacyPolicy\": \"priv1\",\n \"participantIds\": [\"2a74c458-8cf7-4209-8e54-82fa064efe25\", \"92747004-9ff6-47ea-abf9-7dfaebd36d51\"],\n \"worksteps\": [],\n \"workflows\": []\n}", + "raw": "{\n \"name\": \"Test workgroup\",\n \"securityPolicy\": \"sec1\",\n \"privacyPolicy\": \"priv1\",\n \"worksteps\": [],\n \"workflows\": []\n}", "options": { "raw": { "language": "json" @@ -1103,7 +1131,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"publicKey\": \"sig\"\n}", + "raw": "{\n \"publicKey\": \"0x08872e27BC5d78F1FC4590803369492868A1FCCb\"\n}", "options": { "raw": { "language": "json" @@ -1132,7 +1160,7 @@ "header": [], "body": { "mode": "raw", - "raw": "{\n \"message\": \"msg\",\n \"signature\": \"sig\",\n \"publicKey\": \"pk\"\n}", + "raw": "{\n \"message\": \"d21107d6-3806-4fec-8371-90e16ef6afad\",\n \"signature\": \"40e6294f76746ed7bb323df99fce0a2be7b1ea7595dc808eeac2d295ce1d5b45240e2726daa4b468c3e5a9e82ebcd2677bdd1b5f3ed11c307db4fe4fd71a6c1a1b\",\n \"publicKey\": \"0x08872e27BC5d78F1FC4590803369492868A1FCCb\"\n}", "options": { "raw": { "language": "json" @@ -1155,100 +1183,6 @@ "response": [] } ] - }, - { - "name": "Merkle Tree", - "item": [ - { - "name": "Create Merkle Tree", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\n \"leaves\": [\"a\", \"b\", \"c\"],\n \"hashFunction\": \"sha256\"\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://localhost:3000/merkle", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "3000", - "path": [ - "merkle" - ] - } - }, - "response": [] - }, - { - "name": "Get Merkle Tree By Id", - "protocolProfileBehavior": { - "disableBodyPruning": true - }, - "request": { - "method": "GET", - "header": [], - "body": { - "mode": "raw", - "raw": "", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://localhost:3000/merkle/7c2a351a-fd43-468c-a75d-64a0d1b54b8a", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "3000", - "path": [ - "merkle", - "7c2a351a-fd43-468c-a75d-64a0d1b54b8a" - ] - } - }, - "response": [] - }, - { - "name": "Delete Merkle Tree", - "request": { - "method": "DELETE", - "header": [], - "body": { - "mode": "raw", - "raw": "", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://localhost:3000/merkle/d5262706-bb63-4681-ba3e-9bba41960c1a", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "3000", - "path": [ - "merkle", - "d5262706-bb63-4681-ba3e-9bba41960c1a" - ] - } - }, - "response": [] - } - ] } ], "auth": { diff --git a/examples/bri-3/test/sriUseCase.e2e-spec.ts b/examples/bri-3/test/sriUseCase.e2e-spec.ts index a8fe4c6d1..a97e01505 100644 --- a/examples/bri-3/test/sriUseCase.e2e-spec.ts +++ b/examples/bri-3/test/sriUseCase.e2e-spec.ts @@ -140,6 +140,12 @@ describe('SRI use-case end-to-end test', () => { ); }); + it('Add a circuit input translation schema to a workstep', async () => { + const schema = + '{"mapping": [{"circuitInput": "input1", "description": "desc1", "payloadJsonPath": "path1", "dataType": "string"}]}'; + await addCircuitInputsSchema(createdWorkstepId, schema); + }); + it('Submits a transaction for execution of the workstep 1', async () => { // TODO: CheckAuthz on createTransaction and in other places // TODO: Faking two items in the payload as the circuit is hardcoded to 4 @@ -301,6 +307,21 @@ async function createWorkstepAndReturnId( return createdWorkstepResponse.text; } +async function addCircuitInputsSchema( + workstepId: string, + schema: string, +): Promise { + const addCircuitInputsSchemaResponse = await request(server) + .put(`/worksteps/${workstepId}/circuitinputsschema`) + .set('Authorization', `Bearer ${accessToken}`) + .send({ + schema: schema, + }) + .expect(200); + + return addCircuitInputsSchemaResponse.text; +} + async function createWorkflowAndReturnId( name: string, workgroupId: string,