From 8f60cc1e544eff82d2df186753823d0deb1a7597 Mon Sep 17 00:00:00 2001 From: Kfir Dayan Date: Wed, 21 Jun 2023 14:44:05 +0300 Subject: [PATCH] done refactoring User controller + UserModel --- src/controllers/UserController.ts | 155 ++++++++++++++++-------------- src/index.ts | 8 +- src/middlewares/errorHandler.ts | 17 ++-- src/models/userModel.ts | 116 +++++++++++++++++----- src/routes/userRouter.ts | 8 +- src/schemas/userSchema.ts | 2 - src/utils/ApiError.ts | 10 ++ 7 files changed, 201 insertions(+), 115 deletions(-) create mode 100644 src/utils/ApiError.ts diff --git a/src/controllers/UserController.ts b/src/controllers/UserController.ts index 76bd769..1436957 100644 --- a/src/controllers/UserController.ts +++ b/src/controllers/UserController.ts @@ -1,90 +1,101 @@ import { Request, Response } from 'express'; -// import { createUser } from '../models/userModel'; -import { IUser } from '../schemas/userSchema'; -import { User } from '../schemas/userSchema'; +import { createUser, loginUser, getAllUsers, deleteUser } from '../models/userModel'; +import { ApiError } from '../utils/ApiError'; import bcrypt from 'bcryptjs'; import jwt from 'jsonwebtoken'; import { clearJwtCookie, setJwtCookie } from '../middlewares/checkAuth'; -const create = async (req: Request, res: Response) => { +const create = async (req: Request, res: Response, next) => { try { const { email, password, address } = req.body; - const user = await User.create({ email, password, address }); + const user = await createUser({ + email, + password, + address + }); + if(user instanceof ApiError) { + return next(user); + } res.status(201).json(user); - } catch(error) { - res.status(500).json({ error: 'An error occurred during signup' }); + } catch { + const error = new ApiError('Error during user creation'); + error.statusCode = 500; + error.status = 'fail'; + next(error); } - } -// export async function login(req: Request, res: Response) { -// try { -// const { email, password } = req.body; -// // Check if the user exists -// const user: IUser | null = await User.findOne({ email }); -// if (!user) { -// console.error('User not found'); -// return res.status(401).json({ error: 'Invalid email or password' }); -// } +const login = async (req: Request, res: Response, next) => { + try { + const { email, password } = req.body; + const user: any = await loginUser({ + email, + password + }); + if(user instanceof ApiError) { + console.log("Error in login") + return res.status(user.statusCode).json({ error: user.message }); + } + const payload = { + userId: user._id + } + // Generate a JWT + const token = jwt.sign(payload, process.env.JWT_SECRET as string, { expiresIn: '1d' }); + setJwtCookie(res, token); + // Send the JWT as the response + res.status(200).json({ + token + }); + } catch { + const error = new ApiError('Error during user login'); + error.statusCode = 500; + error.status = 'fail'; + next(error) + } +} -// // Compare the provided password with the stored password -// const isPasswordCorrect = await bcrypt.compare(password, user.password); -// if (!isPasswordCorrect) { -// console.error('Invalid password'); -// return res.status(401).json({ error: 'Invalid email or password' }); -// } +const logout = async (req: Request, res: Response, next) => { + try { + clearJwtCookie(res); + res.status(200).json({ message: 'Logout successful' }); + } catch { + const error = new ApiError('Error during user logout'); + error.statusCode = 500; + error.status = 'fail'; + next(error); + } +} -// const payload = { -// userId: user._id -// } -// // Generate a JWT -// const token = jwt.sign(payload, process.env.JWT_SECRET as string, { expiresIn: '1d' }); +const getAll = async (req: Request, res: Response, next) => { + try { + const users = await getAllUsers(); + res.status(200).json(users); + } catch { + const error = new ApiError('Error during user retrieval'); + error.statusCode = 500; + error.status = 'fail'; + next(error); + } +} -// setJwtCookie(res, token); +const deleteHandler = async (req: Request, res: Response, next) => { + try { + const { id } = req.params; + const user = await deleteUser(id); + res.status(200).json(user); + } catch { + const error = new ApiError('Error during user deletion'); + error.statusCode = 500; + error.status = 'fail'; + next(error); + } +} -// // Send the JWT as the response -// res.status(200).json({ -// token -// }); -// } catch (error) { -// console.error('Error during login:', error); -// res.status(500).json({ error: 'An error occurred during login' }); -// } -// } -// export async function logout(req: Request, res: Response) { -// try { -// clearJwtCookie(res); -// res.status(200).json({ message: 'Logout successful' }); -// } catch (error) { -// console.error('Error during logout:', error); -// res.status(500).json({ error: 'An error occurred during logout' }); -// } -// } - -// export async function getAllUsers(req: Request, res: Response) { -// try { -// const users = await User.find().select('-__v -password'); -// res.status(200).json({ users }); -// } catch (error) { -// console.error('Error getting all users:', error); -// res.status(500).json({ error: 'An error occurred while getting all users' }); -// } -// } - -// export async function deleteUser(req: Request, res: Response) { -// try { -// const { id } = req.params; -// const user = await User.findByIdAndDelete(id); -// if (!user) { -// return res.status(404).json({ error: 'User not found' }); -// } -// res.status(200).json({ message: 'User deleted successfully' }); -// } catch (error) { -// console.error('Error deleting user:', error); -// res.status(500).json({ error: 'An error occurred while deleting the user' }); -// } -// } export { - create + create, + getAll, + logout, + login, + deleteHandler } \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index d228490..48be17e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -7,6 +7,8 @@ import productRouter from './routes/productRouter'; import cartRouter from './routes/cartRouter'; import { errorHandler } from './middlewares/errorHandler'; +import { ApiError } from './utils/ApiError'; + const env = require('dotenv').config().parsed; @@ -40,9 +42,9 @@ app.use('/cart', cartRouter); app.all('*', (req, res, next) => { // res.status(404).json({ error: 'Route not found' }); - const error = new Error('Route not found'); - // error.statusCode = 404; - // error.status = 'fail'; + const error = new ApiError('Route not found'); + error.statusCode = 404; + error.status = 'fail'; next(error) }); diff --git a/src/middlewares/errorHandler.ts b/src/middlewares/errorHandler.ts index f2dfc32..5aca5bf 100644 --- a/src/middlewares/errorHandler.ts +++ b/src/middlewares/errorHandler.ts @@ -1,12 +1,13 @@ const errorHandler = (error, req, res, next) => { - // error.statusCode = error.statusCode || 500; - // error.message = error.message || 'Internal server error'; - // error.status = error.status || 'error'; - res.status(error).json( - { - error: error.message - }); - + error.statusCode = error.statusCode || 500; + error.message = error.message || 'Internal server error'; + error.status = error.status || 'error'; + res.status(error.statusCode).json({ + status: error.status, + statusCode: error.statusCode, + message: error.message + }); + } export { diff --git a/src/models/userModel.ts b/src/models/userModel.ts index 1ca8879..28b61aa 100644 --- a/src/models/userModel.ts +++ b/src/models/userModel.ts @@ -1,34 +1,98 @@ -// import { User, IUser } from "../schemas/userSchema"; -// import validate from 'deep-email-validator'; +import { User, IUser } from "../schemas/userSchema"; +import validate from 'deep-email-validator'; +import { ApiError } from "../utils/ApiError"; +import { response } from "express"; +import bcrypt from 'bcryptjs'; -// const createUser = async (user: IUser) => { +const createUser = async (user: any) => { -// if (!user.email || !user.password || !user.address) { -// console.log('All inputs are required') -// } + if (!user.email || !user.password || !user.address) { + const error = new ApiError('Missing required fields'); + error.statusCode = 400; + error.status = 'fail'; + return error; + } -// const { valid, reason, validators } = await validate(user.email); -// if (!valid) { -// // throw new Error(reason); -// console.log(reason) + const { valid, reason, validators } = await validate(user.email); + if (!valid) { + const error = new ApiError(reason); + error.statusCode = 400; + error.status = 'fail'; + return error; + } -// } + const userExists = await User.exists({ email: user.email }); + if (userExists) { + const error = new ApiError('User already exists, Try login :)'); + error.statusCode = 400; + error.status = 'fail'; + return error; + } -// const userExists = await User.exists({ email: user.email }); -// if (userExists) { -// console.log('User already exists, Try login :)') -// } -// const newUser = new User(user); -// try { -// await newUser.save(); -// return newUser; -// } catch (error) { -// return error; -// } + const salt = await bcrypt.genSalt(10); + user.password = await bcrypt.hash(user.password, salt); -// } + const newUser = new User(user); + try { + await newUser.save(); + return { + email: newUser.email, + address: newUser.address, + }; + } catch (error) { + return error; + } +} -// export { -// createUser -// } \ No newline at end of file +const loginUser = async (user: any) => { + const { email, password } = user; + const userExists = await User.findOne({ email }); + if (!userExists) { + const error = new ApiError('Invalid email or password'); + error.statusCode = 404; + error.status = 'fail'; + return error; + } + + const isMatch = await bcrypt.compare(password, userExists.password); + if(!isMatch) { + const error = new ApiError('Invalid email or password'); + error.statusCode = 404; + error.status = 'fail'; + return error; + } + return userExists; +} + +const getAllUsers = async () => { + try { + const users = await User.find(); + return users; + } catch { + const error = new ApiError('Error during fetching users'); + error.statusCode = 500; + error.status = 'fail'; + return error; + } +} + +const deleteUser = async (id: string) => { + try { + const user = await User.findByIdAndDelete(id); + return user; + } catch { + const error = new ApiError('Error during user deletion'); + error.statusCode = 500; + error.status = 'fail'; + return error; + } +} + + +export { + createUser, + loginUser, + getAllUsers, + deleteUser +} \ No newline at end of file diff --git a/src/routes/userRouter.ts b/src/routes/userRouter.ts index 129bdad..49134fd 100644 --- a/src/routes/userRouter.ts +++ b/src/routes/userRouter.ts @@ -1,12 +1,12 @@ import express from 'express'; -import { create } from '../controllers/userController'; +import { create, login, getAll, deleteHandler } from '../controllers/userController'; const userRouter = express.Router(); userRouter.post('/', create); -// userRouter.get('/', getAllUsers); -// userRouter.post('/login', login); +userRouter.get('/', getAll); +userRouter.post('/login', login); // userRouter.post('/logout', logout); -// userRouter.delete('/:id', deleteUser) +userRouter.delete('/:id', deleteHandler) export default userRouter; \ No newline at end of file diff --git a/src/schemas/userSchema.ts b/src/schemas/userSchema.ts index c79a538..d515980 100644 --- a/src/schemas/userSchema.ts +++ b/src/schemas/userSchema.ts @@ -4,8 +4,6 @@ interface IUser extends Document { email: string; password: string; address: string; - createdAt: Date; - updatedAt: Date; } const UserSchema: Schema = new Schema({ diff --git a/src/utils/ApiError.ts b/src/utils/ApiError.ts new file mode 100644 index 0000000..2ccea2f --- /dev/null +++ b/src/utils/ApiError.ts @@ -0,0 +1,10 @@ +class ApiError extends Error { + statusCode: number; + status: string; + + constructor(message: string) { + super(message); + } +} + +export { ApiError }; \ No newline at end of file