diff --git a/.env.example b/.env.example index 8fb1460..9525e51 100644 --- a/.env.example +++ b/.env.example @@ -1,3 +1,5 @@ +NODE_ENV= + ACCESS_KEY= AZURE_POSTGRESQL_DATABASE= @@ -52,6 +54,10 @@ SMTP_SECURE= SMTP_USER= +MAILTRAP_API_TOKEN= + +MAILTRAP_INVITATION_TEMPLATE_UUID= + WEBSITES_ENABLE_APP_SERVICE_STORAGE= PORT= diff --git a/libs/common/src/config/email.config.ts b/libs/common/src/config/email.config.ts index 3a5c21e..e18d4e8 100644 --- a/libs/common/src/config/email.config.ts +++ b/libs/common/src/config/email.config.ts @@ -10,5 +10,8 @@ export default registerAs( SMTP_USER: process.env.SMTP_USER, SMTP_SENDER: process.env.SMTP_SENDER, SMTP_PASSWORD: process.env.SMTP_PASSWORD, + MAILTRAP_API_TOKEN: process.env.MAILTRAP_API_TOKEN, + MAILTRAP_INVITATION_TEMPLATE_UUID: + process.env.MAILTRAP_INVITATION_TEMPLATE_UUID, }), ); diff --git a/libs/common/src/constants/mail-trap.ts b/libs/common/src/constants/mail-trap.ts new file mode 100644 index 0000000..6642244 --- /dev/null +++ b/libs/common/src/constants/mail-trap.ts @@ -0,0 +1,3 @@ +export const SEND_EMAIL_API_URL_PROD = 'https://send.api.mailtrap.io/api/send/'; +export const SEND_EMAIL_API_URL_DEV = + 'https://sandbox.api.mailtrap.io/api/send/2634012'; diff --git a/libs/common/src/util/email.service.ts b/libs/common/src/util/email.service.ts index f3a389d..fd84ea6 100644 --- a/libs/common/src/util/email.service.ts +++ b/libs/common/src/util/email.service.ts @@ -1,6 +1,11 @@ -import { Injectable } from '@nestjs/common'; +import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import * as nodemailer from 'nodemailer'; +import axios from 'axios'; +import { + SEND_EMAIL_API_URL_DEV, + SEND_EMAIL_API_URL_PROD, +} from '../constants/mail-trap'; @Injectable() export class EmailService { @@ -35,4 +40,47 @@ export class EmailService { await transporter.sendMail(mailOptions); } + async sendEmailWithInvitationTemplate( + email: string, + emailInvitationData: any, + ): Promise { + const isProduction = process.env.NODE_ENV === 'production'; + const API_TOKEN = this.configService.get( + 'email-config.MAILTRAP_API_TOKEN', + ); + const API_URL = isProduction + ? SEND_EMAIL_API_URL_PROD + : SEND_EMAIL_API_URL_DEV; + const TEMPLATE_UUID = this.configService.get( + 'email-config.MAILTRAP_INVITATION_TEMPLATE_UUID', + ); + + const emailData = { + from: { + email: this.smtpConfig.sender, + }, + to: [ + { + email: email, + }, + ], + template_uuid: TEMPLATE_UUID, + template_variables: emailInvitationData, + }; + + try { + await axios.post(API_URL, emailData, { + headers: { + Authorization: `Bearer ${API_TOKEN}`, + 'Content-Type': 'application/json', + }, + }); + } catch (error) { + throw new HttpException( + error.response?.data?.message || + 'Error sending email using Mailtrap template', + error.response?.status || HttpStatus.INTERNAL_SERVER_ERROR, + ); + } + } } diff --git a/src/invite-user/invite-user.module.ts b/src/invite-user/invite-user.module.ts index e77f875..402ebb1 100644 --- a/src/invite-user/invite-user.module.ts +++ b/src/invite-user/invite-user.module.ts @@ -9,6 +9,7 @@ import { InviteUserRepository, InviteUserSpaceRepository, } from '@app/common/modules/Invite-user/repositiories'; +import { EmailService } from '@app/common/util/email.service'; @Module({ imports: [ConfigModule, InviteUserRepositoryModule], @@ -17,6 +18,7 @@ import { InviteUserService, InviteUserRepository, UserRepository, + EmailService, InviteUserSpaceRepository, ], exports: [InviteUserService], diff --git a/src/invite-user/services/invite-user.service.ts b/src/invite-user/services/invite-user.service.ts index b7b5ad0..aaeabd7 100644 --- a/src/invite-user/services/invite-user.service.ts +++ b/src/invite-user/services/invite-user.service.ts @@ -4,7 +4,7 @@ import { BaseResponseDto } from '@app/common/dto/base.response.dto'; import { UserStatusEnum } from '@app/common/constants/user-status.enum'; import { SuccessResponseDto } from '@app/common/dto/success.response.dto'; import { generateRandomString } from '@app/common/helper/randomString'; -import { IsNull, Not } from 'typeorm'; +import { In, IsNull, Not } from 'typeorm'; import { DataSource } from 'typeorm'; import { UserEntity } from '@app/common/modules/user/entities'; import { RoleType } from '@app/common/constants/role.type.enum'; @@ -14,12 +14,15 @@ import { } from '@app/common/modules/Invite-user/repositiories'; import { CheckEmailDto } from '../dtos/check-email.dto'; import { UserRepository } from '@app/common/modules/user/repositories'; +import { EmailService } from '@app/common/util/email.service'; +import { SpaceEntity } from '@app/common/modules/space'; @Injectable() export class InviteUserService { constructor( private readonly inviteUserRepository: InviteUserRepository, private readonly userRepository: UserRepository, + private readonly emailService: EmailService, private readonly inviteUserSpaceRepository: InviteUserSpaceRepository, private readonly dataSource: DataSource, ) {} @@ -76,7 +79,16 @@ export class InviteUserService { }); const invitedUser = await queryRunner.manager.save(inviteUser); + const spaceRepo = queryRunner.manager.getRepository(SpaceEntity); + const spaces = await spaceRepo.find({ + where: { + uuid: In(spaceUuids), + }, + }); + const spaceNames = spaces.map((space) => space.spaceName); + + const spaceNamesString = spaceNames.join(', '); const spacePromises = spaceUuids.map(async (spaceUuid) => { const inviteUserSpace = this.inviteUserSpaceRepository.create({ inviteUser: { uuid: invitedUser.uuid }, @@ -86,6 +98,12 @@ export class InviteUserService { }); await Promise.all(spacePromises); + await this.emailService.sendEmailWithInvitationTemplate(email, { + name: firstName + ' ' + lastName, + invitationCode, + role: roleType, + spacesList: spaceNamesString, + }); await queryRunner.commitTransaction();