From 9f23b2582c3b037e7810454ab3a971b9ef43c7cf Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 10 Aug 2020 19:37:01 -0400 Subject: [PATCH] seperate update user problems logic --- src/controllers/auth.ts | 3 -- src/controllers/user.ts | 26 ++++++++++++ src/routes/user.ts | 6 +++ src/validators/user.ts | 3 ++ tests/unit/controllers/auth.test.ts | 3 -- tests/unit/controllers/user.test.ts | 64 +++++++++++++++++++++++++++++ 6 files changed, 99 insertions(+), 6 deletions(-) diff --git a/src/controllers/auth.ts b/src/controllers/auth.ts index 6791e25..b7ec849 100644 --- a/src/controllers/auth.ts +++ b/src/controllers/auth.ts @@ -6,7 +6,6 @@ import { userDBInteractions } from "../database/interactions/user"; import { IUserModel } from "../database/models/user"; import { bcryptPassword } from "../config/bcrypt"; import { statusCodes } from "../config/statusCodes"; -import { codeforces } from "../util/codeforces"; import { auth } from "../util/auth"; const authController = { @@ -35,8 +34,6 @@ const authController = { message: "Invalid email or password" }); } else { - if (user.platformData.codeforces.username) - await codeforces.updateUserProblems(user); const token = jwt.sign( { id: user._id, diff --git a/src/controllers/user.ts b/src/controllers/user.ts index e56f699..c2fc1b6 100644 --- a/src/controllers/user.ts +++ b/src/controllers/user.ts @@ -236,6 +236,32 @@ const userController = { } }, + updateUserProblems: async (req: Request, res: Response) => { + const errors = validationResult(req); + if (!errors.isEmpty()) { + res.status(statusCodes.MISSING_PARAMS).json( + errors.formatWith(errorMessage).array()[0] + ); + } else { + try { + const { userId } = req.params; + const user: IUserModel = await userDBInteractions.find(userId); + if (!user) + res.status(statusCodes.NOT_FOUND).json({ + status: statusCodes.NOT_FOUND, + message: "User not found" + }); + else { + if (user.platformData.codeforces.username) + await codeforces.updateUserProblems(user); + res.status(statusCodes.SUCCESS).json(user); + } + } catch (error) { + res.status(statusCodes.SERVER_ERROR).json(error); + } + } + }, + delete: async (req: Request, res: Response) => { const errors = validationResult(req); if (!errors.isEmpty()) { diff --git a/src/routes/user.ts b/src/routes/user.ts index 700f10a..d77ca54 100644 --- a/src/routes/user.ts +++ b/src/routes/user.ts @@ -22,6 +22,12 @@ userRouter.put( userRouter.patch("/resetLastSubmissions", userController.resetLastSubmissions); +userRouter.patch( + "/:userId/updateUserProblems", + userValidator("PATCH /users/:userId/updateUserProblems"), + userController.updateUserProblems +); + userRouter.patch( "/:userId/problems", userValidator("PATCH /users/:userId/problems"), diff --git a/src/validators/user.ts b/src/validators/user.ts index 87d1868..81f95bc 100644 --- a/src/validators/user.ts +++ b/src/validators/user.ts @@ -71,6 +71,9 @@ export function userValidator(method: string): ValidationChain[] { ).custom(validPassword) ]; } + case "PATCH /users/:userId/updateUserProblems": { + return [param("userId", "Invalid ':userId'").isMongoId()]; + } case "PATCH /users/:userId/problems": { return [ param("userId", "Invalid ':userId'").isMongoId(), diff --git a/tests/unit/controllers/auth.test.ts b/tests/unit/controllers/auth.test.ts index cf438c2..3a56700 100644 --- a/tests/unit/controllers/auth.test.ts +++ b/tests/unit/controllers/auth.test.ts @@ -365,9 +365,6 @@ describe("Auth controller tests", () => { stubs.jwt.sign.returns(testToken); await authController.login(req, mockRes); sinon.assert.calledOnce(stubs.userDB.findByEmail); - sinon.assert.calledOnce( - stubs.userUtil.codeforces.updateUserProblems - ); sinon.assert.calledOnce(stubs.userValidator.validationResult); sinon.assert.calledWith(mockRes.status, statusCodes.SUCCESS); const tmp = testUser.toJSON(); diff --git a/tests/unit/controllers/user.test.ts b/tests/unit/controllers/user.test.ts index 7477d1e..e02f852 100644 --- a/tests/unit/controllers/user.test.ts +++ b/tests/unit/controllers/user.test.ts @@ -124,6 +124,70 @@ describe("Users controller tests", () => { }); }); + describe("UpdateUserProblems", () => { + let req; + beforeEach(() => { + req = mockReq({ + params: { + userId: testUser._id + } + }); + }); + it("status 200: updates user problems", async () => { + stubs.userValidator.validationResult.returns( + emptyValidationError() + ); + stubs.userDB.find.returns(testUser); + stubs.userUtil.codeforces.updateUserProblems.returns(); + await userController.updateUserProblems(req, mockRes); + sinon.assert.calledOnce(stubs.userDB.find); + sinon.assert.calledOnce( + stubs.userUtil.codeforces.updateUserProblems + ); + sinon.assert.calledOnce(stubs.userValidator.validationResult); + sinon.assert.calledWith(mockRes.status, statusCodes.SUCCESS); + sinon.assert.calledWith(mockRes.json, testUser); + }); + + it("status 404: returns an appropriate response if user with given id doesn't exist", async () => { + stubs.userValidator.validationResult.returns( + emptyValidationError() + ); + await userController.updateUserProblems(req, mockRes); + sinon.assert.calledOnce(stubs.userDB.find); + sinon.assert.calledWith(mockRes.status, statusCodes.NOT_FOUND); + sinon.assert.calledWith(mockRes.json, { + status: statusCodes.NOT_FOUND, + message: "User not found" + }); + }); + + it("status 422: returns an appropriate response with validation error", async () => { + const errorMsg = { + status: statusCodes.MISSING_PARAMS, + message: "params[userId]: Invalid or missing ':userId'" + }; + req.params.userId = "not ObjectId"; + stubs.userValidator.validationResult.returns( + validationErrorWithMessage(errorMsg) + ); + await userController.updateUserProblems(req, mockRes); + sinon.assert.calledOnce(stubs.userValidator.validationResult); + sinon.assert.calledWith(mockRes.status, statusCodes.MISSING_PARAMS); + sinon.assert.calledWith(mockRes.json, errorMsg); + }); + + it("status 500: fails to update user problems", async () => { + stubs.userValidator.validationResult.returns( + emptyValidationError() + ); + stubs.userDB.find.returns(testUser); + stubs.userUtil.codeforces.updateUserProblems.throws(); + await userController.updateUserProblems(req, mockRes); + sinon.assert.calledWith(mockRes.status, statusCodes.SERVER_ERROR); + }); + }); + describe("Show", () => { let req; beforeEach(() => {