Skip to content

Commit

Permalink
feat: support schema for key and web (#801)
Browse files Browse the repository at this point in the history
* feat/fix: added support for did:web and did:key and fix the error handling for schema creation

Signed-off-by: tipusinghaw <tipu.singh@ayanworks.com>

* feat: support for all type of schemas

Signed-off-by: tipusinghaw <tipu.singh@ayanworks.com>

* feat: added noledger enum

Signed-off-by: tipusinghaw <tipu.singh@ayanworks.com>

* fix: added validation for did network

Signed-off-by: tipusinghaw <tipu.singh@ayanworks.com>

---------

Signed-off-by: tipusinghaw <tipu.singh@ayanworks.com>
Signed-off-by: KulkarniShashank <shashank.kulkarni@ayanworks.com>
  • Loading branch information
tipusinghaw authored and KulkarniShashank committed Sep 11, 2024
1 parent cf8ad80 commit 7b60f22
Show file tree
Hide file tree
Showing 13 changed files with 527 additions and 292 deletions.
36 changes: 35 additions & 1 deletion apps/agent-service/src/agent-service.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1904,7 +1904,41 @@ export class AgentServiceService {
return data;
}

async natsCall(pattern: object, payload: object): Promise<{
async createW3CSchema(url: string, orgId: string, schemaRequestPayload): Promise<object> {
try {
const getApiKey = await this.getOrgAgentApiKey(orgId);
const schemaRequest = await this.commonService
.httpPost(url, schemaRequestPayload, { headers: { authorization: getApiKey } })
.then(async (response) => response);
return schemaRequest;
} catch (error) {
this.logger.error(`Error in createW3CSchema request in agent service : ${JSON.stringify(error)}`);
throw error;
}
}

async createConnectionInvitation(
url: string,
orgId: string,
connectionPayload: ICreateConnectionInvitation
): Promise<object> {
try {
const getApiKey = await this.getOrgAgentApiKey(orgId);

const createConnectionInvitation = await this.commonService
.httpPost(url, connectionPayload, { headers: { authorization: getApiKey } })
.then(async (response) => response);
return createConnectionInvitation;
} catch (error) {
this.logger.error(`Error in create connection invitation in agent service : ${JSON.stringify(error)}`);
throw error;
}
}

async natsCall(
pattern: object,
payload: object
): Promise<{
response: string;
}> {
try {
Expand Down
100 changes: 77 additions & 23 deletions apps/api-gateway/src/dtos/create-schema.dto.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,37 @@
import { ArrayMinSize, IsArray, IsBoolean, IsNotEmpty, IsOptional, IsString, ValidateNested } from 'class-validator';
import { ArrayMinSize, IsArray, IsBoolean, IsEnum, IsNotEmpty, IsOptional, IsString, ValidateNested } from 'class-validator';

import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { ApiExtraModels, ApiProperty, ApiPropertyOptional, getSchemaPath } from '@nestjs/swagger';
import { Transform, Type } from 'class-transformer';
import { IsNotSQLInjection, trim } from '@credebl/common/cast.helper';
import { JSONSchemaType, SchemaTypeEnum, W3CSchemaDataType } from '@credebl/enum/enum';

class W3CAttributeValue {

@ApiProperty()
@IsString()
@Transform(({ value }) => trim(value))
@IsNotEmpty({ message: 'attributeName is required' })
attributeName: string;

@ApiProperty({
description: 'The type of the schema',
enum: W3CSchemaDataType,
example: W3CSchemaDataType.STRING
})
@IsEnum(W3CSchemaDataType, { message: 'Schema data type must be a valid type' })
schemaDataType: W3CSchemaDataType;

@ApiProperty()
@IsString()
@Transform(({ value }) => trim(value))
@IsNotEmpty({ message: 'displayName is required' })
displayName: string;

@ApiProperty()
@IsBoolean()
@IsNotEmpty({ message: 'isRequired property is required' })
isRequired: boolean;
}
class AttributeValue {

@ApiProperty()
Expand Down Expand Up @@ -74,43 +102,69 @@ export class CreateSchemaDto {

export class CreateW3CSchemaDto {
@ApiProperty({
type: [],
type: [W3CAttributeValue],
'example': [
{
title: 'name',
type: 'string'
attributeName: 'name',
schemaDataType: 'string',
displayName: 'Name',
isRequired: true
}
]
})
@IsNotEmpty({ message: 'Schema attributes are required' })
schemaAttributes: SchemaAttributes [];
@ValidateNested({each: true})
@Type(() => W3CAttributeValue)
@IsNotEmpty()
attributes: W3CAttributeValue [];

@ApiProperty()
@IsString({ message: 'schemaName must be a string' })
@Transform(({ value }) => value.trim())
@IsNotEmpty({ message: 'schemaName is required' })
schemaName: string;

@ApiProperty()
@IsString({ message: 'did must be a string' })
@Transform(({ value }) => value.trim())
@IsNotEmpty({ message: 'did is required' })
did: string;


@ApiProperty()
@IsString({ message: 'description must be a string' })
@IsNotEmpty({ message: 'description is required' })
description: string;

@ApiProperty({
description: 'The type of the schema',
enum: JSONSchemaType,
example: JSONSchemaType.POLYGON_W3C
})
@IsEnum(JSONSchemaType, { message: 'Schema type must be a valid schema type' })
@IsNotEmpty({ message: 'Type is required' })
schemaType: JSONSchemaType;
}

export class SchemaAttributes {
@ApiProperty()
@IsNotEmpty({ message: 'type is required' })
@IsString({ message: 'type must be a string' })
type: string;
@ApiExtraModels(CreateSchemaDto, CreateW3CSchemaDto)
export class GenericSchemaDTO {
@ApiProperty({
description: 'The type of the schema',
enum: SchemaTypeEnum,
example: SchemaTypeEnum.INDY
})
@IsEnum(SchemaTypeEnum, { message: 'Type must be a valid schema type' })
@IsNotEmpty({ message: 'Type is required' })
type: SchemaTypeEnum;

@ApiProperty()
@IsNotEmpty({ message: 'title is required' })
@IsString({ message: 'title must be a string' })
title: string;
@ApiProperty({
type: Object,
oneOf: [
{ $ref: getSchemaPath(CreateSchemaDto) },
{ $ref: getSchemaPath(CreateW3CSchemaDto) }
]
})
@ValidateNested()
@Type(({ object }) => {
if (object.type === SchemaTypeEnum.INDY) {
return CreateSchemaDto;
} else if (object.type === SchemaTypeEnum.JSON) {
return CreateW3CSchemaDto;
}
})
schemaPayload:CreateSchemaDto | CreateW3CSchemaDto;


}
40 changes: 10 additions & 30 deletions apps/api-gateway/src/schema/schema.controller.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Controller, Logger, Post, Body, HttpStatus, UseGuards, Get, Query, BadRequestException, Res, UseFilters, Param, ParseUUIDPipe } from '@nestjs/common';
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable camelcase */
import { ApiOperation, ApiResponse, ApiTags, ApiBearerAuth, ApiForbiddenResponse, ApiUnauthorizedResponse, ApiQuery } from '@nestjs/swagger';
import { ApiOperation, ApiResponse, ApiTags, ApiBearerAuth, ApiForbiddenResponse, ApiUnauthorizedResponse, ApiQuery, ApiExtraModels, ApiBody, getSchemaPath } from '@nestjs/swagger';
import { SchemaService } from './schema.service';
import { AuthGuard } from '@nestjs/passport';
import { ApiResponseDto } from '../dtos/apiResponse.dto';
Expand All @@ -17,7 +17,7 @@ import { OrgRoles } from 'libs/org-roles/enums';
import { Roles } from '../authz/decorators/roles.decorator';
import { IUserRequestInterface } from './interfaces';
import { OrgRolesGuard } from '../authz/guards/org-roles.guard';
import { CreateSchemaDto, CreateW3CSchemaDto } from '../dtos/create-schema.dto';
import { GenericSchemaDTO } from '../dtos/create-schema.dto';
import { CustomExceptionFilter } from 'apps/api-gateway/common/exception-handler';
import { CredDefSortFields, SortFields } from '@credebl/enum/enum';

Expand Down Expand Up @@ -133,42 +133,22 @@ export class SchemaController {
return res.status(HttpStatus.OK).json(finalResponse);
}

@Post('/:orgId/polygon-w3c/schemas')
@ApiOperation({
summary: 'Create and sends a W3C-schema to the ledger.',
description: 'Create and sends a W3C-schema to the ledger.'
})
@Roles(OrgRoles.OWNER, OrgRoles.ADMIN, OrgRoles.ISSUER, OrgRoles.VERIFIER, OrgRoles.MEMBER)
@UseGuards(AuthGuard('jwt'), OrgRolesGuard)
@ApiResponse({ status: HttpStatus.CREATED, description: 'Success', type: ApiResponseDto })
async createW3CSchema(@Res() res: Response, @Body() schemaPayload: CreateW3CSchemaDto, @Param('orgId', new ParseUUIDPipe({exceptionFactory: (): Error => { throw new BadRequestException(ResponseMessages.organisation.error.invalidOrgId); }})) orgId: string, @User() user: IUserRequestInterface): Promise<Response> {

const schemaDetails = await this.appService.createW3CSchema(schemaPayload, orgId, user.id);
const finalResponse: IResponse = {
statusCode: HttpStatus.CREATED,
message: ResponseMessages.schema.success.create,
data: schemaDetails
};
return res.status(HttpStatus.CREATED).json(finalResponse);
}


@Post('/:orgId/schemas')
@ApiOperation({
summary: 'Create and sends a schema to the ledger.',
description: 'Create and sends a schema to the ledger.'
})
summary: 'Create and register various types of schemas.',
description: 'Enables the creation and registration of schemas across different systems: the Indy ledger, the Polygon blockchain network, and W3C ledger-less standards.'
}
)
@Roles(OrgRoles.OWNER, OrgRoles.ADMIN)
@UseGuards(AuthGuard('jwt'), OrgRolesGuard)
@ApiResponse({ status: HttpStatus.CREATED, description: 'Success', type: ApiResponseDto })
async createSchema(@Res() res: Response, @Body() schema: CreateSchemaDto, @Param('orgId', new ParseUUIDPipe({exceptionFactory: (): Error => { throw new BadRequestException(`Invalid format for orgId`); }})) orgId: string, @User() user: IUserRequestInterface): Promise<Response> {

schema.orgId = orgId;
const schemaDetails = await this.appService.createSchema(schema, user, schema.orgId);

async createSchema(@Res() res: Response, @Body() schemaDetails: GenericSchemaDTO, @Param('orgId', new ParseUUIDPipe({exceptionFactory: (): Error => { throw new BadRequestException(ResponseMessages.organisation.error.invalidOrgId); }})) orgId: string, @User() user: IUserRequestInterface): Promise<Response> {
const schemaResponse = await this.appService.createSchema(schemaDetails, user, orgId);
const finalResponse: IResponse = {
statusCode: HttpStatus.CREATED,
message: ResponseMessages.schema.success.create,
data: schemaDetails
data: schemaResponse
};
return res.status(HttpStatus.CREATED).json(finalResponse);
}
Expand Down
20 changes: 7 additions & 13 deletions apps/api-gateway/src/schema/schema.service.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Injectable, Inject } from '@nestjs/common';
import { ClientProxy } from '@nestjs/microservices';
import { BaseService } from '../../../../libs/service/base.service';
import { CreateSchemaDto } from '../dtos/create-schema.dto';
import { ISchemaSearchPayload, W3CSchemaPayload } from '../interfaces/ISchemaSearch.interface';
import { GenericSchemaDTO } from '../dtos/create-schema.dto';
import { ISchemaSearchPayload } from '../interfaces/ISchemaSearch.interface';
import { ISchemaInfo, IUserRequestInterface } from './interfaces';
import { ICredDefWithPagination, ISchemaData, ISchemasWithPagination, IW3CSchema } from '@credebl/common/interfaces/schema.interface';
import { ICredDefWithPagination, ISchemaData, ISchemasWithPagination } from '@credebl/common/interfaces/schema.interface';
import { GetCredentialDefinitionBySchemaIdDto } from './dtos/get-all-schema.dto';

@Injectable()
Expand All @@ -14,19 +14,13 @@ export class SchemaService extends BaseService {
@Inject('NATS_CLIENT') private readonly schemaServiceProxy: ClientProxy
) { super(`Schema Service`); }

createSchema(schema: CreateSchemaDto, user: IUserRequestInterface, orgId: string): Promise<ISchemaData> {
const payload = { schema, user, orgId };
createSchema(schemaDetails: GenericSchemaDTO, user: IUserRequestInterface, orgId: string): Promise<ISchemaData> {
const payload = { schemaDetails, user, orgId };
return this.sendNatsMessage(this.schemaServiceProxy, 'create-schema', payload);
}

createW3CSchema(schemaPayload: W3CSchemaPayload, orgId: string, user: string): Promise<IW3CSchema> {
const payload = { schemaPayload, orgId, user };
return this.sendNatsMessage(this.schemaServiceProxy, 'create-w3c-schema', payload);
}

getSchemaById(schemaId: string, orgId: string): Promise<{
response: object;
}> {

getSchemaById(schemaId: string, orgId: string): Promise<ISchemaInfo> {
const payload = { schemaId, orgId };
return this.sendNatsMessage(this.schemaServiceProxy, 'get-schema-by-id', payload);
}
Expand Down
2 changes: 1 addition & 1 deletion apps/ledger/src/schema/enum/schema.enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ export enum SortFields {

export enum W3CSchemaVersion {
W3C_SCHEMA_VERSION = 'draft-07'
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export interface SchemaPayload {
schemaName: string,
did: string,
description: string
jsonSchemaType?: string
}

export interface W3CSchemaAttributes {
Expand Down
38 changes: 38 additions & 0 deletions apps/ledger/src/schema/interfaces/schema.interface.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { JSONSchemaType, SchemaTypeEnum, W3CSchemaDataType } from '@credebl/enum/enum';
import { UserRoleOrgPermsDto } from '../dtos/user-role-org-perms.dto';

export interface IUserRequestInterface {
Expand Down Expand Up @@ -65,3 +66,40 @@ export interface ISchemasWithCount {
schemasCount: number;
schemasResult: ISchemaData[];
}
interface IW3CAttributeValue {
attributeName: string;
schemaDataType: W3CSchemaDataType;
displayName: string;
isRequired: boolean;
}

interface IAttributeValue {
attributeName: string;
schemaDataType: string;
displayName: string;
isRequired: boolean;
}

export interface ICreateSchema {
schemaVersion?: string;
schemaName: string;
attributes: IAttributeValue[];
orgId?: string;
orgDid?: string;
}
export interface ICreateW3CSchema {
attributes: IW3CAttributeValue[];
schemaName: string;
description: string;
schemaType: JSONSchemaType;
}
export interface IGenericSchema {
type: SchemaTypeEnum;
schemaPayload: ICreateSchema | ICreateW3CSchema;
}

export interface IschemaPayload {
schemaDetails: IGenericSchema,
user: IUserRequestInterface,
orgId: string
}
15 changes: 5 additions & 10 deletions apps/ledger/src/schema/schema.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import {
ISchema,
ISchemaCredDeffSearchInterface,
ISchemaExist,
ISchemaSearchPayload,
W3CSchemaPayload
ISchemaSearchPayload
} from './interfaces/schema-payload.interface';
import { schema } from '@prisma/client';
import {
Expand All @@ -15,22 +14,18 @@ import {
ISchemaDetails,
ISchemasWithPagination
} from '@credebl/common/interfaces/schema.interface';
import { IschemaPayload } from './interfaces/schema.interface';

@Controller('schema')
export class SchemaController {
constructor(private readonly schemaService: SchemaService) {}

@MessagePattern({ cmd: 'create-schema' })
async createSchema(payload: ISchema): Promise<ISchemaData> {
const { schema, user, orgId } = payload;
return this.schemaService.createSchema(schema, user, orgId);
async createSchema(payload: IschemaPayload): Promise<ISchemaData> {
const { schemaDetails, user, orgId } = payload;
return this.schemaService.createSchema(schemaDetails, user, orgId);
}

@MessagePattern({ cmd: 'create-w3c-schema' })
async createW3CSchema(payload: W3CSchemaPayload): Promise<string> {
const {orgId, schemaPayload, user} = payload;
return this.schemaService.createW3CSchema(orgId, schemaPayload, user);
}

@MessagePattern({ cmd: 'get-schema-by-id' })
async getSchemaById(payload: ISchema): Promise<schema> {
Expand Down
Loading

0 comments on commit 7b60f22

Please sign in to comment.