Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support schema for key and web #801

Merged
merged 6 commits into from
Jun 23, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions apps/agent-service/src/agent-service.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1831,6 +1831,7 @@ export class AgentServiceService {
return schemaRequest;
} catch (error) {
this.logger.error(`Error in createW3CSchema request in agent service : ${JSON.stringify(error)}`);
throw error;
}
}

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(ResponseMessages.organisation.error.invalidOrgId); }})) 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
16 changes: 6 additions & 10 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,16 +14,12 @@ 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<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