Skip to content
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
2 changes: 1 addition & 1 deletion apps/api-gateway/src/authz/authz.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ export class AuthzController {
})
@ApiResponse({ status: HttpStatus.OK, description: 'Success', type: ApiResponseDto })
async forgotPassword(@Body() forgotPasswordDto: ForgotPasswordDto, @Res() res: Response): Promise<Response> {

this.logger.log(`forgotPasswordDto::: ${JSON.stringify(forgotPasswordDto)}`);
const userData = await this.authzService.forgotPassword(forgotPasswordDto);
const finalResponse: IResponseType = {
statusCode: HttpStatus.OK,
Expand Down
28 changes: 26 additions & 2 deletions apps/api-gateway/src/authz/dtos/forgot-password.dto.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { IsEmail, IsNotEmpty, IsString } from 'class-validator';
import { IsEmail, IsNotEmpty, IsOptional, IsString, IsUrl } from 'class-validator';

import { ApiProperty } from '@nestjs/swagger';
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { Transform } from 'class-transformer';
import { trim } from '@credebl/common/cast.helper';

Expand All @@ -11,4 +11,28 @@ export class ForgotPasswordDto {
@IsString({ message: 'Email should be a string' })
@Transform(({ value }) => trim(value))
email: string;

@ApiPropertyOptional({ example: 'https://example.com/logo.png' })
@Transform(({ value }) => trim(value))
@IsOptional()
@IsUrl({
// eslint-disable-next-line camelcase
require_protocol: true,
// eslint-disable-next-line camelcase
require_tld: true
},
{ message: 'brandLogoUrl should be a valid URL' })
brandLogoUrl?: string;

@ApiPropertyOptional({ example: 'MyPlatform' })
@Transform(({ value }) => trim(value))
@IsOptional()
@IsString({ message: 'platformName should be string' })
platformName?: string;

@ApiPropertyOptional({ example: 'https://0.0.0.0:5000' })
@Transform(({ value }) => trim(value))
@IsOptional()
@IsString({ message: 'endpoint should be string' })
endpoint?: string;
}
6 changes: 6 additions & 0 deletions apps/user/interfaces/user.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,12 @@ export interface IUserResetPassword{
token?: string;
password?: string;
}
export interface IUserForgotPassword{
email: string;
brandLogoUrl?: string,
platformName?: string,
endpoint?: string
}
export interface IIssueCertificate {
courseCode: string;
courseName: string;
Expand Down
4 changes: 2 additions & 2 deletions apps/user/src/user.controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IOrgUsers, Payload, ICheckUserDetails, PlatformSettings, IShareUserCertificate, UpdateUserProfile, IUsersProfile, IUserInformation, IUserSignIn, IUserCredentials, IUserResetPassword, IUserDeletedActivity, UserKeycloakId} from '../interfaces/user.interface';
import { IOrgUsers, Payload, ICheckUserDetails, PlatformSettings, IShareUserCertificate, UpdateUserProfile, IUsersProfile, IUserInformation, IUserSignIn, IUserCredentials, IUserResetPassword, IUserDeletedActivity, UserKeycloakId, IUserForgotPassword} from '../interfaces/user.interface';
import { AcceptRejectInvitationDto } from '../dtos/accept-reject-invitation.dto';
import { Controller } from '@nestjs/common';
import { MessagePattern } from '@nestjs/microservices';
Expand Down Expand Up @@ -61,7 +61,7 @@ export class UserController {
}

@MessagePattern({ cmd: 'user-forgot-password' })
async forgotPassword(payload: IUserResetPassword): Promise<IResetPasswordResponse> {
async forgotPassword(payload: IUserForgotPassword): Promise<IResetPasswordResponse> {
return this.userService.forgotPassword(payload);
}

Expand Down
19 changes: 11 additions & 8 deletions apps/user/src/user.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ import {
IShareDegreeCertificateRes,
IUserDeletedActivity,
UserKeycloakId,
IEcosystemConfig
IEcosystemConfig,
IUserForgotPassword
} from '../interfaces/user.interface';
import { AcceptRejectInvitationDto } from '../dtos/accept-reject-invitation.dto';
import { UserActivityService } from '@credebl/user-activity';
Expand Down Expand Up @@ -436,9 +437,9 @@ export class UserService {
* @param forgotPasswordDto
* @returns
*/
async forgotPassword(forgotPasswordDto: IUserResetPassword): Promise<IResetPasswordResponse> {
const { email } = forgotPasswordDto;

async forgotPassword(forgotPasswordDto: IUserForgotPassword): Promise<IResetPasswordResponse> {
const { email, brandLogoUrl, platformName, endpoint } = forgotPasswordDto;
this.logger.log(`forgotPasswordDto::::::: ${forgotPasswordDto}`);
try {
this.validateEmail(email.toLowerCase());
const userData = await this.userRepository.checkUserExist(email.toLowerCase());
Expand All @@ -461,7 +462,7 @@ export class UserService {
}

try {
await this.sendEmailForResetPassword(email, tokenCreated.token);
await this.sendEmailForResetPassword(email, brandLogoUrl, platformName, endpoint, tokenCreated.token);
} catch (error) {
throw new InternalServerErrorException(ResponseMessages.user.error.emailSend);
}
Expand All @@ -483,17 +484,19 @@ export class UserService {
* @param verificationCode
* @returns
*/
async sendEmailForResetPassword(email: string, verificationCode: string): Promise<boolean> {
async sendEmailForResetPassword(email: string, brandLogoUrl: string, platformName: string, endpoint: string, verificationCode: string): Promise<boolean> {
try {
const platformConfigData = await this.prisma.platform_config.findMany();

const urlEmailTemplate = new URLUserResetPasswordTemplate();
const emailData = new EmailDto();
emailData.emailFrom = platformConfigData[0].emailFrom;
emailData.emailTo = email;
emailData.emailSubject = `[${process.env.PLATFORM_NAME}] Important: Password Reset Request`;

emailData.emailHtml = await urlEmailTemplate.getUserResetPasswordTemplate(email, verificationCode);
const platform = platformName || process.env.PLATFORM_NAME;
emailData.emailSubject = `[${platform}] Important: Password Reset Request`;

emailData.emailHtml = await urlEmailTemplate.getUserResetPasswordTemplate(email, platform, brandLogoUrl, endpoint, verificationCode);
const isEmailSent = await sendEmail(emailData);
if (isEmailSent) {
return isEmailSent;
Expand Down
13 changes: 8 additions & 5 deletions apps/user/templates/reset-password-template.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import * as url from 'url';
export class URLUserResetPasswordTemplate {
public getUserResetPasswordTemplate(email: string, verificationCode: string): string {
const endpoint = `${process.env.FRONT_END_URL}`;
public getUserResetPasswordTemplate(email: string, platform: string, brandLogoUrl: string, uiEndpoint: string, verificationCode: string): string {
const endpoint = uiEndpoint || process.env.FRONT_END_URL;

const apiUrl = url.parse(
`${endpoint}/reset-password?verificationCode=${verificationCode}&email=${encodeURIComponent(email)}`
);

const logoUrl = brandLogoUrl || process.env.BRAND_LOGO;
const poweredBy = platform || process.env.POWERED_BY;

const validUrl = apiUrl.href.replace('/:', ':');

try {
Expand All @@ -23,7 +26,7 @@ export class URLUserResetPasswordTemplate {

<div style="margin: auto; max-width: 450px; padding: 20px 30px; background-color: #FFFFFF; display:block;">
<div style="display: block; text-align:center;">
<img src="${process.env.BRAND_LOGO}" alt="${process.env.PLATFORM_NAME} logo" style="max-width:100px; background: white; padding: 5px;border-radius: 5px;" width="100%" height="fit-content" class="CToWUd" data-bit="iit">
<img src="${logoUrl}" alt="${platform} logo" style="max-width:100px; background: white; padding: 5px;border-radius: 5px;" width="100%" height="fit-content" class="CToWUd" data-bit="iit">
</div>

<div style="font-family: Montserrat; font-style: normal; font-weight: 500;
Expand All @@ -32,7 +35,7 @@ export class URLUserResetPasswordTemplate {
Hello ${email},
</p>
<p>
A password reset request has been received for your ${process.env.PLATFORM_NAME} platform account. To reset your password, please click on the following link:
A password reset request has been received for your ${platform} platform account. To reset your password, please click on the following link:
</p>

<div style="text-align: center; padding-bottom: 20px;">
Expand All @@ -50,7 +53,7 @@ export class URLUserResetPasswordTemplate {

</div>
<p style="margin-top: 6px;">
© ${process.env.POWERED_BY}
© ${poweredBy}
</p>
</footer>
</div>
Expand Down