diff --git a/apps/api-gateway/src/issuance/dtos/issuance.dto.ts b/apps/api-gateway/src/issuance/dtos/issuance.dto.ts index 7e8302f07..d3f090aff 100644 --- a/apps/api-gateway/src/issuance/dtos/issuance.dto.ts +++ b/apps/api-gateway/src/issuance/dtos/issuance.dto.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/array-type */ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; -import { ArrayMaxSize, ArrayMinSize, IsArray, IsBoolean, IsDefined, IsEmail, IsEnum, IsNotEmpty, IsObject, IsOptional, IsString, MaxLength, ValidateIf, ValidateNested } from 'class-validator'; +import { ArrayMaxSize, ArrayMinSize, IsArray, IsBoolean, IsDefined, IsEmail, IsEnum, IsNotEmpty, IsObject, IsOptional, IsString, MaxLength, ValidateNested } from 'class-validator'; import { IsCredentialJsonLdContext, SingleOrArray } from '../utils/helper'; import { IssueCredentialType, JsonLdCredentialDetailCredentialStatusOptions, JsonLdCredentialDetailOptionsOptions, JsonObject } from '../interfaces'; import { Transform, Type } from 'class-transformer'; @@ -125,11 +125,11 @@ export class Attribute { } export class CredentialsIssuanceDto { - @ValidateIf((obj) => obj.credentialType === IssueCredentialType.INDY) @ApiProperty({ example: 'string' }) @IsNotEmpty({ message: 'Credential definition Id is required' }) @IsString({ message: 'Credential definition id should be string' }) @Transform(({ value }) => value.trim()) + @IsOptional() credentialDefinitionId?: string; @ApiProperty({ example: 'string' }) diff --git a/apps/api-gateway/src/issuance/dtos/multi-connection.dto.ts b/apps/api-gateway/src/issuance/dtos/multi-connection.dto.ts index e58f6c7a4..23a4f56f0 100644 --- a/apps/api-gateway/src/issuance/dtos/multi-connection.dto.ts +++ b/apps/api-gateway/src/issuance/dtos/multi-connection.dto.ts @@ -13,12 +13,12 @@ class ConnectionAttributes { connectionId: string; @ApiProperty({ - example: [ - { - value: 'string', - name: 'string' - } - ] + example: [ + { + value: 'string', + name: 'string' + } + ] }) @IsArray() @ValidateNested({ each: true }) @@ -28,6 +28,7 @@ class ConnectionAttributes { @IsOptional() attributes?: Attribute[]; + @ApiProperty() @IsNotEmpty({ message: 'Please provide valid credential' }) @IsObject({ message: 'credential should be an object' }) @Type(() => Credential) @@ -36,11 +37,11 @@ class ConnectionAttributes { credential?: Credential; @ApiProperty() - @IsOptional() @IsNotEmpty({ message: 'Please provide valid options' }) @IsObject({ message: 'options should be an object' }) - @ValidateNested({ each: true }) @Type(() => JsonLdCredentialDetailOptions) + @IsOptional() + @ValidateNested({ each: true }) options?:JsonLdCredentialDetailOptions; } diff --git a/apps/api-gateway/src/issuance/issuance.controller.ts b/apps/api-gateway/src/issuance/issuance.controller.ts index b7b565717..7fb95be7b 100644 --- a/apps/api-gateway/src/issuance/issuance.controller.ts +++ b/apps/api-gateway/src/issuance/issuance.controller.ts @@ -534,17 +534,26 @@ export class IssuanceController { issueCredentialDto.credentialType = credentialType; const credOffer = issueCredentialDto?.credentialData || []; - if (IssueCredentialType.INDY !== credentialType && IssueCredentialType.JSONLD !== credentialType) { + + if (IssueCredentialType.INDY !== credentialType && IssueCredentialType.JSONLD !== credentialType) { throw new NotFoundException(ResponseMessages.issuance.error.invalidCredentialType); -} - if (issueCredentialDto.credentialType === IssueCredentialType.JSONLD && credOffer.every(offer => (!offer?.credential || 0 === Object.keys(offer?.credential).length))) { + } + + if (credentialType === IssueCredentialType.INDY && !issueCredentialDto.credentialDefinitionId) { + throw new BadRequestException(ResponseMessages.credentialDefinition.error.isRequired); + } + + if (issueCredentialDto.credentialType !== IssueCredentialType.INDY && !credOffer.every(offer => (!offer?.attributes || 0 === Object.keys(offer?.attributes).length))) { + throw new BadRequestException(ResponseMessages.issuance.error.attributesAreRequired); + } + + if (issueCredentialDto.credentialType === IssueCredentialType.JSONLD && credOffer.every(offer => (!offer?.credential || 0 === Object.keys(offer?.credential).length))) { throw new BadRequestException(ResponseMessages.issuance.error.credentialNotPresent); } - if (issueCredentialDto.credentialType === IssueCredentialType.JSONLD && credOffer.every(offer => (!offer?.options || 0 === Object.keys(offer?.options).length))) { + if (issueCredentialDto.credentialType === IssueCredentialType.JSONLD && credOffer.every(offer => (!offer?.options || 0 === Object.keys(offer?.options).length))) { throw new BadRequestException(ResponseMessages.issuance.error.optionsNotPresent); } - const getCredentialDetails = await this.issueCredentialService.sendCredentialCreateOffer(issueCredentialDto, user); const finalResponse: IResponse = { diff --git a/apps/issuance/src/issuance.service.ts b/apps/issuance/src/issuance.service.ts index dbf92c525..d64297b72 100644 --- a/apps/issuance/src/issuance.service.ts +++ b/apps/issuance/src/issuance.service.ts @@ -58,7 +58,6 @@ export class IssuanceService { const schemaResponse: SchemaDetails = await this.issuanceRepository.getCredentialDefinitionDetails( credentialDefinitionId ); - if (schemaResponse?.attributes) { const schemaResponseError = []; const attributesArray: IAttributes[] = JSON.parse(schemaResponse.attributes); @@ -82,31 +81,26 @@ export class IssuanceService { } const agentDetails = await this.issuanceRepository.getAgentEndPoint(orgId); - if (!agentDetails) { throw new NotFoundException(ResponseMessages.issuance.error.agentEndPointNotFound); } - const { agentEndPoint } = agentDetails; const orgAgentType = await this.issuanceRepository.getOrgAgentType(agentDetails?.orgAgentTypeId); - if (!orgAgentType) { throw new NotFoundException(ResponseMessages.issuance.error.orgAgentTypeNotFound); } const issuanceMethodLabel = 'create-offer'; - const url = await this.getAgentUrl(issuanceMethodLabel, orgAgentType, agentEndPoint, agentDetails?.tenantId); - const issuancePromises: Promise[] = []; + const issuancePromises = credentialData.map(async (credentials) => { + const { connectionId, attributes, credential, options } = credentials; + let issueData; - let issueData; - if (payload.credentialType === IssueCredentialType.INDY) { - for (const credentials of credentialData) { - const { connectionId, attributes } = credentials; + if (payload.credentialType === IssueCredentialType.INDY) { issueData = { - protocolVersion: 'v1', + protocolVersion: payload.protocolVersion || 'v1', connectionId, credentialFormats: { indy: { @@ -118,13 +112,7 @@ export class IssuanceService { autoAcceptCredential: payload.autoAcceptCredential || 'always', comment }; - } - } - - if (payload.credentialType === IssueCredentialType.JSONLD) { - for (const credentials of credentialData) { - const { connectionId, credential, options } = credentials; - + } else if (payload.credentialType === IssueCredentialType.JSONLD) { issueData = { protocolVersion: payload.protocolVersion || 'v2', connectionId, @@ -138,16 +126,17 @@ export class IssuanceService { comment: comment || '' }; } - } - await this.delay(500); - const credentialCreateOfferDetails = this._sendCredentialCreateOffer(issueData, url, orgId); - issuancePromises.push(credentialCreateOfferDetails); + await this.delay(500); + return this._sendCredentialCreateOffer(issueData, url, orgId); + }); + const results = await Promise.allSettled(issuancePromises); return results; } catch (error) { this.logger.error(`[sendCredentialCreateOffer] - error in create credentials : ${JSON.stringify(error)}`); const errorStack = error?.status?.message?.error?.reason || error?.status?.message?.error; + if (errorStack) { throw new RpcException({ error: errorStack?.message ? errorStack?.message : errorStack, diff --git a/libs/common/src/response-messages/index.ts b/libs/common/src/response-messages/index.ts index cad52d332..3ff9c9063 100644 --- a/libs/common/src/response-messages/index.ts +++ b/libs/common/src/response-messages/index.ts @@ -181,6 +181,7 @@ export const ResponseMessages = { NotSaved: 'Error in saving credential definition.', Conflict: 'Credential definition already exists', schemaIdNotFound: 'SchemaLedgerId not found', + isRequired: 'Credential definition Id is required', OrgDidNotFound: 'OrgDid not found', credDefIdNotFound: 'Credential Definition Id not found' } @@ -290,6 +291,7 @@ export const ResponseMessages = { orgAgentTypeNotFound: 'Organization agent type not found', credentialNotPresent: 'credential is required', optionsNotPresent:'options are required', + attributesAreRequired: 'attributes are required', invalidCredentialType:'invalid credential type' } },