From 7582873129c3d0f5b810678ba9a8914f567f05bb Mon Sep 17 00:00:00 2001 From: Ndahimana Bonheur Date: Thu, 30 May 2024 14:29:39 +0200 Subject: [PATCH] Feature Admin update role 187584923 (#36) * [delivers #187584923] Delivered with testing * [finished #187584923] Feature admin should update user role * [finishes #187584923] Feature admin should update user role * mend * [finishes #187584923] Feature admin should update user role 1 * mend * mend * mend * mend * [delivers #187584915] Added user login (#35) * mend * mend * mend * mend * [delivers #187584923] Delivered with testing * [finished #187584923] Feature admin should update user role * mend * [finishes #187584923] Feature admin should update user role 1 * mend * mend * mend * mend * mend * mend * mend * mend * [Delivers #187584922] Admin should be able to disable an account (#25) * [Delivers #187584922] Admin should be able to disable an account * Admin should be able to disable or enable an account * Admin should be able to disable or enable an account * Admin should be able to disable or enable an account * Admin should be able to disable or enable an account * Admin should be able to disable or enable an account * Adjusted the database * DB adjusted * adjusted info * done rebase * mend * mend * [delivers #187584923] Delivered with testing * [finished #187584923] Feature admin should update user role * mend * mend * mend * mend * mend * mend * mend * mend * mend * [delivers #187584923] Delivered with testing * [finished #187584923] Feature admin should update user role * mend * [finishes #187584923] Feature admin should update user role 1 * mend * mend * mend * mend * mend * mend * mend * mend * mend * mend * [finishes #187584923] finishes fix the errors * mend * mend * mend * mend --------- Co-authored-by: Mr. David <128073754+ProgrammerDATCH@users.noreply.github.com> Co-authored-by: Saddock Kabandana --- README.md | 8 +- package.json | 1 - public/BUILD.txt | 11 - public/ProjectManagement.jpg | Bin 40299 -> 0 bytes src/middlewares/index.ts | 0 src/middlewares/validation.ts | 5 +- .../auth/controller/authControllers.ts | 2 +- .../auth/repository/authRepositories.ts | 4 +- .../user/controller/userControllers.ts | 27 +- src/modules/user/test/user.spec.ts | 249 ++++++++++++------ .../user/validation/userValidations.ts | 9 + src/routes/index.ts | 5 +- src/routes/userRouter.ts | 5 +- swagger.json | 129 ++++++++- 14 files changed, 342 insertions(+), 113 deletions(-) delete mode 100644 public/BUILD.txt delete mode 100644 public/ProjectManagement.jpg delete mode 100644 src/middlewares/index.ts diff --git a/README.md b/README.md index 3b3a2d4d..7f93df74 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,8 @@ This is the backend for E-Commerce-Ninjas, written in Node.js with TypeScript. - Verification Email Endpoint - Resend verification Endpoint - Login Endpoint -- Admin change status Endpoint +- Admin Update Status Endpoint +- Admin Update Role Endpoint ## TABLE OF API ENDPOINTS SPECIFICATION AND DESCRIPTION @@ -42,8 +43,9 @@ This is the backend for E-Commerce-Ninjas, written in Node.js with TypeScript. | 3 | GET | /api/auth/verify-email/:token | 200 OK | public | Verifying email | | 4 | POST | /api/auth/send-verify-email | 200 OK | public | Resend verification email | | 5 | POST | /api/auth/login | 200 OK | public | Login with Email and Password | -| 6 | PUT | /api/users/admin-update-user-status/:id | 200 OK | private | Admin change status | - +| 5 | PUT | /api/users/admin-update-role/:id | 200 OK | private | Update the user role by admin| +| 6 | PUT | /api/users/admin-update-user-status/:id | 200 OK | private | Admin Update Status Endpoint | +| 7 | PUT | /api/users/admin-update-role/:id | 200 OK | private | Admin Update Role Endpoint | ## INSTALLATION diff --git a/package.json b/package.json index f7e34f47..52f57a2a 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,6 @@ "start": "ts-node-dev src/index.ts", "dev": "ts-node-dev src/index.ts", "test": "cross-env NODE_ENV=test npm run deleteAllTables && cross-env NODE_ENV=test npm run createAllTables && cross-env NODE_ENV=test npm run createAllSeeders && nyc cross-env NODE_ENV=test mocha --require ts-node/register 'src/**/*.spec.ts' --timeout 600000 --exit", - "test-dev": "cross-env NODE_ENV=development npm run deleteAllTables && cross-env NODE_ENV=development npm run createAllTables && cross-env NODE_ENV=development npm run createAllSeeders && nyc cross-env NODE_ENV=development mocha --require ts-node/register 'src/**/*.spec.ts' --timeout 600000 --exit", "coveralls": "nyc --reporter=lcov --reporter=text-lcov npm test | coveralls", "coverage": "cross-env NODE_ENV=test nyc mocha --require ts-node/register 'src/**/*.spec.ts' --timeout 600000 --exit", "lint": "eslint . --ext .ts", diff --git a/public/BUILD.txt b/public/BUILD.txt deleted file mode 100644 index 0099cd3b..00000000 --- a/public/BUILD.txt +++ /dev/null @@ -1,11 +0,0 @@ -Believe: Know that the problem you have identified has a solution, and trust that you and your team can build something to address it. - -Understand: Take the time to learn about the experience of the people affected by this problem / who will be using your solution – what does their journey look like? What are their pain points? What factors are affecting how they operate in / engage with the world? - -Invent: Create a Minimum Viable Product or prototype to test out an idea that you have! Be sure to keep in mind how your “invention” will meet your users’ needs. - -Listen: Get feedback from your users on your MVP / prototype and modify it as needed. - -Deliver: Continue to deliver refined versions of your MVP / prototype and improve it over time! - -Password@123 \ No newline at end of file diff --git a/public/ProjectManagement.jpg b/public/ProjectManagement.jpg deleted file mode 100644 index 1f26cd3809a096cefc632152ae17f5791f97692b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40299 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 F69BWjd_w>L diff --git a/src/middlewares/index.ts b/src/middlewares/index.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/src/middlewares/validation.ts b/src/middlewares/validation.ts index dfc0115c..09e222f4 100644 --- a/src/middlewares/validation.ts +++ b/src/middlewares/validation.ts @@ -99,4 +99,7 @@ const verifyUserCredentials = async (req: Request, res: Response, next: NextFunc -export { validation, isUserExist, isAccountVerified, verifyUserCredentials }; \ No newline at end of file + + + +export { validation, isUserExist, isAccountVerified,verifyUserCredentials }; \ No newline at end of file diff --git a/src/modules/auth/controller/authControllers.ts b/src/modules/auth/controller/authControllers.ts index 4b6dde4e..772ca29f 100644 --- a/src/modules/auth/controller/authControllers.ts +++ b/src/modules/auth/controller/authControllers.ts @@ -35,7 +35,7 @@ const sendVerifyEmail = async (req: any, res: Response) => { const verifyEmail = async (req: any, res: Response) => { try { await authRepositories.destroySession(req.user.id, req.session.token) - await authRepositories.UpdateUserByAttributes("isVerified", true, "id", req.user.id); + await authRepositories.updateUserByAttributes("isVerified", true, "id", req.user.id); res.status(httpStatus.OK).json({ status: httpStatus.OK, message: "Account verified successfully, now login." }); } catch (error) { return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ status: httpStatus.INTERNAL_SERVER_ERROR, message: error.message }); diff --git a/src/modules/auth/repository/authRepositories.ts b/src/modules/auth/repository/authRepositories.ts index afed5226..4eb75488 100644 --- a/src/modules/auth/repository/authRepositories.ts +++ b/src/modules/auth/repository/authRepositories.ts @@ -11,7 +11,7 @@ const findUserByAttributes = async (key:string, value:any) =>{ return await Users.findOne({ where: { [key]: value} }) } -const UpdateUserByAttributes = async (updatedKey:string, updatedValue:any, whereKey:string, whereValue:any) =>{ +const updateUserByAttributes = async (updatedKey:string, updatedValue:any, whereKey:string, whereValue:any) =>{ await Users.update({ [updatedKey]: updatedValue }, { where: { [whereKey]: whereValue} }); return await findUserByAttributes(whereKey, whereValue) } @@ -28,4 +28,4 @@ const destroySession = async (userId: number, token:string) =>{ return await Session.destroy({ where: {userId, token } }); } -export default { createUser, createSession, findUserByAttributes, destroySession, UpdateUserByAttributes, findSessionByUserId } \ No newline at end of file +export default { createUser, createSession, findUserByAttributes, destroySession, updateUserByAttributes, findSessionByUserId } \ No newline at end of file diff --git a/src/modules/user/controller/userControllers.ts b/src/modules/user/controller/userControllers.ts index 9e994339..40f1e77c 100644 --- a/src/modules/user/controller/userControllers.ts +++ b/src/modules/user/controller/userControllers.ts @@ -1,14 +1,35 @@ +// user Controllers import { Request, Response } from "express"; -import httpStatus from "http-status"; + import authRepositories from "../../auth/repository/authRepositories"; +import httpStatus from "http-status"; + +const updateUserRole = async (req: Request, res: Response) => { + try { + const data = await authRepositories.updateUserByAttributes("role", req.body.role, "id", req.params.id) + return res.status(httpStatus.OK).json({ + message: "User role updated successfully", + data + }); + } catch (error) { + return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ + status: httpStatus.INTERNAL_SERVER_ERROR, + message: error.message + }); + } +}; + const updateUserStatus = async (req: Request, res: Response): Promise => { try { const userId: number = Number(req.params.id); - const data = await authRepositories.UpdateUserByAttributes("status", req.body.status, "id", userId); + const data = await authRepositories.updateUserByAttributes("status", req.body.status, "id", userId); res.status(httpStatus.OK).json({ message: "Status updated successfully.", data }); } catch (error) { res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ status: httpStatus.INTERNAL_SERVER_ERROR, message: error.message }); } }; -export default { updateUserStatus }; + + + +export default { updateUserStatus,updateUserRole }; \ No newline at end of file diff --git a/src/modules/user/test/user.spec.ts b/src/modules/user/test/user.spec.ts index 26014c60..34823c9a 100644 --- a/src/modules/user/test/user.spec.ts +++ b/src/modules/user/test/user.spec.ts @@ -17,15 +17,15 @@ describe("Update User Status test case ", () => { let getUserStub: sinon.SinonStub; let updateUserStub: sinon.SinonStub; const testUserId = 1; - let userId: number= null; - const unknownId = 100; + let userId: number = null; + const unknownId = 100; it("should register a new user", (done) => { router() .post("/api/auth/register") .send({ - email: "niyofo8179@acuxi.com", + email: "nda1234@gmail.com", password: "userPassword@123" }) .end((error, response) => { @@ -37,97 +37,184 @@ describe("Update User Status test case ", () => { done(error); }); }); - it("should update the user status successfully", (done) => { - router() - .put(`/api/users/admin-update-user-status/${userId}`) - .send({ status: "disabled" }) - .end((err, res) => { - expect(res).to.have.status(200); - expect(res.body).to.be.an("object"); - expect(res.body).to.have.property("message", "Status updated successfully."); - done(err); - }); + it("should update the user status successfully", (done) => { + router() + .put(`/api/users/admin-update-user-status/${userId}`) + .send({ status: "disabled" }) + .end((err, res) => { + expect(res).to.have.status(200); + expect(res.body).to.be.an("object"); + expect(res.body).to.have.property("message", "Status updated successfully."); + done(err); }); + }); - it("should handle invalid user status", (done) => { - router() - .put(`/api/users/admin-update-user-status/${testUserId}`) - .send({ status: "disableddd" }) - .end((err, res) => { - expect(res).to.have.status(400); - expect(res.body).to.be.an("object"); - expect(res.body).to.have.property("message", "Status must be either 'enabled' or 'disabled'"); - done(err); - }); + it("should handle invalid user status", (done) => { + router() + .put(`/api/users/admin-update-user-status/${testUserId}`) + .send({ status: "disableddd" }) + .end((err, res) => { + expect(res).to.have.status(400); + expect(res.body).to.be.an("object"); + expect(res.body).to.have.property("message", "Status must be either 'enabled' or 'disabled'"); + done(err); }); + }); - it("should return 404 if user doesn't exist", (done) => { - router() - .put(`/api/users/admin-update-user-status/${unknownId}`) - .send({ status: "disabled" }) - .end((err, res) => { - expect(res).to.have.status(httpStatus.NOT_FOUND); - expect(res.body).to.be.an("object"); - expect(res.body).to.have.property("status",httpStatus.NOT_FOUND); - expect(res.body).to.have.property("message", "User not found"); - done(err); - }); + it("should return 404 if user doesn't exist", (done) => { + router() + .put(`/api/users/admin-update-user-status/${unknownId}`) + .send({ status: "disabled" }) + .end((err, res) => { + expect(res).to.have.status(httpStatus.NOT_FOUND); + expect(res.body).to.be.an("object"); + expect(res.body).to.have.property("status", httpStatus.NOT_FOUND); + expect(res.body).to.have.property("message", "User not found"); + done(err); }); + }); }); describe("User Repository Functions", () => { - let findOneStub: sinon.SinonStub; - let updateStub: sinon.SinonStub; - - beforeEach(() => { - findOneStub = sinon.stub(Users, "findOne"); - updateStub = sinon.stub(Users, "update"); - }); - - afterEach(async () => { - sinon.restore(); - await Users.destroy({ where: {} }); + let findOneStub: sinon.SinonStub; + let updateStub: sinon.SinonStub; + + beforeEach(() => { + findOneStub = sinon.stub(Users, "findOne"); + updateStub = sinon.stub(Users, "update"); + }); + + afterEach(async () => { + sinon.restore(); + }); + + describe("getSingleUserById", () => { + it("should return a user if found", async () => { + const user = { id: 1, status: true }; + findOneStub.resolves(user); + const result = await authRepositories.findUserByAttributes("id", 1); + expect(findOneStub.calledOnce).to.be.true; + expect(findOneStub.calledWith({ where: { id: 1 } })).to.be.true; + expect(result).to.equal(user); }); - - describe("getSingleUserById", () => { - it("should return a user if found", async () => { - const user = { id: 1, status: true }; - findOneStub.resolves(user); - const result = await authRepositories.findUserByAttributes("id",1); + + it("should throw an error if there is a database error", async () => { + findOneStub.rejects(new Error("Database error")); + try { + await authRepositories.findUserByAttributes("id", 1); + } catch (error) { expect(findOneStub.calledOnce).to.be.true; - expect(findOneStub.calledWith({ where: { id: 1 } })).to.be.true; - expect(result).to.equal(user); - }); - - it("should throw an error if there is a database error", async () => { - findOneStub.rejects(new Error("Database error")); - try { - await authRepositories.findUserByAttributes("id",1); - } catch (error) { - expect(findOneStub.calledOnce).to.be.true; - expect(error.message).to.equal("Database error"); - } - }); + expect(error.message).to.equal("Database error"); + } }); - - describe("updateUserStatus", () => { - it("should update the user status successfully", async () => { - updateStub.resolves([1]); - const user = { id: 1, status: true }; - const result = await authRepositories.UpdateUserByAttributes("status", "enabled", "id", 1); + }); + + describe("updateUserStatus", () => { + it("should update the user status successfully", async () => { + updateStub.resolves([1]); + const user = { id: 1, status: true }; + const result = await authRepositories.updateUserByAttributes("status", "enabled", "id", 1); + expect(updateStub.calledOnce).to.be.true; + expect(updateStub.calledWith({ status: true }, { where: { id: 1 } })).to.be.false; + }); + + it("should throw an error if there is a database error", async () => { + updateStub.rejects(new Error("Database error")); + try { + await authRepositories.updateUserByAttributes("status", "enabled", "id", 1); + } catch (error) { expect(updateStub.calledOnce).to.be.true; - expect(updateStub.calledWith({ status: true }, { where: { id: 1 } })).to.be.false; + expect(error.message).to.equal("Database error"); + } + }); + }); +}); + + + +describe("Admin update User roles", () => { + + before(async () => { + await Users.destroy({ + where: {} + }) + }) + after(async () => { + await Users.destroy({ + where: {} + }) + }) + let userIdd: number = null; + + + it("should register a new user", (done) => { + router() + .post("/api/auth/register") + .send({ + email: "nda1234@gmail.com", + password: "userPassword@123" + }) + .end((error, response) => { + expect(response.status).to.equal(httpStatus.CREATED); + expect(response.body).to.be.an("object"); + expect(response.body).to.have.property("data"); + userIdd = response.body.data.user.id; + expect(response.body).to.have.property("message", "Account created successfully. Please check email to verify account."); + done(error); }); - - it("should throw an error if there is a database error", async () => { - updateStub.rejects(new Error("Database error")); - try { - await authRepositories.UpdateUserByAttributes("status", "enabled", "id", 1); - } catch (error) { - expect(updateStub.calledOnce).to.be.true; - expect(error.message).to.equal("Database error"); - } + }); + + it("Should notify if no role is specified", async () => { + + const response = await router() + .put(`/api/users/admin-update-role/${userIdd}`); + + expect(response.status).to.equal(httpStatus.BAD_REQUEST); + expect(response.body).to.have.property("message"); + }); + + it("Should notify if the role is other than ['Admin', 'Buyer', 'Seller']", async () => { + + const response = await router() + .put(`/api/users/admin-update-role/${userIdd}`) + .send({ role: "Hello" }); + + expect(response.status).to.equal(httpStatus.BAD_REQUEST); + expect(response.body).to.have.property("message", "Only Admin, Buyer and Seller are allowed."); + }); + + it("Should return error when invalid Id is passed", async () => { + const response = await router() + .put("/api/users/admin-update-role/invalid-id") + .send({ role: "Admin" }); + + expect(response.status).to.equal(httpStatus.INTERNAL_SERVER_ERROR); + expect(response).to.have.property("status", httpStatus.INTERNAL_SERVER_ERROR); + }); + + + it("Should update User and return updated user", (done) => { + router() + .put(`/api/users/admin-update-role/${userIdd}`) + .send({ role: "Admin" }) + .end((err, res) => { + expect(res).to.have.status(httpStatus.OK); + expect(res.body).to.be.an("object"); + expect(res.body).to.have.property("message", "User role updated successfully"); + done(err); }); - }); }); + + + it("Should return 404 if user is not found", (done) => { + router().put("/api/users/admin-update-role/10001").send({ role: "Admin" }).end((err, res) => { + expect(res).to.have.status(httpStatus.NOT_FOUND); + expect(res.body).to.be.an("object"); + expect(res.body).to.have.property("message", "User not found") + done(err) + }) + }) + + +}); \ No newline at end of file diff --git a/src/modules/user/validation/userValidations.ts b/src/modules/user/validation/userValidations.ts index 4b775e53..106ca645 100644 --- a/src/modules/user/validation/userValidations.ts +++ b/src/modules/user/validation/userValidations.ts @@ -7,3 +7,12 @@ export const statusSchema = Joi.object({ "any.required": "Status is required" }) }); + + +export const roleSchema = Joi.object({ + role: Joi.string().valid("Admin", "Buyer", "Seller").required().messages({ + "any.required": "The 'role' parameter is required.", + "string.base": "The 'role' parameter must be a string.", + "any.only": "Only Admin, Buyer and Seller are allowed." + }) +}); diff --git a/src/routes/index.ts b/src/routes/index.ts index 2a71fef1..197898e7 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -1,11 +1,12 @@ import { Router } from "express" import authRouter from "./authRouter" -import userRouter from "./userRouter" +import userRouter from "./userRouter"; + const router: Router = Router() router.use("/auth", authRouter); - router.use("/users", userRouter); + export default router; diff --git a/src/routes/userRouter.ts b/src/routes/userRouter.ts index 6bfe550f..ec66fdda 100644 --- a/src/routes/userRouter.ts +++ b/src/routes/userRouter.ts @@ -1,11 +1,12 @@ import { Router } from "express"; import userControllers from "../modules/user/controller/userControllers"; import {isUserExist, validation} from "../middlewares/validation"; -import { statusSchema } from "../modules/user/validation/userValidations"; +import { statusSchema,roleSchema } from "../modules/user/validation/userValidations"; const router: Router = Router() router.put("/admin-update-user-status/:id", validation(statusSchema), isUserExist, userControllers.updateUserStatus); +router.put("/admin-update-role/:id",validation(roleSchema),isUserExist, userControllers.updateUserRole); -export default router; +export default router; \ No newline at end of file diff --git a/swagger.json b/swagger.json index 816b55ab..bf6be133 100644 --- a/swagger.json +++ b/swagger.json @@ -3,7 +3,7 @@ "info": { "version": "1.0.0", "title": "E-commerce-ninjas", - "description": "APIs for the E-commmerce-ninjas Project", + "description": "APIs for the E-commerce-ninjas Project", "termsOfService": "https://github.com/atlp-rwanda/e-commerce-ninjas-bn/blob/develop/README.md", "contact": { "email": "e-commerce-ninjas@andela.com" @@ -26,7 +26,7 @@ }, { "name": "Admin User Routes", - "description": "Change User Status Endpoint | PUT Route" + "description": "" } ], "schemes": [ @@ -34,12 +34,10 @@ "https" ], "consumes": [ - "application/json", - "none" + "application/json" ], "produces": [ - "application/json", - "none" + "application/json" ], "paths": { "/": { @@ -429,6 +427,125 @@ } } } + }, + + "/api/users/admin-update-role/{id}": { + "put": { + "tags": [ + "Admin User Routes" + ], + "summary": "Update user role", + "description": "This endpoint allows admin to update a user's role", + "parameters": [ + { + "in":"path", + "name": "id", + "type": "string", + "description":"Pass the ID" + } + ], + "requestBody": { + "description": "User role update details", + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "role": { + "type": "string", + "enum": [ + "Admin", + "Buyer", + "Seller" + ] + } + }, + "required": [ + "role" + ] + } + } + } + }, + "responses": { + "200": { + "description": "User role updated successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean" + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "400": { + "description": "Invalid input", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "404": { + "description": "User not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string" + } + } + } + } + } + }, + "500": { + "description": "Internal server error", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "example": false + }, + "message": { + "type": "string" + } + } + } + } + } + } + } + } } }, "components": {