Files
bigcapital/server/src/http/controllers/Authentication.ts
2020-09-05 13:29:39 +02:00

220 lines
5.9 KiB
TypeScript

import { Request, Response, Router } from 'express';
import { check, ValidationChain } from 'express-validator';
import { Service, Inject } from 'typedi';
import BaseController from '@/http/controllers/BaseController';
import validateMiddleware from '@/http/middleware/validateMiddleware';
import asyncMiddleware from '@/http/middleware/asyncMiddleware';
import AuthenticationService from '@/services/Authentication';
import { IUserOTD, ISystemUser, IRegisterOTD } from '@/interfaces';
import { ServiceError, ServiceErrors } from "@/exceptions";
@Service()
export default class AuthenticationController extends BaseController{
@Inject()
authService: AuthenticationService;
/**
* Constructor method.
*/
router() {
const router = Router();
router.post(
'/login',
this.loginSchema,
validateMiddleware,
asyncMiddleware(this.login.bind(this))
);
router.post(
'/register',
this.registerSchema,
validateMiddleware,
asyncMiddleware(this.register.bind(this))
);
router.post(
'/send_reset_password',
this.sendResetPasswordSchema,
validateMiddleware,
asyncMiddleware(this.sendResetPassword.bind(this))
);
router.post(
'/reset/:token',
this.resetPasswordSchema,
validateMiddleware,
asyncMiddleware(this.resetPassword.bind(this))
);
return router;
}
/**
* Login schema.
*/
get loginSchema(): ValidationChain[] {
return [
check('crediential').exists().isEmail(),
check('password').exists().isLength({ min: 5 }),
];
}
/**
* Register schema.
*/
get registerSchema(): ValidationChain[] {
return [
check('organization_name').exists().trim().escape(),
check('first_name').exists().trim().escape(),
check('last_name').exists().trim().escape(),
check('email').exists().trim().escape(),
check('phone_number').exists().trim().escape(),
check('password').exists().trim().escape(),
check('country').exists().trim().escape(),
];
}
/**
* Reset password schema.
*/
get resetPasswordSchema(): ValidationChain[] {
return [
check('password').exists().isLength({ min: 5 })
.custom((value, { req }) => {
if (value !== req.body.confirm_password) {
throw new Error("Passwords don't match");
} else {
return value;
}
}),
];
}
/**
* Send reset password validation schema.
*/
get sendResetPasswordSchema(): ValidationChain[] {
return [
check('email').exists().isEmail().trim().escape(),
];
}
/**
* Handle user login.
* @param {Request} req
* @param {Response} res
*/
async login(req: Request, res: Response, next: Function): Response {
const userDTO: IUserOTD = this.matchedBodyData(req);
try {
const { token, user } = await this.authService.signIn(
userDTO.crediential,
userDTO.password
);
return res.status(200).send({ token, user });
} catch (error) {
if (error instanceof ServiceError) {
if (['invalid_details', 'invalid_password'].indexOf(error.errorType) !== -1) {
return res.boom.badRequest(null, {
errors: [{ type: 'INVALID_DETAILS', code: 100 }],
});
}
if (error.errorType === 'user_inactive') {
return res.boom.badRequest(null, {
errors: [{ type: 'INVALID_DETAILS', code: 200 }],
});
}
}
next();
}
}
/**
* Organization register handler.
* @param {Request} req
* @param {Response} res
*/
async register(req: Request, res: Response, next: Function) {
const registerDTO: IRegisterOTD = this.matchedBodyData(req);
try {
const registeredUser: ISystemUser = await this.authService.register(registerDTO);
return res.status(200).send({
code: 'REGISTER.SUCCESS',
message: 'Register organization has been success.',
});
} catch (error) {
if (error instanceof ServiceErrors) {
const errorReasons = [];
if (error.hasType('phone_number_exists')) {
errorReasons.push({ type: 'PHONE_NUMBER_EXISTS', code: 100 });
}
if (error.hasType('email_exists')) {
errorReasons.push({ type: 'EMAIL.EXISTS', code: 200 });
}
if (errorReasons.length > 0) {
return res.status(200).send({ errors: errorReasons });
}
}
next();
}
}
/**
* Send reset password handler
* @param {Request} req
* @param {Response} res
*/
async sendResetPassword(req: Request, res: Response, next: Function) {
const { email } = this.matchedBodyData(req);
try {
await this.authService.sendResetPassword(email);
return res.status(200).send({
code: 'SEND_RESET_PASSWORD_SUCCESS',
});
} catch(error) {
if (error instanceof ServiceError) {
if (error.errorType === 'email_not_found') {
return res.status(400).send({
errors: [{ type: 'EMAIL.NOT.REGISTERED', code: 200 }],
});
}
}
next();
}
}
/**
* Reset password handler
* @param {Request} req
* @param {Response} res
*/
async resetPassword(req: Request, res: Response) {
const { token } = req.params;
const { password } = req.body;
try {
await this.authService.resetPassword(token, password);
return res.status(200).send({
type: 'RESET_PASSWORD_SUCCESS',
})
} catch(error) {
if (error instanceof ServiceError) {
if (error.errorType === 'token_invalid') {
return res.boom.badRequest(null, {
errors: [{ type: 'TOKEN_INVALID', code: 100 }],
});
}
if (error.errorType === 'user_not_found') {
return res.boom.badRequest(null, {
errors: [{ type: 'USER_NOT_FOUND', code: 120 }],
});
}
}
}
}
};