-
Notifications
You must be signed in to change notification settings - Fork 85
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
26736f7
commit cb09ae3
Showing
13 changed files
with
6,067 additions
and
5,902 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import httpStatus from 'http-status'; | ||
import { Request, Response } from 'express'; | ||
import catchAsync from '../utils/catchAsync'; | ||
import { createUser } from '../Users/user.service'; | ||
import { generateAuthTokens, generateResetPasswordToken, generateVerifyEmailToken } from '../Tokens/token.service'; | ||
import { loginUserWithEmailAndPassword, logout, refreshAuth, resetPassword, verifyEmail } from './auth.service'; | ||
import { | ||
sendAccountCreated, | ||
sendResetPasswordEmail, | ||
sendSuccessfulRegistration, | ||
sendVerificationEmail, | ||
} from '../Email/email.service'; | ||
import config from '../config/config'; | ||
import { AccessAndRefreshTokens } from '../Tokens/token.interfaces'; | ||
|
||
export const sendTokens = (res: Response, tokens: AccessAndRefreshTokens) => { | ||
res.cookie('accessToken', tokens.access, config.jwt.cookieOptions); | ||
res.cookie('refreshToken', tokens.refresh, config.jwt.cookieOptions); | ||
}; | ||
|
||
export const register = catchAsync(async (req: Request, res: Response) => { | ||
const user = await createUser(req.body); | ||
const tokens = await generateAuthTokens(user); | ||
const verifyEmailToken = await generateVerifyEmailToken(user); | ||
await sendSuccessfulRegistration(user.email, verifyEmailToken, user.name); | ||
sendTokens(res, tokens); | ||
res.status(httpStatus.CREATED).send({ user }); | ||
}); | ||
|
||
export const login = catchAsync(async (req: Request, res: Response) => { | ||
const { email, password } = req.body; | ||
const user = await loginUserWithEmailAndPassword(email, password); | ||
const tokens = await generateAuthTokens(user); | ||
sendTokens(res, tokens); | ||
res.send({ user }); | ||
}); | ||
|
||
export const logoutController = catchAsync(async (req: Request, res: Response) => { | ||
await logout(req.cookies.refreshToken); | ||
res.status(httpStatus.NO_CONTENT).send(); | ||
}); | ||
|
||
export const refreshTokens = catchAsync(async (req: Request, res: Response) => { | ||
const tokens = await refreshAuth(req.cookies.refreshToken); | ||
sendTokens(res, tokens); | ||
res.status(httpStatus.OK).send(); | ||
}); | ||
|
||
export const forgotPassword = catchAsync(async (req: Request, res: Response) => { | ||
const resetPasswordToken = await generateResetPasswordToken(req.body.email); | ||
await sendResetPasswordEmail(req.body.email, resetPasswordToken); | ||
res.status(httpStatus.NO_CONTENT).send(); | ||
}); | ||
|
||
export const resetPasswordController = catchAsync(async (req: Request, res: Response) => { | ||
await resetPassword(req.cookies.resetPasswordToken, req.body.password); | ||
res.status(httpStatus.NO_CONTENT).send(); | ||
}); | ||
|
||
export const sendVerificationEmailController = catchAsync(async (req: Request, res: Response) => { | ||
const verifyEmailToken = await generateVerifyEmailToken(req.user); | ||
await sendVerificationEmail(req.user.email, verifyEmailToken, req.user.name); | ||
res.status(httpStatus.NO_CONTENT).send(); | ||
}); | ||
|
||
export const verifyEmailController = catchAsync(async (req: Request, res: Response) => { | ||
const user = await verifyEmail(req.cookies.verifyEmailToken); | ||
if (user) { | ||
await sendAccountCreated(user.email, user.name); | ||
} | ||
res.status(httpStatus.NO_CONTENT).send(); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
export interface Message { | ||
from: string; | ||
to: string; | ||
subject: string; | ||
text: string; | ||
html?: string; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,118 @@ | ||
import nodemailer from 'nodemailer'; | ||
import config from '../config/config'; | ||
import logger from '../config/logger'; | ||
import { Message } from './email.interfaces'; | ||
|
||
export const transport = nodemailer.createTransport(config.email.smtp); | ||
/* istanbul ignore next */ | ||
if (config.env !== 'test') { | ||
transport | ||
.verify() | ||
.then(() => logger.info('Connected to email server')) | ||
.catch(() => logger.warn('Unable to connect to email server. Make sure you have configured the SMTP options in .env')); | ||
} | ||
|
||
/** | ||
* Send an email | ||
* @param {string} to | ||
* @param {string} subject | ||
* @param {string} text | ||
* @param {string} html | ||
* @returns {Promise<void>} | ||
*/ | ||
export const sendEmail = async (to: string, subject: string, text: string, html: string): Promise<void> => { | ||
const msg: Message = { from: config.email.from, to, subject, text, html }; | ||
await transport.sendMail(msg); | ||
}; | ||
|
||
/** | ||
* Send reset password email | ||
* @param {string} to | ||
* @param {string} token | ||
* @returns {Promise<void>} | ||
*/ | ||
export const sendResetPasswordEmail = async (to: string, token: string): Promise<void> => { | ||
const subject = 'Reset password'; | ||
// replace this url with the link to the reset password page of your front-end app | ||
const resetPasswordUrl = `http://link-to-app/reset-password?token=${token}`; | ||
const text = `Hi, | ||
To reset your password, click on this link: ${resetPasswordUrl} | ||
If you did not request any password resets, then ignore this email.`; | ||
const html = `<div style="margin:30px; padding:30px; border:1px solid black; border-radius: 20px 10px;"><h4><strong>Dear user,</strong></h4> | ||
<p>To reset your password, click on this link: ${resetPasswordUrl}</p> | ||
<p>If you did not request any password resets, please ignore this email.</p> | ||
<p>Thanks,</p> | ||
<p><strong>Team</strong></p></div>`; | ||
await sendEmail(to, subject, text, html); | ||
}; | ||
|
||
/** | ||
* Send verification email | ||
* @param {string} to | ||
* @param {string} token | ||
* @param {string} name | ||
* @returns {Promise<void>} | ||
*/ | ||
export const sendVerificationEmail = async (to: string, token: string, name: string): Promise<void> => { | ||
const subject = 'Email Verification'; | ||
// replace this url with the link to the email verification page of your front-end app | ||
const verificationEmailUrl = `http://link-to-app/verify-email?token=${token}`; | ||
const text = `Hi ${name}, | ||
To verify your email, click on this link: ${verificationEmailUrl} | ||
If you did not create an account, then ignore this email.`; | ||
const html = `<div style="margin:30px; padding:30px; border:1px solid black; border-radius: 20px 10px;"><h4><strong>Hi ${name},</strong></h4> | ||
<p>To verify your email, click on this link: ${verificationEmailUrl}</p> | ||
<p>If you did not create an account, then ignore this email.</p></div>`; | ||
await sendEmail(to, subject, text, html); | ||
}; | ||
|
||
/** | ||
* Send email verification after registration | ||
* @param {string} to | ||
* @param {string} token | ||
* @param {string} name | ||
* @returns {Promise<void>} | ||
*/ | ||
export const sendSuccessfulRegistration = async (to: string, token: string, name: string): Promise<void> => { | ||
const subject = 'Email Verification'; | ||
// replace this url with the link to the email verification page of your front-end app | ||
const verificationEmailUrl = `http://link-to-app/verify-email?token=${token}`; | ||
const text = `Hi ${name}, | ||
Congratulations! Your account has been created. | ||
You are almost there. Complete the final step by verifying your email at: ${verificationEmailUrl} | ||
Don't hesitate to contact us if you face any problems | ||
Regards, | ||
Team`; | ||
const html = `<div style="margin:30px; padding:30px; border:1px solid black; border-radius: 20px 10px;"><h4><strong>Hi ${name},</strong></h4> | ||
<p>Congratulations! Your account has been created.</p> | ||
<p>You are almost there. Complete the final step by verifying your email at: ${verificationEmailUrl}</p> | ||
<p>Don't hesitate to contact us if you face any problems</p> | ||
<p>Regards,</p> | ||
<p><strong>Team</strong></p></div>`; | ||
await sendEmail(to, subject, text, html); | ||
}; | ||
|
||
/** | ||
* Send email verification after registration | ||
* @param {string} to | ||
* @param {string} name | ||
* @returns {Promise<void>} | ||
*/ | ||
export const sendAccountCreated = async (to: string, name: string): Promise<void> => { | ||
const subject = 'Account Created Successfully'; | ||
// replace this url with the link to the email verification page of your front-end app | ||
const loginUrl = `http://link-to-app/auth/login`; | ||
const text = `Hi ${name}, | ||
Congratulations! Your account has been created successfully. | ||
You can now login at: ${loginUrl} | ||
Don't hesitate to contact us if you face any problems | ||
Regards, | ||
Team`; | ||
const html = `<div style="margin:30px; padding:30px; border:1px solid black; border-radius: 20px 10px;"><h4><strong>Hi ${name},</strong></h4> | ||
<p>Congratulations! Your account has been created successfully.</p> | ||
<p>You can now login at: ${loginUrl}</p> | ||
<p>Don't hesitate to contact us if you face any problems</p> | ||
<p>Regards,</p> | ||
<p><strong>Team</strong></p></div>`; | ||
await sendEmail(to, subject, text, html); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
import httpStatus from 'http-status'; | ||
import { Request, Response } from 'express'; | ||
import mongoose from 'mongoose'; | ||
import catchAsync from '../utils/catchAsync'; | ||
import ApiError from '../utils/ApiError'; | ||
import pick from '../utils/pick'; | ||
import { createUser, queryUsers, getUserById, updateUserById, deleteUserById } from './user.service'; | ||
import { IOptions } from '../plugins/paginate'; | ||
|
||
export const createUserController = catchAsync(async (req: Request, res: Response) => { | ||
const user = await createUser(req.body); | ||
res.status(httpStatus.CREATED).send(user); | ||
}); | ||
|
||
export const getUsers = catchAsync(async (req: Request, res: Response) => { | ||
const filter = pick(req.query, ['name', 'role']); | ||
const options: IOptions = pick(req.query, ['sortBy', 'limit', 'page']); | ||
const result = await queryUsers(filter, options); | ||
res.send(result); | ||
}); | ||
|
||
export const getUser = catchAsync(async (req: Request, res: Response) => { | ||
if (typeof req.params['userId'] === 'string') { | ||
const user = await getUserById(new mongoose.Schema.Types.ObjectId(req.params['userId'])); | ||
if (!user) { | ||
throw new ApiError(httpStatus.NOT_FOUND, 'User not found'); | ||
} | ||
res.send(user); | ||
} | ||
}); | ||
|
||
export const updateUser = catchAsync(async (req: Request, res: Response) => { | ||
if (typeof req.params['userId'] === 'string') { | ||
const user = await updateUserById(new mongoose.Schema.Types.ObjectId(req.params['userId']), req.body); | ||
res.send(user); | ||
} | ||
}); | ||
|
||
export const deleteUser = catchAsync(async (req: Request, res: Response) => { | ||
if (typeof req.params['userId'] === 'string') { | ||
await deleteUserById(new mongoose.Schema.Types.ObjectId(req.params['userId'])); | ||
res.status(httpStatus.NO_CONTENT).send(); | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,9 @@ | ||
import { IUserDoc } from './Users/user.interfaces'; | ||
|
||
declare module 'express' { | ||
export interface Request { | ||
user: IUserDoc; | ||
} | ||
} | ||
|
||
declare module 'xss-clean'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.