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

fix: ecosystem member list search sorting issue #532

Merged
merged 3 commits into from
Feb 22, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
16 changes: 5 additions & 11 deletions apps/api-gateway/src/authz/guards/ecosystem-roles.guard.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
import { BadRequestException, CanActivate, ExecutionContext, ForbiddenException, Logger } from '@nestjs/common';

import { HttpException } from '@nestjs/common';
import { HttpStatus } from '@nestjs/common';
import { Injectable } from '@nestjs/common';
import { BadRequestException, CanActivate, ExecutionContext, ForbiddenException, Logger, Injectable } from '@nestjs/common';
import { ECOSYSTEM_ROLES_KEY } from '../decorators/roles.decorator';
import { Reflector } from '@nestjs/core';
import { EcosystemService } from '../../ecosystem/ecosystem.service';
Expand Down Expand Up @@ -54,19 +50,17 @@ export class EcosystemRolesGuard implements CanActivate {
const ecosystemOrgData = await this.ecosystemService.fetchEcosystemOrg(ecosystemId, orgId);

if (!ecosystemOrgData) {
throw new HttpException('Organization does not match', HttpStatus.FORBIDDEN);
throw new ForbiddenException('Organization does not match');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add these messages in the common file

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Resolved.

}

const {response} = ecosystemOrgData;

user.ecosystemOrgRole = response['ecosystemRole']['name'];
user.ecosystemOrgRole = ecosystemOrgData['ecosystemRole']['name'];

if (!user.ecosystemOrgRole) {
throw new HttpException('Ecosystem role not match', HttpStatus.FORBIDDEN);
throw new ForbiddenException('Ecosystem role not match');
}

} else {
throw new HttpException('organization & ecosystem is required', HttpStatus.BAD_REQUEST);
throw new BadRequestException('organization & ecosystem is required');
}

// Sending user friendly message if a user attempts to access an API that is inaccessible to their role
Expand Down
29 changes: 7 additions & 22 deletions apps/api-gateway/src/ecosystem/dtos/get-members.dto.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,20 @@
import { Transform, Type } from 'class-transformer';
import { Transform } from 'class-transformer';
import { trim } from '@credebl/common/cast.helper';

import { ApiProperty } from '@nestjs/swagger';
import { IsEnum, IsOptional } from 'class-validator';
import { SortFields } from 'apps/connection/src/enum/connection.enum';
import { SortValue } from '@credebl/enum/enum';

export class GetAllEcosystemMembersDto {

@ApiProperty({ required: false, example: '1' })
@IsOptional()
pageNumber: number;

@ApiProperty({ required: false, example: '10' })
@IsOptional()
pageSize: number;

@ApiProperty({ required: false })
@IsOptional()
@Transform(({ value }) => trim(value))
@Type(() => String)
search: string = '';
import { SortMembers, SortValue } from '@credebl/enum/enum';
import { PaginationDto } from '@credebl/common/dtos/pagination.dto';

export class GetAllEcosystemMembersDto extends PaginationDto {
@ApiProperty({
enum: [SortMembers.CREATED_DATE_TIME, SortMembers.ID, SortMembers.ORGANIZATION, SortMembers.STATUS],
required: false
})
@Transform(({ value }) => trim(value))
@IsOptional()
@IsEnum(SortFields)
sortField: string = SortFields.CREATED_DATE_TIME;
@IsEnum(SortMembers)
sortField: string = SortMembers.CREATED_DATE_TIME;

@ApiProperty({
enum: [SortValue.DESC, SortValue.ASC],
Expand All @@ -38,5 +24,4 @@ export class GetAllEcosystemMembersDto {
@IsOptional()
@IsEnum(SortValue)
sortBy: string = SortValue.DESC;

}
13 changes: 7 additions & 6 deletions apps/api-gateway/src/ecosystem/ecosystem.controller.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ApiBearerAuth, ApiExcludeEndpoint, ApiForbiddenResponse, ApiOperation, ApiQuery, ApiResponse, ApiTags, ApiUnauthorizedResponse } from '@nestjs/swagger';
import { EcosystemService } from './ecosystem.service';
import { Controller, UseFilters, Put, Post, Get, Body, Param, UseGuards, Query, BadRequestException, Delete, HttpStatus, Res } from '@nestjs/common';
import { Controller, UseFilters, Put, Post, Get, Body, Param, UseGuards, Query, BadRequestException, Delete, HttpStatus, Res, ParseUUIDPipe } from '@nestjs/common';
import { RequestCredDefDto, RequestSchemaDto } from './dtos/request-schema.dto';
import IResponse from '@credebl/common/interfaces/response.interface';
import { Response } from 'express';
Expand Down Expand Up @@ -256,7 +256,7 @@ export class EcosystemController {
@EcosystemsRoles(EcosystemRoles.ECOSYSTEM_OWNER, EcosystemRoles.ECOSYSTEM_LEAD, EcosystemRoles.ECOSYSTEM_MEMBER)
@ApiBearerAuth()
@UseGuards(AuthGuard('jwt'), EcosystemRolesGuard, OrgRolesGuard)
@ApiResponse({ status: 200, description: 'Success', type: ApiResponseDto })
@ApiResponse({ status: HttpStatus.OK, description: 'Success', type: ApiResponseDto })
@ApiOperation({ summary: 'Get ecosystem members list', description: 'Get ecosystem members list.' })
@ApiQuery({
name: 'pageNumber',
Expand All @@ -274,18 +274,19 @@ export class EcosystemController {
required: false
})
async getEcosystemMembers(
@Param('ecosystemId') ecosystemId: string,
@Param('ecosystemId', new ParseUUIDPipe({exceptionFactory: (): Error => { throw new BadRequestException(`Invalid format for ecosystemId`); }})) ecosystemId: string,
@Param('orgId') orgId: string,
@Query() getEcosystemMembers: GetAllEcosystemMembersDto,
@Res() res: Response): Promise<Response> {

const members = await this.ecosystemService.getEcosystemMembers(ecosystemId, getEcosystemMembers);
const finalResponse: IResponse = {
statusCode: 200,
statusCode: HttpStatus.OK,
message: ResponseMessages.ecosystem.success.fetchMembers,
data: members?.response
data: members
};

return res.status(200).json(finalResponse);
return res.status(HttpStatus.OK).json(finalResponse);
}

@Post('/:ecosystemId/:orgId/transaction/schema')
Expand Down
11 changes: 5 additions & 6 deletions apps/api-gateway/src/ecosystem/ecosystem.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,10 @@ export class EcosystemService extends BaseService {
*/
async getEcosystemMembers(
ecosystemId: string,
getEcosystemMembers: GetAllEcosystemMembersDto
payload: GetAllEcosystemMembersDto
): Promise<{ response: object }> {
const { pageNumber, pageSize, search, sortBy } = getEcosystemMembers;
const payload = { ecosystemId, pageNumber, pageSize, search, sortBy };
return this.sendNats(this.serviceProxy, 'fetch-ecosystem-members', payload);
payload['ecosystemId'] = ecosystemId;
return this.sendNatsMessage(this.serviceProxy, 'fetch-ecosystem-members', payload);
}

/**
Expand Down Expand Up @@ -126,9 +125,9 @@ export class EcosystemService extends BaseService {
return this.sendNats(this.serviceProxy, 'accept-reject-ecosystem-invitations', payload);
}

async fetchEcosystemOrg(ecosystemId: string, orgId: string): Promise<{ response: object }> {
async fetchEcosystemOrg(ecosystemId: string, orgId: string): Promise<object> {
const payload = { ecosystemId, orgId };
return this.sendNats(this.serviceProxy, 'fetch-ecosystem-org-data', payload);
return this.sendNatsMessage(this.serviceProxy, 'fetch-ecosystem-org-data', payload);
}

async getEndorsementTranasactions(
Expand Down
1 change: 1 addition & 0 deletions apps/ecosystem/interfaces/ecosystemMembers.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export interface EcosystemMembersPayload {
pageSize: number;
search: string;
sortBy: string;
sortField: string;
}
2 changes: 1 addition & 1 deletion apps/ecosystem/src/ecosystem.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export class EcosystemController {
*/
@MessagePattern({ cmd: 'fetch-ecosystem-members' })
async getEcosystemMembers(@Body() payload: EcosystemMembersPayload): Promise<object> {
return this.ecosystemService.getEcoystemMembers(payload);
return this.ecosystemService.getEcosystemMembers(payload);
}

/**
Expand Down
134 changes: 70 additions & 64 deletions apps/ecosystem/src/ecosystem.repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { ResponseMessages } from '@credebl/common/response-messages';
import { NotFoundException } from '@nestjs/common';
import { CommonConstants } from '@credebl/common/common.constant';
import { GetAllSchemaList } from '../interfaces/endorsements.interface';
import { SortValue } from '@credebl/enum/enum';
// eslint-disable-next-line camelcase

@Injectable()
Expand Down Expand Up @@ -160,7 +161,7 @@ export class EcosystemRepository {
}
})
]);

return {
ecosystemDetails,
totalCount: ecosystemCount
Expand All @@ -170,7 +171,7 @@ export class EcosystemRepository {
throw error;
}
}


/**
*
Expand Down Expand Up @@ -486,62 +487,67 @@ export class EcosystemRepository {
* @returns users list
*/

async findEcosystemMembers(
ecosystemId: string,
pageNumber: number,
pageSize: number,
search: string,
sortBy: string
): Promise<object> {
try {
const result = await this.prisma.$transaction([
this.prisma.ecosystem_orgs.findMany({
where: {
ecosystemId,
OR: [
{
organisation: {
name: { contains: search, mode: 'insensitive' },
// eslint-disable-next-line camelcase
org_agents: {
some: {
orgDid: { contains: search, mode: 'insensitive' }
async findEcosystemMembers(
ecosystemId: string,
pageNumber: number,
pageSize: number,
search: string,
sortBy: string,
sortField: string
): Promise<object> {
try {
const result = await this.prisma.$transaction([
this.prisma.ecosystem_orgs.findMany({
where: {
ecosystemId,
OR: [
{
organisation: {
name: { contains: search, mode: 'insensitive' }
}
},
{
organisation: {
// eslint-disable-next-line camelcase
org_agents: {
some: {
orgDid: { contains: search, mode: 'insensitive' }
}
}
}
}
]
},
include: {
ecosystem: true,
ecosystemRole: true,
organisation: {
select: {
name: true,
orgSlug: true,
// eslint-disable-next-line camelcase
org_agents: true
}
}
]
},
include: {
ecosystem: true,
ecosystemRole: true,
organisation: {
select: {
name: true,
orgSlug: true,
// eslint-disable-next-line camelcase
org_agents: true
}
},
take: Number(pageSize),
skip: (pageNumber - 1) * pageSize,
orderBy: {
[sortField]: SortValue.ASC === sortBy ? 'asc' : 'desc'
}
},
take: Number(pageSize),
skip: (pageNumber - 1) * pageSize,
orderBy: {
createDateTime: 'asc' === sortBy ? 'asc' : 'desc'
}
}),
this.prisma.ecosystem_orgs.count({
where: {
ecosystemId
}
})
]);
return result;
} catch (error) {
this.logger.error(`error: ${JSON.stringify(error)}`);
throw error;
}),
this.prisma.ecosystem_orgs.count({
where: {
ecosystemId
}
})
]);
return result;
} catch (error) {
this.logger.error(`error: ${JSON.stringify(error)}`);
throw error;
}
}
}

async getEcosystemInvitationsPagination(queryObject: object, pageNumber: number, pageSize: number): Promise<IEcosystemInvitation> {
try {
Expand Down Expand Up @@ -590,18 +596,18 @@ async findEcosystemMembers(
async fetchEcosystemOrg(
payload: object
): Promise<object> {

return this.prisma.ecosystem_orgs.findFirst({
where: {
...payload
},
select: {
ecosystem: true,
ecosystemRole: true,
organisation: true
}
});

where: {
...payload
},
select: {
ecosystem: true,
ecosystemRole: true,
organisation: true
}
});
}


Expand Down Expand Up @@ -833,7 +839,7 @@ async findEcosystemMembers(
schemaTransactionResponse: SchemaTransactionResponse,
requestBody: object,
type: endorsementTransactionType
// eslint-disable-next-line camelcase
// eslint-disable-next-line camelcase
): Promise<endorsement_transaction> {
try {
const { endorserDid, authorDid, requestPayload, status, ecosystemOrgId, userId } = schemaTransactionResponse;
Expand Down
7 changes: 4 additions & 3 deletions apps/ecosystem/src/ecosystem.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1109,15 +1109,16 @@ export class EcosystemService {
* @returns Ecosystem members list
*/

async getEcoystemMembers(payload: EcosystemMembersPayload): Promise<object> {
async getEcosystemMembers(payload: EcosystemMembersPayload): Promise<object> {
try {
const { ecosystemId, pageNumber, pageSize, search, sortBy } = payload;
const { ecosystemId, pageNumber, pageSize, search, sortBy, sortField } = payload;
const getEcosystemMember = await this.ecosystemRepository.findEcosystemMembers(
ecosystemId,
pageNumber,
pageSize,
search,
sortBy
sortBy,
sortField
);

const ecosystemMemberResponse = {
Expand Down
7 changes: 7 additions & 0 deletions libs/enum/src/enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ export enum AutoAccept {
Never = "never"
}

export enum SortMembers {
CREATED_DATE_TIME = 'createDateTime',
STATUS = 'status',
ID = 'id',
ORGANIZATION = 'organization'
}

const transitionMap: { [key in Invitation]: Invitation[] } = {
[Invitation.PENDING]: [Invitation.ACCEPTED, Invitation.REJECTED],
[Invitation.ACCEPTED]: [],
Expand Down
4 changes: 4 additions & 0 deletions libs/http-exception.filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ export class HttpExceptionFilter implements ExceptionFilter {
httpStatus = HttpStatus.BAD_REQUEST;
message = exception?.response?.message || exception?.message;
break;
case 'P2023': // Inconsistent column data: {message}
httpStatus = HttpStatus.BAD_REQUEST;
message = exception?.meta?.message || exception?.message;
break;
case 'P2018': // The required connected records were not found. {details}
case 'P2025': // An operation failed because it depends on one or more records that were required but not found. {cause}
case 'P2015': // A related record could not be found. {details}
Expand Down