mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2025-11-13 00:03:27 +10:00
perf(app): working docker build stage, with github actions ci to push image
This commit is contained in:
@ -4,7 +4,7 @@
|
||||
"projectType": "application",
|
||||
"targets": {
|
||||
"build": {
|
||||
"executor": "@nrwl/node:build",
|
||||
"executor": "@nrwl/node:webpack",
|
||||
"outputs": ["{options.outputPath}"],
|
||||
"options": {
|
||||
"outputPath": "dist/apps/server",
|
||||
@ -27,7 +27,7 @@
|
||||
}
|
||||
},
|
||||
"serve": {
|
||||
"executor": "@nrwl/node:execute",
|
||||
"executor": "@nrwl/node:node",
|
||||
"options": {
|
||||
"buildTarget": "server:build"
|
||||
},
|
||||
|
||||
288
apps/server/src/assets/templates/forgot-password.hbs
Normal file
288
apps/server/src/assets/templates/forgot-password.hbs
Normal file
@ -0,0 +1,288 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset='utf-8' />
|
||||
<meta http-equiv='x-ua-compatible' content='ie=edge' />
|
||||
<meta name='viewport' content='width=device-width, initial-scale=1' />
|
||||
|
||||
<title>Reset Your Password</title>
|
||||
|
||||
<style type='text/css'>
|
||||
@media screen { @font-face { font-family: "Source Sans Pro"; font-style: normal; font-weight: 400; src:
|
||||
local("Source Sans Pro Regular"), local("SourceSansPro-Regular"),
|
||||
url(https://fonts.gstatic.com/s/sourcesanspro/v10/ODelI1aHBYDBqgeIAH2zlBM0YzuT7MdOe03otPbuUS0.woff)
|
||||
format("woff"); } @font-face { font-family: "Source Sans Pro"; font-style: normal; font-weight: 700; src:
|
||||
local("Source Sans Pro Bold"), local("SourceSansPro-Bold"),
|
||||
url(https://fonts.gstatic.com/s/sourcesanspro/v10/toadOcfmlt9b38dHJxOBGFkQc6VGVFSmCnC_l7QZG60.woff)
|
||||
format("woff"); } } body, table, td, a { -ms-text-size-adjust: 100%; /* 1 */ -webkit-text-size-adjust: 100%; /* 2
|
||||
*/ } /** * Remove extra space added to tables and cells in Outlook. */ table, td { mso-table-rspace: 0pt;
|
||||
mso-table-lspace: 0pt; } /** * Better fluid images in Internet Explorer. */ img { -ms-interpolation-mode: bicubic;
|
||||
} /** * Remove blue links for iOS devices. */ a[x-apple-data-detectors] { font-family: inherit !important;
|
||||
font-size: inherit !important; font-weight: inherit !important; line-height: inherit !important; color: inherit
|
||||
!important; text-decoration: none !important; } /** * Fix centering issues in Android 4.4. */ div[style*="margin:
|
||||
16px 0; "] { margin: 0 !important; } body { width: 100% !important; height: 100% !important; padding: 0
|
||||
!important; margin: 0 !important; } /** * Collapse table borders to avoid space between cells. */ table {
|
||||
border-collapse: collapse !important; } a { color: #1a82e2; } img { height: auto; line-height: 100%;
|
||||
text-decoration: none; border: 0; outline: none; }
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body style='background-color: #e9ecef'>
|
||||
<!-- start preheader -->
|
||||
<div
|
||||
class='preheader'
|
||||
style='
|
||||
display: none;
|
||||
max-width: 0;
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
font-size: 1px;
|
||||
line-height: 1px;
|
||||
color: #fff;
|
||||
opacity: 0;
|
||||
'
|
||||
>
|
||||
Inside this email, you will find a unique link to reset your password. Do not share this email with anyone as your
|
||||
account may become compromised.
|
||||
</div>
|
||||
<!-- end preheader -->
|
||||
|
||||
<!-- start body -->
|
||||
<table border='0' cellpadding='0' cellspacing='0' width='100%'>
|
||||
<!-- start logo -->
|
||||
<tr>
|
||||
<td align='center' bgcolor='#e9ecef'>
|
||||
<!--[if (gte mso 9)|(IE)]>
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" width="600">
|
||||
<tr>
|
||||
<td align="center" valign="top" width="600">
|
||||
<![endif]-->
|
||||
<table border='0' cellpadding='0' cellspacing='0' width='100%' style='max-width: 600px'>
|
||||
<tr>
|
||||
<td align='center' valign='top' style='padding: 36px 24px'>
|
||||
<a href='https://rxresu.me/' target='_blank' style='display: inline-block'>
|
||||
<img
|
||||
src='https://i.imgur.com/pc8Ingg.png'
|
||||
alt='Reactive Resume Logo'
|
||||
border='0'
|
||||
width='128'
|
||||
style='
|
||||
display: block;
|
||||
width: 128px;
|
||||
max-width: 128px;
|
||||
min-width: 128px;
|
||||
'
|
||||
/>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<!--[if (gte mso 9)|(IE)]>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<![endif]-->
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end logo -->
|
||||
|
||||
<!-- start hero -->
|
||||
<tr>
|
||||
<td align='center' bgcolor='#e9ecef'>
|
||||
<!--[if (gte mso 9)|(IE)]>
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" width="600">
|
||||
<tr>
|
||||
<td align="center" valign="top" width="600">
|
||||
<![endif]-->
|
||||
<table border='0' cellpadding='0' cellspacing='0' width='100%' style='max-width: 600px'>
|
||||
<tr>
|
||||
<td
|
||||
align='left'
|
||||
bgcolor='#ffffff'
|
||||
style="
|
||||
padding: 36px 24px 0;
|
||||
font-family: 'Source Sans Pro', Helvetica, Arial, sans-serif;
|
||||
border-top: 3px solid #d4dadf;
|
||||
"
|
||||
>
|
||||
<h1
|
||||
style='
|
||||
margin: 0;
|
||||
font-size: 32px;
|
||||
font-weight: 700;
|
||||
letter-spacing: -1px;
|
||||
line-height: 48px;
|
||||
'
|
||||
>
|
||||
Hello,
|
||||
{{name}}!
|
||||
</h1>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<!--[if (gte mso 9)|(IE)]>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<![endif]-->
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end hero -->
|
||||
|
||||
<!-- start copy block -->
|
||||
<tr>
|
||||
<td align='center' bgcolor='#e9ecef'>
|
||||
<!--[if (gte mso 9)|(IE)]>
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" width="600">
|
||||
<tr>
|
||||
<td align="center" valign="top" width="600">
|
||||
<![endif]-->
|
||||
<table border='0' cellpadding='0' cellspacing='0' width='100%' style='max-width: 600px'>
|
||||
<!-- start copy -->
|
||||
<tr>
|
||||
<td
|
||||
align='left'
|
||||
bgcolor='#ffffff'
|
||||
style="
|
||||
padding: 24px;
|
||||
font-family: 'Source Sans Pro', Helvetica, Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
"
|
||||
>
|
||||
<p style='margin: 0'>
|
||||
Tap the button below to reset your account password. If you didn't request a new password, you can
|
||||
safely delete this email.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end copy -->
|
||||
|
||||
<!-- start button -->
|
||||
<tr>
|
||||
<td align='left' bgcolor='#ffffff'>
|
||||
<table border='0' cellpadding='0' cellspacing='0' width='100%'>
|
||||
<tr>
|
||||
<td align='center' bgcolor='#ffffff' style='padding: 12px'>
|
||||
<table border='0' cellpadding='0' cellspacing='0'>
|
||||
<tr>
|
||||
<td align='center' bgcolor='#1a82e2' style='border-radius: 6px'>
|
||||
<a
|
||||
href='{{url}}'
|
||||
target='_blank'
|
||||
style="
|
||||
display: inline-block;
|
||||
padding: 16px 36px;
|
||||
font-family: 'Source Sans Pro', Helvetica, Arial,
|
||||
sans-serif;
|
||||
font-size: 16px;
|
||||
color: #ffffff;
|
||||
text-decoration: none;
|
||||
border-radius: 6px;
|
||||
"
|
||||
>Reset Your Password</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end button -->
|
||||
|
||||
<!-- start copy -->
|
||||
<tr>
|
||||
<td
|
||||
align='left'
|
||||
bgcolor='#ffffff'
|
||||
style="
|
||||
padding: 24px;
|
||||
font-family: 'Source Sans Pro', Helvetica, Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
"
|
||||
>
|
||||
<p style='margin: 0'>
|
||||
If that doesn't work, copy and paste the following link in your browser:
|
||||
</p>
|
||||
<p style='margin: 0'>
|
||||
<a href='{{url}}' target='_blank'>{{url}}</a>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end copy -->
|
||||
|
||||
<!-- start copy -->
|
||||
<tr>
|
||||
<td
|
||||
align='left'
|
||||
bgcolor='#ffffff'
|
||||
style="
|
||||
padding: 24px;
|
||||
font-family: 'Source Sans Pro', Helvetica, Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
border-bottom: 3px solid #d4dadf;
|
||||
"
|
||||
>
|
||||
<p style='margin: 0'>
|
||||
Cheers,<br />
|
||||
<a href='https://www.amruthpillai.com/'>Amruth Pillai</a>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end copy -->
|
||||
</table>
|
||||
<!--[if (gte mso 9)|(IE)]>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<![endif]-->
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end copy block -->
|
||||
|
||||
<!-- start footer -->
|
||||
<tr>
|
||||
<td align='center' bgcolor='#e9ecef' style='padding: 24px'>
|
||||
<!--[if (gte mso 9)|(IE)]>
|
||||
<table align="center" border="0" cellpadding="0" cellspacing="0" width="600">
|
||||
<tr>
|
||||
<td align="center" valign="top" width="600">
|
||||
<![endif]-->
|
||||
<table border='0' cellpadding='0' cellspacing='0' width='100%' style='max-width: 600px'>
|
||||
<!-- start permission -->
|
||||
<tr>
|
||||
<td
|
||||
align='center'
|
||||
bgcolor='#e9ecef'
|
||||
style="
|
||||
padding: 12px 24px;
|
||||
font-family: 'Source Sans Pro', Helvetica, Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: #666;
|
||||
"
|
||||
>
|
||||
<p style='margin: 0'>
|
||||
You received this email because we received a request for resetting the password for your account. If
|
||||
you didn't request a password reset you can safely delete this email.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end permission -->
|
||||
</table>
|
||||
<!--[if (gte mso 9)|(IE)]>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<![endif]-->
|
||||
</td>
|
||||
</tr>
|
||||
<!-- end footer -->
|
||||
</table>
|
||||
<!-- end body -->
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@ -72,7 +72,7 @@ export class AuthService {
|
||||
}
|
||||
|
||||
forgotPassword(email: string) {
|
||||
this.usersService.generateResetToken(email);
|
||||
return this.usersService.generateResetToken(email);
|
||||
}
|
||||
|
||||
async resetPassword(resetPasswordDto: ResetPasswordDto) {
|
||||
|
||||
@ -13,13 +13,15 @@ const validationSchema = Joi.object({
|
||||
TZ: Joi.string().default('UTC'),
|
||||
PORT: Joi.number().default(3100),
|
||||
SECRET_KEY: Joi.string().required(),
|
||||
NODE_ENV: Joi.string().valid('development', 'production').default('development'),
|
||||
|
||||
// URLs
|
||||
APP_URL: Joi.string().default('http://localhost:3000'),
|
||||
SERVER_URL: Joi.string().default('http://localhost:3100'),
|
||||
NODE_ENV: Joi.string().valid('development', 'production').default('development'),
|
||||
|
||||
// Database
|
||||
POSTGRES_HOST: Joi.string().required(),
|
||||
POSTGRES_PORT: Joi.string().default(5432),
|
||||
POSTGRES_PORT: Joi.number().default(5432),
|
||||
POSTGRES_USERNAME: Joi.string().required(),
|
||||
POSTGRES_PASSWORD: Joi.string().required(),
|
||||
POSTGRES_DATABASE: Joi.string().required(),
|
||||
@ -33,7 +35,7 @@ const validationSchema = Joi.object({
|
||||
|
||||
// Mail
|
||||
MAIL_HOST: Joi.string().allow(''),
|
||||
MAIL_PORT: Joi.string().allow(''),
|
||||
MAIL_PORT: Joi.number().default(465),
|
||||
MAIL_USERNAME: Joi.string().allow(''),
|
||||
MAIL_PASSWORD: Joi.string().allow(''),
|
||||
});
|
||||
|
||||
@ -2,7 +2,7 @@ import { registerAs } from '@nestjs/config';
|
||||
|
||||
export default registerAs('mail', () => ({
|
||||
host: process.env.MAIL_HOST,
|
||||
port: parseInt(process.env.MAIL_PORT, 10),
|
||||
port: parseInt(process.env.MAIL_PORT, 10) || 465,
|
||||
username: process.env.MAIL_USERNAME,
|
||||
password: process.env.MAIL_PASSWORD,
|
||||
from: process.env.MAIL_FROM,
|
||||
|
||||
@ -19,8 +19,6 @@ import { User } from '@/users/entities/user.entity';
|
||||
database: configService.get<string>('postgres.database'),
|
||||
synchronize: true,
|
||||
entities: [User, Resume],
|
||||
migrations: [__dirname + 'migrations'],
|
||||
cli: { migrationsDir: __dirname + 'migrations' },
|
||||
}),
|
||||
}),
|
||||
],
|
||||
|
||||
@ -1,10 +0,0 @@
|
||||
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/' };
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,6 @@
|
||||
import { DynamicModule, Global, Module } from '@nestjs/common';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
|
||||
import { MailController } from './mail.controller';
|
||||
import { MailService } from './mail.service';
|
||||
|
||||
@Global()
|
||||
@ -12,7 +11,6 @@ export class MailModule {
|
||||
static register(): DynamicModule {
|
||||
return {
|
||||
module: MailModule,
|
||||
controllers: [MailController],
|
||||
providers: [MailService],
|
||||
exports: [MailService],
|
||||
};
|
||||
|
||||
@ -15,7 +15,7 @@ export class MailService {
|
||||
this.transporter = createTransport(
|
||||
{
|
||||
host: this.configService.get<string>('mail.host'),
|
||||
port: this.configService.get<number>('mail.host'),
|
||||
port: this.configService.get<number>('mail.port'),
|
||||
auth: {
|
||||
user: this.configService.get<string>('mail.username'),
|
||||
pass: this.configService.get<string>('mail.password'),
|
||||
@ -28,8 +28,9 @@ export class MailService {
|
||||
}
|
||||
|
||||
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 appUrl = this.configService.get<string>('app.url');
|
||||
const url = `${appUrl}?modal=auth.reset&resetToken=${resetToken}`;
|
||||
const templateSource = readFileSync(join(__dirname, 'assets/templates/forgot-password.hbs'), 'utf-8');
|
||||
const template = compile(templateSource);
|
||||
const html = template({ name: user.name, url });
|
||||
|
||||
|
||||
@ -1,68 +0,0 @@
|
||||
<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