mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2025-11-26 06:32:03 +10:00
🚀 release: v3.0.0
This commit is contained in:
10
apps/server/src/mail/mail.controller.ts
Normal file
10
apps/server/src/mail/mail.controller.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { Controller, Get, Render } from '@nestjs/common';
|
||||
|
||||
@Controller('mail')
|
||||
export class MailController {
|
||||
@Get('forgot-password')
|
||||
@Render('forgot-password')
|
||||
forgotPassword() {
|
||||
return { name: 'Amruth', url: 'https://amruthpillai.com/' };
|
||||
}
|
||||
}
|
||||
20
apps/server/src/mail/mail.module.ts
Normal file
20
apps/server/src/mail/mail.module.ts
Normal file
@ -0,0 +1,20 @@
|
||||
import { DynamicModule, Global, Module } from '@nestjs/common';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
|
||||
import { MailController } from './mail.controller';
|
||||
import { MailService } from './mail.service';
|
||||
|
||||
@Global()
|
||||
@Module({
|
||||
imports: [ConfigModule],
|
||||
})
|
||||
export class MailModule {
|
||||
static register(): DynamicModule {
|
||||
return {
|
||||
module: MailModule,
|
||||
controllers: [MailController],
|
||||
providers: [MailService],
|
||||
exports: [MailService],
|
||||
};
|
||||
}
|
||||
}
|
||||
42
apps/server/src/mail/mail.service.ts
Normal file
42
apps/server/src/mail/mail.service.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { ConfigService } from '@nestjs/config';
|
||||
import { readFileSync } from 'fs';
|
||||
import { compile } from 'handlebars';
|
||||
import { createTransport, Transporter } from 'nodemailer';
|
||||
import { join } from 'path';
|
||||
|
||||
import { User } from '@/users/entities/user.entity';
|
||||
|
||||
@Injectable()
|
||||
export class MailService {
|
||||
private readonly transporter: Transporter;
|
||||
|
||||
constructor(private configService: ConfigService) {
|
||||
this.transporter = createTransport(
|
||||
{
|
||||
host: this.configService.get<string>('mail.host'),
|
||||
port: this.configService.get<number>('mail.host'),
|
||||
auth: {
|
||||
user: this.configService.get<string>('mail.username'),
|
||||
pass: this.configService.get<string>('mail.password'),
|
||||
},
|
||||
},
|
||||
{
|
||||
from: this.configService.get<string>('mail.from'),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
async sendForgotPasswordEmail(user: User, resetToken: string) {
|
||||
const url = `http://localhost:3000?modal=auth.reset&resetToken=${resetToken}`;
|
||||
const templateSource = readFileSync(join(__dirname, 'templates/forgot-password.hbs'), 'utf-8');
|
||||
const template = compile(templateSource);
|
||||
const html = template({ name: user.name, url });
|
||||
|
||||
await this.transporter.sendMail({
|
||||
to: user.email,
|
||||
subject: 'Reset your Reactive Resume password',
|
||||
html,
|
||||
});
|
||||
}
|
||||
}
|
||||
68
apps/server/src/mail/templates/forgot-password.hbs
Normal file
68
apps/server/src/mail/templates/forgot-password.hbs
Normal file
@ -0,0 +1,68 @@
|
||||
<html lang='en'>
|
||||
|
||||
<head>
|
||||
<meta charset='UTF-8' />
|
||||
<meta http-equiv='X-UA-Compatible' content='IE=edge' />
|
||||
<meta name='viewport' content='width=device-width, initial-scale=1.0' />
|
||||
<title>Reset Password | Reactive Resume</title>
|
||||
|
||||
<link rel='preconnect' href='https://fonts.googleapis.com' />
|
||||
<link rel='preconnect' href='https://fonts.gstatic.com' crossorigin />
|
||||
<link href='https://fonts.googleapis.com/css2?family=Inter&display=swap' rel='stylesheet' />
|
||||
|
||||
<style>
|
||||
.container { margin: 0; padding: 48px 0; color: #eee; font-size: 14px; background-color: #222;
|
||||
font-family: 'Inter', sans-serif; display: flex; align-items: center; justify-content: center;
|
||||
} .inner { display: flex; align-items: center; flex-direction: column; } .logo {
|
||||
padding-bottom: 32px; } .box { max-width: 640px; padding: 8px 16px; border-radius: 4px;
|
||||
border: 1px solid #444; } .paragraph { line-height: 1.75em; } .button { display: inline-block;
|
||||
color: #222; margin: 6px 0; background-color: #eee; padding: 10px 16px; border-radius: 4px;
|
||||
text-decoration: none; } .footer { opacity: 0.5; align-self: flex-start; margin-top: 16px;
|
||||
max-width: 420px; font-size: 12px; } .footer span { display: block; line-height: 1.75em; }
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body class='container'>
|
||||
|
||||
<div class='inner'>
|
||||
<a href='https://rxresu.me'>
|
||||
<img
|
||||
class='logo'
|
||||
src='https://raw.githubusercontent.com/AmruthPillai/Reactive-Resume/develop/static/images/logo.png'
|
||||
alt='Reactive Resume'
|
||||
width='128px'
|
||||
/>
|
||||
</a>
|
||||
|
||||
<div class='box'>
|
||||
<p class='paragraph'>Hey {{name}},</p>
|
||||
|
||||
<p class='paragraph'>
|
||||
Trouble signing in? Don't worry, resetting your password is easy.
|
||||
<br />
|
||||
We'll have you up and running in no time.
|
||||
</p>
|
||||
|
||||
<p class='paragraph'>
|
||||
Just click the button below to set a new password.
|
||||
<br />
|
||||
But hurry, because the link expires in 30 minutes.
|
||||
</p>
|
||||
|
||||
<a class='button' href={{url}} target='_blank'>
|
||||
Reset your password
|
||||
</a>
|
||||
|
||||
<p class='paragraph'>If you did not request to change your password, then you can safely
|
||||
ignore this email.</p>
|
||||
</div>
|
||||
|
||||
<footer class='footer'>
|
||||
<span>By the community, for the community.</span>
|
||||
<span>Thank you for using Reactive Resume.</span>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user