diff --git a/apps/api-gateway/src/ecosystem/dtos/add-organizations.dto.ts b/apps/api-gateway/src/ecosystem/dtos/add-organizations.dto.ts new file mode 100644 index 000000000..717dba3aa --- /dev/null +++ b/apps/api-gateway/src/ecosystem/dtos/add-organizations.dto.ts @@ -0,0 +1,18 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { ArrayNotEmpty, ArrayUnique, IsArray, IsString, IsUUID } from 'class-validator'; + +export class AddOrganizationsDto { + @ApiProperty({ + example: ['32f54163-7166-48f1-93d8-ff217bdb0653'] + }) + @IsArray() + @ArrayNotEmpty({ message: 'Organization Ids array must not be empty' }) + @IsUUID('4', { each: true }) + @ArrayUnique({ message: 'Duplicate Organization Ids are not allowed' }) + @IsString({ each: true, message: 'Each organization Id in the array should be a string' }) + organizationIds: string[]; + + ecosystemId: string; + + orgId: string; +} diff --git a/apps/api-gateway/src/ecosystem/ecosystem.controller.ts b/apps/api-gateway/src/ecosystem/ecosystem.controller.ts index b1959df39..429fe1457 100644 --- a/apps/api-gateway/src/ecosystem/ecosystem.controller.ts +++ b/apps/api-gateway/src/ecosystem/ecosystem.controller.ts @@ -27,6 +27,7 @@ import { GetAllEndorsementsDto } from './dtos/get-all-endorsements.dto'; import { CreateEcosystemDto } from './dtos/create-ecosystem-dto'; import { PaginationDto } from '@credebl/common/dtos/pagination.dto'; import { IEcosystemInvitations, IEditEcosystem, IEndorsementTransaction } from 'apps/ecosystem/interfaces/ecosystem.interfaces'; +import { AddOrganizationsDto } from './dtos/add-organizations.dto'; @UseFilters(CustomExceptionFilter) @@ -305,6 +306,7 @@ export class EcosystemController { return res.status(HttpStatus.OK).json(finalResponse); } + @Post('/:ecosystemId/:orgId/transaction/schema') @ApiOperation({ summary: 'Request new schema', description: 'Create request for new schema' }) @ApiResponse({ status: HttpStatus.CREATED, description: 'Created', type: ApiResponseDto }) @@ -447,6 +449,45 @@ export class EcosystemController { } + /** + * + * @param orgId + * @param ecosystemId + */ + @Post('/:ecosystemId/:orgId/orgs') + @ApiOperation({ + summary: 'Add multiple organizations of ecosystem owner in ecosystem', + description: 'Add multiple organizations of ecosystem owner under the same ecosystem' + }) + @ApiResponse({ status: HttpStatus.CREATED, description: 'Created', type: ApiResponseDto }) + @ApiBearerAuth() + @UseGuards(AuthGuard('jwt'), OrgRolesGuard, EcosystemRolesGuard) + @EcosystemsRoles(EcosystemRoles.ECOSYSTEM_OWNER, EcosystemRoles.ECOSYSTEM_LEAD) + @Roles(OrgRoles.OWNER, OrgRoles.ADMIN) + async addOrganizationsInEcosystem( + @Body() addOrganizationsDto: AddOrganizationsDto, + @Param('ecosystemId', new ParseUUIDPipe({exceptionFactory: (): Error => { throw new BadRequestException(ResponseMessages.ecosystem.error.invalidEcosystemId); }})) ecosystemId: string, + @Param('orgId', new ParseUUIDPipe({exceptionFactory: (): Error => { throw new BadRequestException(ResponseMessages.organisation.error.invalidOrgId); }})) orgId: string, + @User() user: user, + @Res() res: Response + ): Promise { + + addOrganizationsDto.ecosystemId = ecosystemId; + addOrganizationsDto.orgId = orgId; + + const addOrganizations = await this.ecosystemService.addOrganizationsInEcosystem(addOrganizationsDto, user.id); + const { results, statusCode, message } = addOrganizations; + + const finalResponse: IResponse = { + statusCode, + message, + data: results + }; + + return res.status(statusCode).json(finalResponse); + } + + /** * * @param res diff --git a/apps/api-gateway/src/ecosystem/ecosystem.service.ts b/apps/api-gateway/src/ecosystem/ecosystem.service.ts index 6d5ae7cb3..fc5157bf1 100644 --- a/apps/api-gateway/src/ecosystem/ecosystem.service.ts +++ b/apps/api-gateway/src/ecosystem/ecosystem.service.ts @@ -14,6 +14,7 @@ import { EditEcosystemDto } from './dtos/edit-ecosystem-dto'; import { IEcosystemDashboard, IEcosystemInvitation, IEcosystemInvitations, IEcosystem, IEditEcosystem, IEndorsementTransaction, ISchemaResponse } from 'apps/ecosystem/interfaces/ecosystem.interfaces'; import { PaginationDto } from '@credebl/common/dtos/pagination.dto'; import { IEcosystemDetails } from '@credebl/common/interfaces/ecosystem.interface'; +import { AddOrganizationsDto } from './dtos/add-organizations.dto'; @Injectable() export class EcosystemService extends BaseService { @@ -78,6 +79,16 @@ export class EcosystemService extends BaseService { return this.sendNatsMessage(this.serviceProxy, 'send-ecosystem-invitation', payload); } + /** + * + * @param orgId + * @param ecosystemId + */ + async addOrganizationsInEcosystem(addOrganizationsDto: AddOrganizationsDto, userId: string): Promise<{ results: { statusCode: number, message: string, error?: string, data?: { orgId: string } }[], statusCode: number, message: string }> { + const payload = { ...addOrganizationsDto, userId }; + return this.sendNatsMessage(this.serviceProxy, 'add-organization-in-ecosystem', payload); + } + async getInvitationsByEcosystemId( ecosystemId: string, paginationDto: PaginationDto, diff --git a/apps/api-gateway/src/organization/dtos/get-organizations.dto.ts b/apps/api-gateway/src/organization/dtos/get-organizations.dto.ts new file mode 100644 index 000000000..4a4b35ddd --- /dev/null +++ b/apps/api-gateway/src/organization/dtos/get-organizations.dto.ts @@ -0,0 +1,14 @@ +import { trim } from '@credebl/common/cast.helper'; +import { PaginationDto } from '@credebl/common/dtos/pagination.dto'; +import { ApiProperty } from '@nestjs/swagger'; +import { Transform } from 'class-transformer'; +import { IsEnum, IsOptional } from 'class-validator'; +import { OrgRoles } from 'libs/org-roles/enums'; + +export class GetAllOrganizationsDto extends PaginationDto { + @ApiProperty({ required: false, enum: OrgRoles }) + @Transform(({ value }) => trim(value)) + @IsOptional() + @IsEnum(OrgRoles) + role: string; +} diff --git a/apps/api-gateway/src/organization/organization.controller.ts b/apps/api-gateway/src/organization/organization.controller.ts index 99df72455..73774f5a1 100644 --- a/apps/api-gateway/src/organization/organization.controller.ts +++ b/apps/api-gateway/src/organization/organization.controller.ts @@ -25,6 +25,7 @@ import { ClientCredentialsDto } from './dtos/client-credentials.dto'; import { PaginationDto } from '@credebl/common/dtos/pagination.dto'; import { validate as isValidUUID } from 'uuid'; import { UserAccessGuard } from '../authz/guards/user-access-guard'; +import { GetAllOrganizationsDto } from './dtos/get-organizations.dto'; import { PrimaryDid } from './dtos/set-primary-did.dto'; @UseFilters(CustomExceptionFilter) @@ -215,27 +216,9 @@ export class OrganizationController { @ApiResponse({ status: HttpStatus.OK, description: 'Success', type: ApiResponseDto }) @UseGuards(AuthGuard('jwt'), UserAccessGuard) @ApiBearerAuth() - @ApiQuery({ - name: 'pageNumber', - example: '1', - type: Number, - required: false - }) - @ApiQuery({ - name: 'pageSize', - example: '10', - type: Number, - required: false - }) - @ApiQuery({ - name: 'search', - example: '', - type: String, - required: false - }) - async getOrganizations(@Query() paginationDto: PaginationDto, @Res() res: Response, @User() reqUser: user): Promise { + async getOrganizations(@Query() organizationDto: GetAllOrganizationsDto, @Res() res: Response, @User() reqUser: user): Promise { - const getOrganizations = await this.organizationService.getOrganizations(paginationDto, reqUser.id); + const getOrganizations = await this.organizationService.getOrganizations(organizationDto, reqUser.id); const finalResponse: IResponse = { statusCode: HttpStatus.OK, diff --git a/apps/api-gateway/src/organization/organization.service.ts b/apps/api-gateway/src/organization/organization.service.ts index 14bf3d598..4d19e8d0f 100644 --- a/apps/api-gateway/src/organization/organization.service.ts +++ b/apps/api-gateway/src/organization/organization.service.ts @@ -14,6 +14,7 @@ import { ClientCredentialsDto } from './dtos/client-credentials.dto'; import { IAccessTokenData } from '@credebl/common/interfaces/interface'; import { PaginationDto } from '@credebl/common/dtos/pagination.dto'; import { IClientRoles } from '@credebl/client-registration/interfaces/client.interface'; +import { GetAllOrganizationsDto } from './dtos/get-organizations.dto'; import { PrimaryDid } from './dtos/set-primary-did.dto'; @Injectable() @@ -79,8 +80,8 @@ export class OrganizationService extends BaseService { * @returns Organizations details */ - async getOrganizations(paginationDto: PaginationDto, userId: string): Promise { - const payload = { userId, ...paginationDto }; + async getOrganizations(organizationDto: GetAllOrganizationsDto, userId: string): Promise { + const payload = { userId, ...organizationDto }; const fetchOrgs = await this.sendNatsMessage(this.serviceProxy, 'get-organizations', payload); return fetchOrgs; } diff --git a/apps/ecosystem/interfaces/ecosystem.interfaces.ts b/apps/ecosystem/interfaces/ecosystem.interfaces.ts index 4fa335baf..c35310783 100644 --- a/apps/ecosystem/interfaces/ecosystem.interfaces.ts +++ b/apps/ecosystem/interfaces/ecosystem.interfaces.ts @@ -369,3 +369,31 @@ export interface IEcosystemList { pageSize: number; search: string; } + +export interface IEcosystemLeadOrgs { + organizationIds: string[]; + ecosystemId: string; + orgId: string; + userId: string; +} + +export interface IEcosystemOrgs { + orgId: string, + ecosystemId: string, + ecosystemRoleId: string, + status: string, + deploymentMode: string, + createdBy: string, + lastChangedBy: string +} +export interface IEcosystemOrgsData extends IEcosystemOrgs { + id: string; + createDateTime: Date; + lastChangedDateTime: Date; + deletedAt: Date; +} + +export interface IEcosystemOrgDetails { + count: Prisma.BatchPayload; + ecosystemOrgs: IEcosystemOrgsData[]; +} diff --git a/apps/ecosystem/src/ecosystem.controller.ts b/apps/ecosystem/src/ecosystem.controller.ts index 95513b5d7..349f3f897 100644 --- a/apps/ecosystem/src/ecosystem.controller.ts +++ b/apps/ecosystem/src/ecosystem.controller.ts @@ -8,8 +8,9 @@ import { AcceptRejectEcosystemInvitationDto } from '../dtos/accept-reject-ecosys import { FetchInvitationsPayload } from '../interfaces/invitations.interface'; import { EcosystemMembersPayload } from '../interfaces/ecosystemMembers.interface'; import { GetEndorsementsPayload, ISchemasResponse } from '../interfaces/endorsements.interface'; -import { IEcosystemDashboard, RequestCredDeffEndorsement, RequestSchemaEndorsement, IEcosystem, IEcosystemInvitation, IEcosystemInvitations, IEditEcosystem, IEndorsementTransaction, IEcosystemList } from '../interfaces/ecosystem.interfaces'; +import { IEcosystemDashboard, RequestCredDeffEndorsement, RequestSchemaEndorsement, IEcosystem, IEcosystemInvitation, IEcosystemInvitations, IEditEcosystem, IEndorsementTransaction, IEcosystemList, IEcosystemLeadOrgs } from '../interfaces/ecosystem.interfaces'; import { IEcosystemDetails } from '@credebl/common/interfaces/ecosystem.interface'; +// eslint-disable-next-line camelcase @Controller() export class EcosystemController { @@ -98,6 +99,19 @@ export class EcosystemController { return this.ecosystemService.createInvitation(payload.bulkInvitationDto, payload.userId, payload.userEmail, payload.orgId); } + + /** + * + * @param orgId + * @param ecosystemId + */ + @MessagePattern({ cmd: 'add-organization-in-ecosystem' }) + async addOrganizationsInEcosystem( + ecosystemLeadOrgs: IEcosystemLeadOrgs + ): Promise<{ results: { statusCode: number, message: string, error?: string, data?: { orgId: string } }[], statusCode: number, message: string }> { + return this.ecosystemService.addOrganizationsInEcosystem(ecosystemLeadOrgs); + } + /** * * @param payload diff --git a/apps/ecosystem/src/ecosystem.repository.ts b/apps/ecosystem/src/ecosystem.repository.ts index 45085caa4..ae610e519 100644 --- a/apps/ecosystem/src/ecosystem.repository.ts +++ b/apps/ecosystem/src/ecosystem.repository.ts @@ -1,10 +1,10 @@ import { BadRequestException, Injectable, InternalServerErrorException, Logger } from '@nestjs/common'; import { PrismaService } from '@credebl/prisma-service'; // eslint-disable-next-line camelcase -import { credential_definition, ecosystem, ecosystem_config, ecosystem_invitations, ecosystem_orgs, ecosystem_roles, endorsement_transaction, org_agents, platform_config, schema } from '@prisma/client'; +import { Prisma, credential_definition, ecosystem, ecosystem_config, ecosystem_invitations, ecosystem_orgs, ecosystem_roles, endorsement_transaction, org_agents, organisation, platform_config, schema } from '@prisma/client'; import { DeploymentModeType, EcosystemInvitationStatus, EcosystemOrgStatus, EcosystemRoles, endorsementTransactionStatus, endorsementTransactionType } from '../enums/ecosystem.enum'; import { updateEcosystemOrgsDto } from '../dtos/update-ecosystemOrgs.dto'; -import { CreateEcosystem, IEcosystemInvitation, SaveSchema, SchemaTransactionResponse, saveCredDef } from '../interfaces/ecosystem.interfaces'; +import { CreateEcosystem, IEcosystemInvitation, IEcosystemOrgs, IEcosystemOrgsData, SaveSchema, SchemaTransactionResponse, saveCredDef } from '../interfaces/ecosystem.interfaces'; import { ResponseMessages } from '@credebl/common/response-messages'; import { NotFoundException } from '@nestjs/common'; import { CommonConstants } from '@credebl/common/common.constant'; @@ -87,6 +87,72 @@ export class EcosystemRepository { } } + //eslint-disable-next-line camelcase + async addOrganizationInEcosystem(orgs: IEcosystemOrgs[]): Promise { + try { + + const result = await this.prisma.ecosystem_orgs.createMany({ + data: orgs + }); + + return result; + + } catch (error) { + this.logger.error(`Error in add organization ecosystem: ${error.message}`); + throw error; + } + } + + async getEcosystemOrgs(orgIds: string[], ecosystemId: string): Promise { + try { + const result = await this.prisma.ecosystem_orgs.findMany({ + where: { + orgId: { + in: orgIds + }, + ecosystemId + } + }); + + return result; + + } catch (error) { + this.logger.error(`Error in fetch ecosystem orgs: ${error.message}`); + throw error; + } + } + + async checkOrgExists(orgId: string): Promise { + try { + const isOrgExists = await this.prisma.organisation.findUnique({ + where: { + id: orgId + } + }); + return isOrgExists; + } catch (error) { + this.logger.error(`error: ${JSON.stringify(error)}`); + throw new InternalServerErrorException(error); + } + } + + + // eslint-disable-next-line camelcase + async checkOrgExistsInEcosystem(orgId: string, ecosystemId: string): Promise { + try { + const existingOrgs = await this.prisma.ecosystem_orgs.findFirst({ + where: { + ecosystemId, + orgId + } + }); + return existingOrgs; + } catch (error) { + this.logger.error(`error: ${JSON.stringify(error)}`); + throw new InternalServerErrorException(error); + } + } + /** * Description: Edit ecosystem by Id * @param editEcosystemDto @@ -539,7 +605,12 @@ export class EcosystemRepository { name: true, orgSlug: true, // eslint-disable-next-line camelcase - org_agents: true + org_agents: true, + userOrgRoles: { + select: { + userId: true + } + } } } }, diff --git a/apps/ecosystem/src/ecosystem.service.ts b/apps/ecosystem/src/ecosystem.service.ts index 9aa3dff26..04a19af33 100644 --- a/apps/ecosystem/src/ecosystem.service.ts +++ b/apps/ecosystem/src/ecosystem.service.ts @@ -5,6 +5,7 @@ import { ConflictException, ForbiddenException, HttpException, + HttpStatus, Inject, Injectable, InternalServerErrorException, @@ -23,6 +24,7 @@ import { sendEmail } from '@credebl/common/send-grid-helper-file'; import { AcceptRejectEcosystemInvitationDto } from '../dtos/accept-reject-ecosysteminvitation.dto'; import { EcosystemConfigSettings, Invitation, OrgAgentType } from '@credebl/enum/enum'; import { + DeploymentModeType, EcosystemOrgStatus, EcosystemRoles, endorsementTransactionStatus, @@ -49,7 +51,8 @@ import { IEcosystemInvitations, IEditEcosystem, IEndorsementTransaction, - IEcosystemList + IEcosystemList, + IEcosystemLeadOrgs } from '../interfaces/ecosystem.interfaces'; import { GetAllSchemaList, GetEndorsementsPayload, ISchemasResponse } from '../interfaces/endorsements.interface'; import { CommonConstants } from '@credebl/common/common.constant'; @@ -419,6 +422,114 @@ export class EcosystemService { } } + async addOrganizationsInEcosystem(ecosystemLeadOrgs: IEcosystemLeadOrgs): Promise<{ + results: { statusCode: number; message: string; error?: string; data?: { orgId: string } }[]; + statusCode: number; + message: string; + }> { + try { + const ecosystemRoleDetails = await this.ecosystemRepository.getEcosystemRole(EcosystemRoles.ECOSYSTEM_MEMBER); + + const getEcosystemDetails = await this.ecosystemRepository.getEcosystemLeadDetails(ecosystemLeadOrgs.ecosystemId); + const getEcosystemLeadOrg = getEcosystemDetails?.orgId; + const getEcosystemLeadOrgLedgerDetails = await this.ecosystemRepository.getAgentDetails(getEcosystemLeadOrg); + const getEcosystemLeadOrgLedgerId = getEcosystemLeadOrgLedgerDetails?.ledgerId; + + const { organizationIds } = ecosystemLeadOrgs; + const errorOrgs: { statusCode: number; message: string; error?: string; data?: { orgId: string } }[] = []; + const addedOrgs = []; + let successCount: number = 0; + let errorCount: number = 0; + + for (const orgId of organizationIds) { + const result: { statusCode: number; message: string; error?: string; data?: { orgId: string } } = { + statusCode: 0, + message: '' + }; + + const orgAgentDetails = await this.ecosystemRepository.getAgentDetails(orgId); + const getOrgLedgerId = orgAgentDetails?.ledgerId; + if (orgAgentDetails?.orgDid) { + const existingOrg = await this.ecosystemRepository.checkOrgExistsInEcosystem( + orgId, + ecosystemLeadOrgs.ecosystemId + ); + if (getOrgLedgerId === getEcosystemLeadOrgLedgerId) { + if (!existingOrg) { + addedOrgs.push({ + orgId, + ecosystemId: ecosystemLeadOrgs.ecosystemId, + ecosystemRoleId: ecosystemRoleDetails.id, + status: EcosystemOrgStatus.ACTIVE, + deploymentMode: DeploymentModeType.PROVIDER_HOSTED, + createdBy: ecosystemLeadOrgs.userId, + lastChangedBy: ecosystemLeadOrgs.userId + }); + successCount++; + } else { + result.statusCode = HttpStatus.CONFLICT; + result.message = `${ResponseMessages.ecosystem.error.orgAlreadyExists}`; + result.error = `${ResponseMessages.ecosystem.error.unableToAdd}`; + result.data = { orgId }; + errorCount++; + } + } else { + result.statusCode = HttpStatus.BAD_REQUEST; + result.message = `${ResponseMessages.ecosystem.error.ledgerNotMatch}`; + result.error = `${ResponseMessages.ecosystem.error.unableToAdd}`; + result.data = { orgId }; + errorCount++; + } + } else { + result.statusCode = HttpStatus.BAD_REQUEST; + result.message = `${ResponseMessages.ecosystem.error.agentNotSpunUp}`; + result.error = `${ResponseMessages.ecosystem.error.unableToAdd}`; + result.data = { orgId }; + errorCount++; + } + if (0 !== result.statusCode) { + errorOrgs.push(result); + } + } + let statusCode = HttpStatus.CREATED; + let message = ResponseMessages.ecosystem.success.add; + let getOrgs = []; + + if (0 < addedOrgs?.length) { + const orgs = addedOrgs.map((item) => item.orgId); + await this.ecosystemRepository.addOrganizationInEcosystem(addedOrgs); + + //need to discuss + getOrgs = await this.ecosystemRepository.getEcosystemOrgs(orgs, ecosystemLeadOrgs.ecosystemId); + } + + const success = + 0 < getOrgs?.length + ? getOrgs?.map((item) => ({ + statusCode: HttpStatus.CREATED, + message: `${ResponseMessages.ecosystem.success.add}`, + data: { + orgId: item.orgId + } + })) + : []; + const finalResult = [...errorOrgs, ...success]; + + if (0 === successCount) { + statusCode = HttpStatus.BAD_REQUEST; + message = ResponseMessages.ecosystem.error.unableToAdd; + } else if (0 < errorCount && 0 < successCount) { + statusCode = HttpStatus.PARTIAL_CONTENT; + message = ResponseMessages.ecosystem.error.partiallyAdded; + } + + return { results: finalResult, statusCode, message }; + } catch (error) { + this.logger.error(`In add organizations: ${JSON.stringify(error)}`); + throw new RpcException(error.response ? error.response : error); + } + } + async checkLedgerMatches(orgDetails: OrganizationData, ecosystemId: string): Promise { const orgLedgers = orgDetails.org_agents.map((agent) => agent.ledgers.id); @@ -443,7 +554,10 @@ export class EcosystemService { * @param userId * @returns Ecosystem invitation status */ - async acceptRejectEcosystemInvitations(acceptRejectInvitation: AcceptRejectEcosystemInvitationDto, email: string): Promise { + async acceptRejectEcosystemInvitations( + acceptRejectInvitation: AcceptRejectEcosystemInvitationDto, + email: string + ): Promise { try { const isMultiEcosystemEnabled = await this.ecosystemRepository.getSpecificEcosystemConfig( EcosystemConfigSettings.MULTI_ECOSYSTEM @@ -1088,7 +1202,11 @@ export class EcosystemService { endorserDid: endorsementTransactionPayload.endorserDid }; - const schemaTransactionRequest: SignedTransactionMessage = await this._signTransaction(payload, url, ecosystemLeadDetails.orgId); + const schemaTransactionRequest: SignedTransactionMessage = await this._signTransaction( + payload, + url, + ecosystemLeadDetails.orgId + ); if (!schemaTransactionRequest) { throw new InternalServerErrorException(ResponseMessages.ecosystem.error.signRequestError); @@ -1333,7 +1451,7 @@ export class EcosystemService { async submitTransaction(transactionPayload: TransactionPayload): Promise { try { - const { endorsementId, ecosystemId, ecosystemLeadAgentEndPoint, orgId } = transactionPayload; + const { endorsementId, ecosystemId, ecosystemLeadAgentEndPoint, orgId } = transactionPayload; const endorsementTransactionPayload = await this.ecosystemRepository.getEndorsementTransactionById( endorsementId, endorsementTransactionStatus.SIGNED @@ -1366,20 +1484,17 @@ export class EcosystemService { ecosystemMemberDetails, ecosystemLeadAgentDetails ); - + if (endorsementTransactionPayload.type === endorsementTransactionType.SCHEMA) { - const isSchemaExists = await this.ecosystemRepository.schemaExist( - payload.schema.name, - payload.schema.version - ); - - if (0 !== isSchemaExists.length) { - this.logger.error(ResponseMessages.ecosystem.error.schemaAlreadyExist); - throw new ConflictException( - ResponseMessages.ecosystem.error.schemaAlreadyExist, - { cause: new Error(), description: ResponseMessages.errorMessages.conflict } - ); - } + const isSchemaExists = await this.ecosystemRepository.schemaExist(payload.schema.name, payload.schema.version); + + if (0 !== isSchemaExists.length) { + this.logger.error(ResponseMessages.ecosystem.error.schemaAlreadyExist); + throw new ConflictException(ResponseMessages.ecosystem.error.schemaAlreadyExist, { + cause: new Error(), + description: ResponseMessages.errorMessages.conflict + }); + } } const submitTransactionRequest = await this._submitTransaction(payload, url, orgId); @@ -1430,7 +1545,7 @@ export class EcosystemService { throw new InternalServerErrorException(ResponseMessages.ecosystem.error.updateCredDefId); } return this.handleCredDefSubmission( - endorsementTransactionPayload, + endorsementTransactionPayload, ecosystemMemberDetails, submitTransactionRequest ); diff --git a/apps/organization/interfaces/organization.interface.ts b/apps/organization/interfaces/organization.interface.ts index e4e087384..150e0d7ba 100644 --- a/apps/organization/interfaces/organization.interface.ts +++ b/apps/organization/interfaces/organization.interface.ts @@ -143,6 +143,7 @@ export interface Payload { pageNumber: number; pageSize: number; search: string; + role?: string; } export interface IDidList { diff --git a/apps/organization/repositories/organization.repository.ts b/apps/organization/repositories/organization.repository.ts index 6d2bd4f0c..31f7e3474 100644 --- a/apps/organization/repositories/organization.repository.ts +++ b/apps/organization/repositories/organization.repository.ts @@ -551,14 +551,24 @@ export class OrganizationRepository { queryObject: object, filterOptions: object, pageNumber: number, - pageSize: number + pageSize: number, + role?: string, + userId?: string ): Promise { try { const sortByName = SortValue.DESC; const result = await this.prisma.$transaction([ this.prisma.organisation.findMany({ where: { - ...queryObject + ...queryObject, + userOrgRoles: { + some: { + orgRole: { + name: role + }, + userId + } + } }, select: { id: true, @@ -566,7 +576,19 @@ export class OrganizationRepository { description: true, logoUrl: true, orgSlug: true, + createDateTime: true, + ecosystemOrgs: { + select: { + ecosystemId: true + } + }, userOrgRoles: { + where: { + orgRole: { + name: role + }, + ...filterOptions + }, select: { id: true, orgRole: { @@ -576,27 +598,29 @@ export class OrganizationRepository { description: true } } - }, - where: { - ...filterOptions - // Additional filtering conditions if needed } } }, take: pageSize, skip: (pageNumber - 1) * pageSize, orderBy: { - name: sortByName - + createDateTime: sortByName } }), this.prisma.organisation.count({ where: { - ...queryObject + ...queryObject, + userOrgRoles: { + some: { + orgRole: { + name: role + }, + userId + } + } } }) ]); - const organizations = result[0]; const totalCount = result[1]; const totalPages = Math.ceil(totalCount / pageSize); diff --git a/apps/organization/src/organization.controller.ts b/apps/organization/src/organization.controller.ts index cbed622e3..5e02bea41 100644 --- a/apps/organization/src/organization.controller.ts +++ b/apps/organization/src/organization.controller.ts @@ -79,8 +79,8 @@ export class OrganizationController { async getOrganizations( @Body() payload: { userId: string} & Payload ): Promise { - const { userId, pageNumber, pageSize, search } = payload; - return this.organizationService.getOrganizations(userId, pageNumber, pageSize, search); + const { userId, pageNumber, pageSize, search, role } = payload; + return this.organizationService.getOrganizations(userId, pageNumber, pageSize, search, role); } /** diff --git a/apps/organization/src/organization.service.ts b/apps/organization/src/organization.service.ts index e8b5994be..3bd1caf00 100644 --- a/apps/organization/src/organization.service.ts +++ b/apps/organization/src/organization.service.ts @@ -512,14 +512,15 @@ export class OrganizationService { userId: string, pageNumber: number, pageSize: number, - search: string + search: string, + role?: string ): Promise { try { const query = { userOrgRoles: { some: { userId } }, - OR: [ + OR: [ { name: { contains: search, mode: 'insensitive' } }, { description: { contains: search, mode: 'insensitive' } } ] @@ -529,7 +530,7 @@ export class OrganizationService { userId }; - const getOrgs = await this.organizationRepository.getOrganizations(query, filterOptions, pageNumber, pageSize); + const getOrgs = await this.organizationRepository.getOrganizations(query, filterOptions, pageNumber, pageSize, role, userId); return getOrgs; } catch (error) { this.logger.error(`In fetch getOrganizations : ${JSON.stringify(error)}`); diff --git a/libs/common/src/dtos/pagination.dto.ts b/libs/common/src/dtos/pagination.dto.ts index 0805416b7..f321c0ed3 100644 --- a/libs/common/src/dtos/pagination.dto.ts +++ b/libs/common/src/dtos/pagination.dto.ts @@ -8,18 +8,18 @@ export class PaginationDto { @IsOptional() @Transform(({ value }) => toNumber(value)) @Min(1, { message: 'Page number must be greater than 0' }) - pageNumber = 1; + pageNumber: number = 1; @ApiProperty({ required: false }) @IsOptional() @Type(() => String) - search = ''; + search: string = ''; @ApiProperty({ required: false, default: 10 }) @IsOptional() @Transform(({ value }) => toNumber(value)) @Min(1, { message: 'Page size must be greater than 0' }) @Max(100, { message: 'Page size must be less than 100' }) - pageSize = 10; + pageSize: number = 10; } diff --git a/libs/common/src/interfaces/ecosystem.interface.ts b/libs/common/src/interfaces/ecosystem.interface.ts index 648153c19..de76fa317 100644 --- a/libs/common/src/interfaces/ecosystem.interface.ts +++ b/libs/common/src/interfaces/ecosystem.interface.ts @@ -6,7 +6,7 @@ interface EcosystemRole { lastChangedDateTime: Date; deletedAt: Date; } - + interface Ecosystem { id: string; name: string; diff --git a/libs/common/src/response-messages/index.ts b/libs/common/src/response-messages/index.ts index 0b514ce96..cad52d332 100644 --- a/libs/common/src/response-messages/index.ts +++ b/libs/common/src/response-messages/index.ts @@ -320,6 +320,7 @@ export const ResponseMessages = { success: { create: 'Ecosystem created successfully', update: 'Ecosystem details updated successfully', + add: 'Organization added successfully', delete: 'Ecosystem invitations deleted successfully', fetch: 'Ecosystem fetched successfully', getEcosystemDashboard: 'Ecosystem dashboard details fetched successfully', @@ -340,6 +341,10 @@ export const ResponseMessages = { }, error: { notCreated: 'Error while creating ecosystem', + agentNotSpunUp: 'Agent is not spun up for this organization', + orgAlreadyExists: 'Organization is already exists in ecosystem', + unableToAdd: 'Unable to add organization', + partiallyAdded: 'Organization(s) are partially added', orgNotExist: 'Organization does not exist', orgDidNotExist: 'Organization did does not exist', exists: 'An ecosystem name is already exist',