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: ecosystem send invitation #117

Merged
merged 1 commit into from
Oct 5, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
28 changes: 28 additions & 0 deletions apps/api-gateway/src/ecosystem/dtos/send-invitation.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { ApiExtraModels, ApiProperty } from '@nestjs/swagger';
import { IsArray, IsEmail, IsNotEmpty, IsString, ValidateNested } from 'class-validator';
import { Transform, Type } from 'class-transformer';

import { trim } from '@credebl/common/cast.helper';

@ApiExtraModels()
export class EcosystemInvitationDto {

@ApiProperty({ example: '[email protected]' })
@IsEmail()
@Transform(({ value }) => trim(value))
@IsNotEmpty({ message: 'Please provide valid email' })
@IsString({ message: 'email should be string' })
email: string;

}

@ApiExtraModels()
export class BulkEcosystemInvitationDto {

@ApiProperty({ type: [EcosystemInvitationDto] })
@IsArray()
@ValidateNested({ each: true })
@Type(() => EcosystemInvitationDto)
invitations: EcosystemInvitationDto[];
ecosystemId: string;
}
35 changes: 35 additions & 0 deletions apps/api-gateway/src/ecosystem/ecosystem.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import { ResponseMessages } from '@credebl/common/response-messages';
import { CustomExceptionFilter } from 'apps/api-gateway/common/exception-handler';
import { EditEcosystemDto } from './dtos/edit-ecosystem-dto';
import { AuthGuard } from '@nestjs/passport';
import { User } from '../authz/decorators/user.decorator';
import { BulkEcosystemInvitationDto } from './dtos/send-invitation.dto';


@UseFilters(CustomExceptionFilter)
Expand Down Expand Up @@ -57,6 +59,38 @@ export class EcosystemController {
return res.status(HttpStatus.CREATED).json(finalResponse);
}


/**
*
* @param bulkInvitationDto
* @param ecosystemId
* @param user
* @param res
* @returns Ecosystem invitation send details
*/
@Post('/:ecosystemId/invitations')
@ApiOperation({
summary: 'Send ecosystem invitation',
description: 'Send ecosystem invitation'
})
@ApiResponse({ status: 201, description: 'Success', type: ApiResponseDto })
@UseGuards(AuthGuard('jwt'))
@ApiBearerAuth()
async createInvitation(@Body() bulkInvitationDto: BulkEcosystemInvitationDto, @Param('ecosystemId') ecosystemId: string, @User() user: user, @Res() res: Response): Promise<Response> {

bulkInvitationDto.ecosystemId = ecosystemId;
await this.ecosystemService.createInvitation(bulkInvitationDto, String(user.id));

const finalResponse: IResponseType = {
statusCode: HttpStatus.CREATED,
message: ResponseMessages.ecosystem.success.createInvitation
};

return res.status(HttpStatus.CREATED).json(finalResponse);

}


@Put('/:ecosystemId/')
@ApiOperation({ summary: 'Edit ecosystem', description: 'Edit existing ecosystem' })
@ApiResponse({ status: 201, description: 'Success', type: ApiResponseDto })
Expand All @@ -70,4 +104,5 @@ export class EcosystemController {
};
return res.status(HttpStatus.CREATED).json(finalResponse);
}

}
14 changes: 14 additions & 0 deletions apps/api-gateway/src/ecosystem/ecosystem.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Inject } from '@nestjs/common';
import { Injectable } from '@nestjs/common';
import { ClientProxy } from '@nestjs/microservices';
import { BaseService } from 'libs/service/base.service';
import { BulkEcosystemInvitationDto } from './dtos/send-invitation.dto';


@Injectable()
Expand Down Expand Up @@ -38,5 +39,18 @@ export class EcosystemService extends BaseService {
async getAllEcosystem(): Promise<{ response: object }> {
return this.sendNats(this.serviceProxy, 'get-all-ecosystem', '');
}


/**
*
* @param bulkInvitationDto
* @param userId
* @returns
*/
async createInvitation(bulkInvitationDto: BulkEcosystemInvitationDto, userId: string): Promise<object> {
const payload = { bulkInvitationDto, userId };
return this.sendNats(this.serviceProxy, 'send-ecosystem-invitation', payload);
}


}
12 changes: 12 additions & 0 deletions apps/ecosystem/dtos/send-invitation.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { ApiExtraModels } from '@nestjs/swagger';

@ApiExtraModels()
export class SendInvitationDto {
email: string;
}

@ApiExtraModels()
export class BulkSendInvitationDto {
invitations: SendInvitationDto[];
ecosystemId: string;
}
6 changes: 6 additions & 0 deletions apps/ecosystem/enums/ecosystem.enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,10 @@ export enum EcosystemRoles {

export enum EcosystemOrgStatus {
ACTIVE = 'ACTIVE'
}

export enum EcosystemInvitationStatus {
ACCEPTED = 'accepted',
REJECTED = 'rejected',
PENDING = 'pending'
}
14 changes: 14 additions & 0 deletions apps/ecosystem/src/ecosystem.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Controller, Logger } from '@nestjs/common';
import { MessagePattern } from '@nestjs/microservices';
import { EcosystemService } from './ecosystem.service';
import { Body } from '@nestjs/common';
import { BulkSendInvitationDto } from '../dtos/send-invitation.dto';

@Controller()
export class EcosystemController {
Expand Down Expand Up @@ -39,5 +40,18 @@ export class EcosystemController {
async getAllEcosystems(): Promise<object> {
return this.ecosystemService.getAllEcosystem();
}


/**
*
* @param payload
* @returns Sent ecosystem invitations status
*/
@MessagePattern({ cmd: 'send-ecosystem-invitation' })
async createInvitation(
@Body() payload: { bulkInvitationDto: BulkSendInvitationDto; userId: string }
): Promise<string> {
return this.ecosystemService.createInvitation(payload.bulkInvitationDto, payload.userId);
}

}
79 changes: 76 additions & 3 deletions apps/ecosystem/src/ecosystem.repository.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Injectable, Logger } from '@nestjs/common';
import { Injectable, InternalServerErrorException, Logger } from '@nestjs/common';
import { PrismaService } from '@credebl/prisma-service';
import { ecosystem } from '@prisma/client';
import {EcosystemOrgStatus, EcosystemRoles} from '../enums/ecosystem.enum';
// eslint-disable-next-line camelcase
import { ecosystem, ecosystem_invitations } from '@prisma/client';
import {EcosystemInvitationStatus, EcosystemOrgStatus, EcosystemRoles} from '../enums/ecosystem.enum';
// eslint-disable-next-line camelcase
@Injectable()
export class EcosystemRepository {
Expand Down Expand Up @@ -112,5 +113,77 @@ export class EcosystemRepository {
}
}

/**
*
* @param ecosystemId
* @returns Get specific ecosystem details
*/
async getEcosystemDetails(ecosystemId: string): Promise<ecosystem> {
try {
return this.prisma.ecosystem.findFirst({
where: {
id: ecosystemId
}
});
} catch (error) {
this.logger.error(`error: ${JSON.stringify(error)}`);
throw new InternalServerErrorException(error);
}
}

/**
*
* @param queryObject
* @returns Get all ecosystem invitations
*/
async getEcosystemInvitations(
queryObject: object
// eslint-disable-next-line camelcase
): Promise<ecosystem_invitations[]> {
try {
return this.prisma.ecosystem_invitations.findMany({
where: {
...queryObject
},
include: {
ecosystem: true
}
});
} catch (error) {
this.logger.error(`error: ${JSON.stringify(error)}`);
throw new InternalServerErrorException(error);
}
}


/**
*
* @param email
* @param ecosystemId
* @param userId
* @returns
*/
async createSendInvitation(
email: string,
ecosystemId: string,
userId: string
// eslint-disable-next-line camelcase
): Promise<ecosystem_invitations> {
try {
return this.prisma.ecosystem_invitations.create({
data: {
email,
userId,
ecosystem: {connect: {id: ecosystemId}},
status: EcosystemInvitationStatus.PENDING,
orgId: ''
}
});
} catch (error) {
this.logger.error(`error: ${JSON.stringify(error)}`);
throw new InternalServerErrorException(error);
}
}


}
105 changes: 103 additions & 2 deletions apps/ecosystem/src/ecosystem.service.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
// eslint-disable-next-line camelcase
import { Injectable, NotFoundException } from '@nestjs/common';
import { Injectable, InternalServerErrorException, Logger, NotFoundException } from '@nestjs/common';
import { EcosystemRepository } from './ecosystem.repository';
import { ResponseMessages } from '@credebl/common/response-messages';
import { BulkSendInvitationDto } from '../dtos/send-invitation.dto';
import { RpcException } from '@nestjs/microservices';
import { PrismaService } from '@credebl/prisma-service';
import { EcosystemInviteTemplate } from '../templates/EcosystemInviteTemplate';
import { EmailDto } from '@credebl/common/dtos/email.dto';
import { sendEmail } from '@credebl/common/send-grid-helper-file';

@Injectable()
export class EcosystemService {
constructor(
private readonly ecosystemRepository: EcosystemRepository
private readonly ecosystemRepository: EcosystemRepository,
private readonly logger: Logger,
private readonly prisma: PrismaService

) { }

/**
Expand Down Expand Up @@ -54,4 +63,96 @@ export class EcosystemService {
}
return getAllEcosystemDetails;
}


/**
*
* @param bulkInvitationDto
* @param userId
* @returns
*/
async createInvitation(bulkInvitationDto: BulkSendInvitationDto, userId: string): Promise<string> {
const { invitations, ecosystemId } = bulkInvitationDto;

try {
const ecosystemDetails = await this.ecosystemRepository.getEcosystemDetails(ecosystemId);

for (const invitation of invitations) {
const { email } = invitation;

const isInvitationExist = await this.checkInvitationExist(email, ecosystemId);

if (!isInvitationExist) {
await this.ecosystemRepository.createSendInvitation(email, ecosystemId, userId);

try {
await this.sendInviteEmailTemplate(email, ecosystemDetails.name);
} catch (error) {
throw new InternalServerErrorException(ResponseMessages.user.error.emailSend);
}
}
}
return ResponseMessages.ecosystem.success.createInvitation;
} catch (error) {
this.logger.error(`In send Invitation : ${JSON.stringify(error)}`);
throw new RpcException(error.response ? error.response : error);
}
}


/**
*
* @param email
* @param ecosystemId
* @returns Returns boolean status for invitation
*/
async checkInvitationExist(
email: string,
ecosystemId: string
): Promise<boolean> {
try {

const query = {
email,
ecosystemId
};

const invitations = await this.ecosystemRepository.getEcosystemInvitations(query);

if (0 < invitations.length) {
return true;
}
return false;
} catch (error) {
throw new RpcException(error.response ? error.response : error);
}
}

/**
*
* @param email
* @param ecosystemName
* @returns Send invitation mail
*/
async sendInviteEmailTemplate(
email: string,
ecosystemName: string
): Promise<boolean> {
const platformConfigData = await this.prisma.platform_config.findMany();

const urlEmailTemplate = new EcosystemInviteTemplate();
const emailData = new EmailDto();
emailData.emailFrom = platformConfigData[0].emailFrom;
emailData.emailTo = email;
emailData.emailSubject = `${process.env.PLATFORM_NAME} Platform: Invitation`;

emailData.emailHtml = await urlEmailTemplate.sendInviteEmailTemplate(email, ecosystemName);

//Email is sent to user for the verification through emailData
const isEmailSent = await sendEmail(emailData);

return isEmailSent;
}


}
Loading