From 59a59710eaf5c49acec29ee5a97866d1be666a72 Mon Sep 17 00:00:00 2001 From: "C. Fuhrman" Date: Tue, 1 Oct 2024 18:03:55 -0400 Subject: [PATCH] Users test passes and the UserController works (manual testing) --- server/__tests__/users.test.js | 6 +- server/controllers/users.js | 117 ++++++++++++++++----------------- server/models/users.js | 3 +- server/routers/users.js | 16 +++-- 4 files changed, 72 insertions(+), 70 deletions(-) diff --git a/server/__tests__/users.test.js b/server/__tests__/users.test.js index 506d8ec..280f30a 100644 --- a/server/__tests__/users.test.js +++ b/server/__tests__/users.test.js @@ -21,7 +21,7 @@ describe('Users', () => { getConnection: jest.fn().mockReturnThis(), // Add getConnection method collection: jest.fn().mockReturnThis(), findOne: jest.fn(), - insertOne: jest.fn().mockResolvedValue({ _id: new ObjectId() }), // Mock insertOne to return an ObjectId + insertOne: jest.fn().mockResolvedValue({ insertedId: new ObjectId() }), // Mock insertOne to return an ObjectId updateOne: jest.fn(), deleteOne: jest.fn(), }; @@ -31,7 +31,7 @@ describe('Users', () => { it('should register a new user', async () => { db.collection().findOne.mockResolvedValue(null); // No user found - db.collection().insertOne.mockResolvedValue({ _id: new ObjectId() }); + db.collection().insertOne.mockResolvedValue({ insertedId: new ObjectId() }); bcrypt.hash.mockResolvedValue('hashedPassword'); Folders.create.mockResolvedValue(true); @@ -48,7 +48,7 @@ describe('Users', () => { created_at: expect.any(Date), }); expect(Folders.create).toHaveBeenCalledWith('Dossier par Défaut', expect.any(String)); - expect(result._id).toBeDefined(); // Ensure result has _id + expect(result.insertedId).toBeDefined(); // Ensure result has insertedId }); // it('should update the user password', async () => { diff --git a/server/controllers/users.js b/server/controllers/users.js index 8f102b1..4d5c579 100644 --- a/server/controllers/users.js +++ b/server/controllers/users.js @@ -1,41 +1,45 @@ const emailer = require('../config/email.js'); -const model = require('../models/users.js'); +const userModel = require('../models/users.js'); const jwt = require('../middleware/jwtToken.js'); const db = require('../config/db.js'); const AppError = require('../middleware/AppError.js'); const { MISSING_REQUIRED_PARAMETER, LOGIN_CREDENTIALS_ERROR, GENERATE_PASSWORD_ERROR, UPDATE_PASSWORD_ERROR, DELETE_USER_ERROR } = require('../constants/errorCodes'); +// controllers must use arrow functions to bind 'this' to the class instance in order to access class properties as callbacks in Express class UsersController { constructor() { + console.log("UsersController constructor: db", db) this.db = db; - this.users = new model(this.db); + this.users = new userModel(this.db); + console.log("UsersController constructor: users", this.users); } - async register(req, res, next) { + register = async (req, res, next) => { try { const { email, password } = req.body; - + if (!email || !password) { throw new AppError(MISSING_REQUIRED_PARAMETER); } - - await model.register(email, password); - - emailer.registerConfirmation(email) - + + if (!this.users) { + throw new AppError('Users model not found'); + } + await this.users.register(email, password); + + emailer.registerConfirmation(email); + return res.status(200).json({ message: 'Utilisateur créé avec succès.' }); - - } - catch (error) { + + } catch (error) { return next(error); } } - - async login(req, res, next) { + login = async (req, res, next) => { try { const { email, password } = req.body; @@ -43,7 +47,11 @@ class UsersController { throw new AppError(MISSING_REQUIRED_PARAMETER); } - const user = await model.login(email, password); + if (!this) { + throw new AppError('UsersController not initialized'); + } + + const user = await this.users.login(email, password); if (!user) { throw new AppError(LOGIN_CREDENTIALS_ERROR); @@ -51,102 +59,93 @@ class UsersController { const token = jwt.create(user.email, user._id); - return res.status(200).json({ - token: token, - id: user.email - }); - - } - catch (error) { - return next(error); + return res.status(200).json({ token }); + } catch (error) { + next(error); } } - async resetPassword(req, res, next) { + resetPassword = async (req, res, next) => { try { const { email } = req.body; - + if (!email) { throw new AppError(MISSING_REQUIRED_PARAMETER); } - - const newPassword = await model.resetPassword(email); - + + const newPassword = await this.users.resetPassword(email); + if (!newPassword) { throw new AppError(GENERATE_PASSWORD_ERROR); } - + emailer.newPasswordConfirmation(email, newPassword); - + return res.status(200).json({ message: 'Nouveau mot de passe envoyé par courriel.' }); - } - catch (error) { + } catch (error) { return next(error); } } - - async changePassword(req, res, next) { + + changePassword = async (req, res, next) => { try { const { email, oldPassword, newPassword } = req.body; - + if (!email || !oldPassword || !newPassword) { throw new AppError(MISSING_REQUIRED_PARAMETER); } - + // verify creds first - const user = await model.login(email, oldPassword); - + const user = await this.users.login(email, oldPassword); + if (!user) { throw new AppError(LOGIN_CREDENTIALS_ERROR); } - - const password = await model.changePassword(email, newPassword) - + + const password = await this.users.changePassword(email, newPassword); + if (!password) { throw new AppError(UPDATE_PASSWORD_ERROR); } - + return res.status(200).json({ message: 'Mot de passe changé avec succès.' }); - } - catch (error) { + } catch (error) { return next(error); } } - - async delete(req, res, next) { + + delete = async (req, res, next) => { try { const { email, password } = req.body; - + if (!email || !password) { throw new AppError(MISSING_REQUIRED_PARAMETER); } - + // verify creds first - const user = await model.login(email, password); - + const user = await this.users.login(email, password); + if (!user) { throw new AppError(LOGIN_CREDENTIALS_ERROR); } - - const result = await model.delete(email) - + + const result = await this.users.delete(email); + if (!result) { - throw new AppError(DELETE_USER_ERROR) + throw new AppError(DELETE_USER_ERROR); } - + return res.status(200).json({ message: 'Utilisateur supprimé avec succès' }); - } - catch (error) { + } catch (error) { return next(error); } } - } -module.exports = new UsersController; +module.exports = UsersController; diff --git a/server/models/users.js b/server/models/users.js index 1738424..0d561d5 100644 --- a/server/models/users.js +++ b/server/models/users.js @@ -42,7 +42,8 @@ class Users { }; const result = await userCollection.insertOne(newUser); - const userId = result._id.toString(); + console.log("userCollection.insertOne() result", result); + const userId = result.insertedId.toString(); const folderTitle = 'Dossier par Défaut'; await Folders.create(folderTitle, userId); diff --git a/server/routers/users.js b/server/routers/users.js index 4e43ca5..649e813 100644 --- a/server/routers/users.js +++ b/server/routers/users.js @@ -2,12 +2,14 @@ const express = require('express'); const router = express.Router(); const jwt = require('../middleware/jwtToken.js'); -const usersController = require('../controllers/users.js') +const usersController = require('../controllers/users.js'); +// instantiate the controller +const users = new usersController(); -router.post("/register", usersController.register); -router.post("/login", usersController.login); -router.post("/reset-password", usersController.resetPassword); -router.post("/change-password", jwt.authenticate, usersController.changePassword); -router.post("/delete-user", jwt.authenticate, usersController.delete); +router.post("/register", users.register); +router.post("/login", users.login); +router.post("/reset-password", users.resetPassword); +router.post("/change-password", jwt.authenticate, users.changePassword); +router.post("/delete-user", jwt.authenticate, users.delete); -module.exports = router; \ No newline at end of file +module.exports = router;