diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml index 630b7482..86660e40 100644 --- a/.github/workflows/node.js.yml +++ b/.github/workflows/node.js.yml @@ -50,7 +50,6 @@ jobs: curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter chmod +x ./cc-test-reporter ./cc-test-reporter before-build - - name: Run tests run: npm run test diff --git a/src/__test__/users.test.ts b/src/__test__/users.test.ts index 19fa8ed8..58924aa8 100644 --- a/src/__test__/users.test.ts +++ b/src/__test__/users.test.ts @@ -7,9 +7,11 @@ import { login_user, login_user_invalid_email, login_user_wrong_credentials, - register_user, + NewUser, + user_bad_request } from "../mock/static"; + jest.setTimeout(30000); function logErrors( @@ -32,13 +34,28 @@ describe("USER API TEST", () => { afterAll(async () => { await deleteTableData(User, "users"); }); - - it("should create a new user", async () => { - // Your test implementation goes here + it("it should register a user and return 201", async () => { const { body } = await Jest_request.post("/api/v1/users/register") - .send(register_user) + .send(NewUser) .expect(201); + expect(body.status).toStrictEqual("SUCCESS"); + expect(body.message).toStrictEqual("Account Created successfully!"); + expect(body.token).toBeDefined(); + }); + it("it should return a user not found and status 400", async () => { + const { body } = await Jest_request.post("/api/v1/users/register") + .send(user_bad_request) + .expect(400); + }); + + it("it should return a user exist and status 409 when Email is already used in database", async () => { + const { body } = await Jest_request.post("/api/v1/users/register") + .send(NewUser) + .expect(409); + expect(body.status).toStrictEqual("CONFLICT"); + expect(body.message).toStrictEqual("User already exist!"); }); + /** * ---------------------------- LOGIN -------------------------------------------- @@ -78,4 +95,6 @@ describe("USER API TEST", () => { expect(body.status).toStrictEqual("BAD REQUEST"); expect(body.message).toBeDefined(); }) + + }); diff --git a/src/controllers/userController.ts b/src/controllers/userController.ts index 3c613155..b1246ced 100644 --- a/src/controllers/userController.ts +++ b/src/controllers/userController.ts @@ -2,48 +2,42 @@ import { NextFunction, Request, Response } from "express"; import { UserModelAttributes } from "../database/models/User"; import { generateAccessToken } from "../helpers/security.helpers"; import { HttpException } from "../utils/http.exception"; -import passport from "../middlewares/passport"; +import passport, { CustomVerifyOptions } from "../middlewares/passport"; -interface InfoAttribute { - message: string; -} + +interface InfoAttribute extends CustomVerifyOptions {} const registerUser = async ( req: Request, res: Response, next: NextFunction, ) => { - try { - if (req.body) { - passport.authenticate( - "signup", - (err: Error, user: UserModelAttributes, info: InfoAttribute) => { - if (!user) { - return res - .status(404) - .json(new HttpException("NOT FOUND", info.message)); - } - (req as any).login(user, async () => { - if (err) { - return res - .status(400) - .json(new HttpException("BAD REQUEST", "Bad Request!")); - } - const token = generateAccessToken({ id: user.id, role: user.role }); - const response = new HttpException( - "SUCCESS", - "Account Created successfully!", - ).response(); - res.status(201).json({ ...response, token }); - }); - }, - )(req, res, next); - } - } catch (error) { - res - .status(500) - .json(new HttpException("SERVER ERROR", "Something went wrong!")); - } + try { + if (req.body) { + passport.authenticate( + "signup", + (err: Error, user: UserModelAttributes, info: InfoAttribute) => { + if (!user) { + return res + .status(info.statusNumber || 400) + .json(new HttpException(info.status, info.message)); + } + req.login(user, async () => { + const token = generateAccessToken({ id: user.id, role: user.role }); + const response = new HttpException( + "SUCCESS", + "Account Created successfully!" + ).response(); + res.status(201).json({ ...response, token }); + }); + } + )(req, res, next); + } + } catch (error) { + res + .status(500) + .json(new HttpException("SERVER FAILS", "Something went wrong!")); + } }; const login = async (req: Request, res: Response, next: NextFunction) => { @@ -82,6 +76,6 @@ const login = async (req: Request, res: Response, next: NextFunction) => { }; export default { - login, registerUser, + login }; diff --git a/src/database/config/config.ts b/src/database/config/config.js similarity index 100% rename from src/database/config/config.ts rename to src/database/config/config.js diff --git a/src/middlewares/passport.ts b/src/middlewares/passport.ts index 5127bc14..31e30220 100644 --- a/src/middlewares/passport.ts +++ b/src/middlewares/passport.ts @@ -1,82 +1,93 @@ -import { Request } from "express"; -import passport from "passport"; -import { Strategy as LocalStrategy } from "passport-local"; -import { User } from "../database/models/User"; -import { isValidPassword } from "../utils/password.checks"; -import { hashPassword } from "../utils/password"; - -passport.serializeUser(function (user: any, done) { - done(null, user); -}); - -passport.deserializeUser(function (user: any, done) { - done(null, user); -}); - -passport.use( - "signup", - new LocalStrategy( - { - usernameField: "email", - passwordField: "password", - passReqToCallback: true, - }, - async (req, email, password, done) => { - try { - const data = { - email: email.trim(), - password: await hashPassword(password), - confirmPassword: await hashPassword(req.body.confirmPassword), - userName: - req.body.userName == null - ? req.body.email.split("@")[0] - : req.body.userName, - firstName: req.body.firstName, - lastName: req.body.lastName, - role: "BUYER", - }; - const user = await User.create({ ...data }); - if (!user) { - return done(null, false, { - message: "Something went wrong", - }); - } - done(null, user); - } catch (error) { - done(error); - } - }, - ), -); - -passport.use( - "login", - new LocalStrategy( - { - usernameField: "email", - passwordField: "password", - passReqToCallback: true, - }, - async (_req: Request, email, password, done) => { - try { - const user = await User.findOne({ where: { email } }); - - if (!user) return done(null, false, { message: "Wrong credentials!" }); - - const currPassword = user.dataValues.password; - - const isValidPass = await isValidPassword(password, currPassword); - - if (!isValidPass) { - return done(null, false, { message: "Wrong credentials!" }); - } - - return done(null, user); - } catch (error) { - done(error); - } - }, - ), -); - -export default passport; +import { Request } from "express"; +import passport from "passport"; +import { Strategy as LocalStrategy } from "passport-local"; +import { User } from "../database/models/User"; +import { isValidPassword } from "../utils/password.checks"; +import { hashPassword } from "../utils/password"; +export interface CustomVerifyOptions { + message: string; + status: string; + statusNumber?: number; +} +passport.serializeUser(function (user: any, done) { + done(null, user); +}); + +passport.deserializeUser(function (user: any, done) { + done(null, user); +}); + +passport.use( + "signup", + new LocalStrategy( + { + usernameField: "email", + passwordField: "password", + passReqToCallback: true, + }, + async (req, email, password, done) => { + try { + const data = { + email: email.trim(), + password: await hashPassword(password), + confirmPassword: await hashPassword(req.body.confirmPassword), + userName: + req.body.userName == null + ? req.body.email.split("@")[0] + : req.body.userName, + firstName: req.body.firstName, + lastName: req.body.lastName, + role: "BUYER", + }; + const userEXist = await User.findOne({ + where: { + email: data.email, + }, + }); + if (userEXist) { + const options: CustomVerifyOptions = { + statusNumber: 409, + message: "User already exist!", + status: "CONFLICT", + }; + return done(null, false, options); + } + const user = await User.create({ ...data }); + done(null, user); + } catch (error) { + done(error); + } + } + ) +); + +passport.use( + "login", + new LocalStrategy( + { + usernameField: "email", + passwordField: "password", + passReqToCallback: true, + }, + async (_req: Request, email, password, done) => { + try { + const user = await User.findOne({ where: { email } }); + + if (!user) return done(null, false, { message: "Wrong credentials!" }); + + const currPassword = user.dataValues.password; + + const isValidPass = await isValidPassword(password, currPassword); + + if (!isValidPass) + return done(null, false, { message: "Wrong credentials!" }); + + return done(null, user); + } catch (error) { + done(error); + } + } + ) +); + +export default passport; diff --git a/src/middlewares/user.middleware.ts b/src/middlewares/user.middleware.ts index 6d526f8f..5926f59f 100644 --- a/src/middlewares/user.middleware.ts +++ b/src/middlewares/user.middleware.ts @@ -3,74 +3,50 @@ import { userValidate } from "../validations/user.valid"; import { NextFunction, Request, Response } from "express"; import validateLogIn from "../validations/login.validation"; import { HttpException } from "../utils/http.exception"; -import { User } from "../database/models/User"; - -const userExist = async (req: Request, res: Response, next: NextFunction) => { - try { - if (req.body) { - const newUSer = { - email: req.body.email, - password: req.body.password, - }; - - const user = await User.findOne({ - where: { - email: newUSer.email, - }, - }); - if (user) { - return res - .status(409) - .json(new HttpException("CONFLICT", "User already exist!!")); - } - } - next(); - } catch (error) { - res - .status(500) - .json(new HttpException("SERVER ERROR", "Something went wrong!!")); - } -}; const userValid = async (req: Request, res: Response, next: NextFunction) => { - try { - if (req.body) { - const { error } = userValidate(req.body); - if (error) { - return res.status(400).json( - new HttpException( - "BAD REQUEST", - // eslint-disable-next-line no-useless-escape - error.details[0].message.replace(/\"/g, ""), - ), - ); - } - } - next(); - } catch (error) { - res - .status(500) - .json(new HttpException("SERVER ERROR", "Something went wrong!!")); - } + try { + if (req.body) { + const { error } = userValidate(req.body); + if (error) { + return res + .status(400) + .json( + new HttpException( + "BAD REQUEST", + error.details[0].message.replace(/\"/g, "") + ) + ); + } + } + next(); + } catch (error) { + res + .status(500) + .json({ + status: "SERVER FAIL", + message: "Something went wrong!!", + error: error, + }); + } }; const logInValidated = (req: Request, res: Response, next: NextFunction) => { - const error = validateLogIn(req.body); + const error = validateLogIn(req.body); - if (error) { - return res.status(400).json( - new HttpException( - "BAD REQUEST", - // eslint-disable-next-line no-useless-escape - error.details[0].message.replace(/\"/g, ""), - ), - ); - } + if (error) + return res + .status(400) + .json( + new HttpException( + "BAD REQUEST", + error.details[0].message.replace(/\"/g, "") + ) + ); - next(); + next(); }; export default { - logInValidated, - userExist, - userValid, + logInValidated, + userValid, }; diff --git a/src/mock/static.ts b/src/mock/static.ts index 659b3312..e85a2d3d 100644 --- a/src/mock/static.ts +++ b/src/mock/static.ts @@ -1,23 +1,48 @@ -export const register_user = { - userName: "hohndoe", - firstName: "John", - lastName: "Doe", - email: "john@example.com", - password: "", - confirmPassword: "", -}; - -export const login_user = { - email: "john@example.com", - password: "", -}; - -export const login_user_wrong_credentials = { - email: "john@example.com", - password: "", -}; - -export const login_user_invalid_email = { - email: "peter", - password: "", -}; + +export const login_user = { + email:"peter234565@gmail.com", + password:"passwordQWE123", +}; + +export const login_user_wrong_credentials = { + email: "john@example.com", + password: "", +}; + +export const login_user_invalid_email = { + email: "peter", + password: "", +}; + +export const NewUser={ + firstName:"peter", + lastName:"paul", + email:"peter234565@gmail.com", + password:"passwordQWE123", + confirmPassword:"passwordQWE123" +} + +export const exist_user={ + userName:"Tp", + firstName:"travis", + lastName:"paul", + email:"travis@gmail.com", + password:"passwordQWE123", + confirmPassword:"passwordQWE123", + role: "BUYER" +} +export const user_bad_request={ + firstName:"unknow", + lastName:"paul", + email:"unknown@gmail.com", + password:"passwordQWE123", + confirmPassword:"passwordQWE123", + age:12 +} + +export const User_without_email={ + firstName:"peter", + lastName:"paul", + password:"passwordQWE123", + confirmPassword:"passwordQWE123" +} diff --git a/src/routes/userRoutes.ts b/src/routes/userRoutes.ts index 6c383fb9..e036f36c 100644 --- a/src/routes/userRoutes.ts +++ b/src/routes/userRoutes.ts @@ -4,11 +4,12 @@ import userMiddleware from "../middlewares/user.middleware"; const userRoutes = express.Router(); userRoutes.post( - "/register", - userMiddleware.userValid, - userMiddleware.userExist, - userController.registerUser, + "/register", + userMiddleware.userValid, + userController.registerUser ); + userRoutes.post("/login", userMiddleware.logInValidated, userController.login); + export default userRoutes; diff --git a/src/services/user.services.ts b/src/services/user.services.ts new file mode 100644 index 00000000..3126afe9 --- /dev/null +++ b/src/services/user.services.ts @@ -0,0 +1,23 @@ +import { hashPassword } from "../utils/password"; +import { User } from "../database/models/User"; +import { UserModelAttributes } from "../database/models/User"; +interface UserInt { + userName: string; + firstName: string; + lastName: string; + email: string; + password: string; + confirmPassword: string; + role: string; +} +export const createUser = async (data: UserInt) => { + return User.create({ + email: data.email.trim(), + password: await hashPassword(data.password), + confirmPassword: await hashPassword(data.password), + userName: data.userName == null ? data.email.split("@")[0] : data.userName, + firstName: data.firstName, + lastName: data.lastName, + role: "BUYER", + }); +}; diff --git a/src/utils/database.utils.ts b/src/utils/database.utils.ts index 74f7dba8..54c6a482 100644 --- a/src/utils/database.utils.ts +++ b/src/utils/database.utils.ts @@ -1,14 +1,14 @@ -export const deleteTableData = async (Model: any, tableName: string) => { - try { - const deletedRows = await Model.destroy({ - where: {}, - truncate: true, - cascade: true, - }); - if (deletedRows) { - console.log(`${deletedRows} rows have been deleted from ${tableName}.`); - } - } catch (error) { - console.log("Something went wrong in the process:", error); - } -}; +export const deleteTableData = async (Model: any, tableName: string) => { + try { + const deletedRows = await Model.destroy({ + where: {}, + truncate: true, + cascade: true, + }); + if (deletedRows) { + console.log(`${deletedRows} rows have been deleted from ${tableName}.`); + } + } catch (error) { + console.log("Something went wrong in the process:", error); + } +};