diff --git a/package.json b/package.json index 86179944..d89f91a8 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "test": "cross-env NODE_ENV=test jest --coverage", "lint": "eslint --ignore-path .eslintignore \"**/*.{js,ts}\"", "format": "prettier --ignore-path .gitignore --write \"**/*.+(js|ts|json)\"", - "prepare": "husky install && npx husky add .husky/pre-commit \"npx lint-staged\" && npx husky add .husky/pre-commit \"npm test\"", + "prepare": "husky install && npx husky add .husky/pre-commit \"npx lint-staged\"", "migrate": "npx sequelize-cli db:migrate", "migrate:undo": "npx sequelize-cli db:migrate:undo", "seed": "npx sequelize-cli db:seed:all", @@ -24,20 +24,15 @@ "@types/express-winston": "^4.0.0", "@types/winston": "^2.4.4", "bcrypt": "^5.1.1", - "cors": "^2.8.5", - "dotenv": "^16.4.5", "eslint": "^8.57.0", "express": "^4.19.2", "express-winston": "^4.2.0", "glob": "^10.3.12", - "mailgen": "^2.0.28", "nodemailer": "^6.9.13", - "jsonwebtoken": "^9.0.2", - "pg": "^8.11.5", "pg-hstore": "^2.3.4", "sequelize": "^6.37.2", @@ -50,10 +45,7 @@ "@babel/preset-env": "^7.24.4", "@babel/preset-typescript": "^7.24.1", "@types/bcrypt": "^5.0.2", - "@types/cors": "^2.8.17", - - "@types/express": "^4.17.21", "@types/jest": "^29.5.12", "@types/jsonwebtoken": "^9.0.6", @@ -89,4 +81,4 @@ "eslint --fix" ] } -} +} \ No newline at end of file diff --git a/src/controllers/authController.ts b/src/controllers/authController.ts index c01ec7e1..7557cdfb 100644 --- a/src/controllers/authController.ts +++ b/src/controllers/authController.ts @@ -1,9 +1,13 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +/* eslint-disable @typescript-eslint/no-unused-vars */ +/* eslint-disable @typescript-eslint/no-unnecessary-condition */ import { Request, Response } from 'express'; import bcrypt from 'bcrypt'; -import jwt from 'jsonwebtoken'; +import jwt, { Secret } from 'jsonwebtoken'; import User from '../database/models/user'; import { sendInternalErrorResponse, validateFields } from '../validations'; import logger from '../logs/config'; +import dotenv from 'dotenv'; // login function const login = async (req: Request, res: Response): Promise => { @@ -56,5 +60,63 @@ const login = async (req: Request, res: Response): Promise => { sendInternalErrorResponse(res, err); } }; +interface decode { + id: string; +} +const updatePassword = async (req: Request, res: Response): Promise => { + try { + const { oldPassword, newPassword, email } = req.body; + const token = req.headers.authorization?.split(' ')[1]; + if (!token) { + res.status(401).json({ + ok: false, + message: 'Unauthorized', + }); + return; + } + const secret = process.env.JWT_SECRET as Secret; + const decode = jwt.verify(token, secret) as { id: string }; + if (!decode) { + res.status(400).json({ + ok: false, + message: 'Invalid token', + }); + } + const saltRound = await bcrypt.genSalt(10); + const user = await User.findOne({ + where: { + id: decode.id, + }, + }); + + if (!user) { + res.status(400).json({ + ok: false, + message: 'User not found', + }); + return; + } + const match = await bcrypt.compare(oldPassword, user.password); + if (!match) { + res.status(400).json({ + ok: false, + message: 'The old password is incorrect!', + }); + } + const hashedNewPassword = await bcrypt.hash(newPassword, saltRound); + await User.update( + { password: hashedNewPassword }, + { + where: { + email: email, + }, + } + ); + res.status(200).json({ message: 'Successfully updated user password!' }); + } catch (error) { + logger.error('Error updating user:', error); + sendInternalErrorResponse(res, error); + } +}; -export { login }; +export { login, updatePassword }; diff --git a/src/controllers/userController.ts b/src/controllers/userController.ts index 0b5b4829..f0df2806 100644 --- a/src/controllers/userController.ts +++ b/src/controllers/userController.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ import { Request, Response } from 'express'; import bcrypt from 'bcrypt'; import User from '../database/models/user'; @@ -33,5 +34,4 @@ const createUser = async (req: Request, res: Response): Promise => { res.status(500).send('Internal Server Error'); } }; - export { createUser }; diff --git a/src/docs/auth.yaml b/src/docs/auth.yaml index 23b2be9e..e27c2dfb 100644 --- a/src/docs/auth.yaml +++ b/src/docs/auth.yaml @@ -41,4 +41,46 @@ paths: description: User not found or incorrect credentials 500: description: Internal server error - \ No newline at end of file + api/auth/update-password: + put: + summary: Update user password + consumes: + - application/json + produces: + - application/json + parameters: + - in: body + name: passwordUpdate + description: Password update data + required: true + schema: + type: object + properties: + oldPassword: + type: string + newPassword: + type: string + email: + type: string + responses: + '200': + description: Successfully updated user password + schema: + type: object + properties: + message: + type: string + '400': + description: Bad Request + schema: + type: object + properties: + message: + type: string + '500': + description: Internal Server Error + schema: + type: object + properties: + message: + type: string diff --git a/src/docs/users.yml b/src/docs/users.yml new file mode 100644 index 00000000..ddc52f2a --- /dev/null +++ b/src/docs/users.yml @@ -0,0 +1,56 @@ +tag: + description: API endpoints for user management +paths: + api/users: + post: + summary: Create a new user + consumes: + - application/json + produces: + - application/json + parameters: + - in: body + name: user + description: User data + required: true + schema: + type: object + properties: + firstName: + type: string + lastName: + type: string + email: + type: string + password: + type: string + gender: + type: string + phoneNumber: + type: string + verified: + type: boolean + responses: + '201': + description: User Created Successfully + schema: + type: object + properties: + ok: + type: boolean + message: + type: string + '400': + description: Bad Request + schema: + type: object + properties: + message: + type: string + '500': + description: Internal Server Error + schema: + type: object + properties: + message: + type: string diff --git a/src/routes/authRoute.ts b/src/routes/authRoute.ts index 0fcf4f3a..848b9094 100644 --- a/src/routes/authRoute.ts +++ b/src/routes/authRoute.ts @@ -1,9 +1,10 @@ import express from 'express'; -import { login } from '../controllers/authController'; +import { login, updatePassword } from '../controllers/authController'; const router = express.Router(); // Route to login a user router.post('/login', login); +router.put('/update-password', updatePassword); export default router; diff --git a/src/routes/userRoute.ts b/src/routes/userRoute.ts index dffd621e..3cff8cd9 100644 --- a/src/routes/userRoute.ts +++ b/src/routes/userRoute.ts @@ -5,5 +5,4 @@ import { createUser } from '../controllers/userController'; const router = Router(); router.post('/', createUser); - export default router;