Skip to content

Conversation

@oberezhnay
Copy link

Auth application

Copy link

@mateacademy-ai-mentor mateacademy-ai-mentor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Summary

Hello! You've done a great job structuring the project with separate controllers, services, and models. However, I'm requesting changes to address a few critical issues that are currently preventing the application from working as required.

Here are the main points to focus on:

  • Module System Incompatibility: Several files (like jwt.service.js, mailer.js, and auth.middleware.js) use ES Module export, but they are being imported with CommonJS require(). This will cause the application to crash. Please ensure all files consistently use the CommonJS module system (module.exports).
  • Critical Runtime Errors:
    • In auth.controller.js, the login function sends a JSON response and then tries to redirect, which will cause a ERR_HTTP_HEADERS_SENT error. A request can only have one response.
    • The findUserById function in user.service.js is missing an await, causing it to return a promise instead of the user data.
  • Incorrect Logic:
    • The account activation logic in auth.controller.js incorrectly tries to nullify a non-existent accessToken field instead of the activationToken.
    • The /logout route needs to be protected by the authMiddleware to meet the requirement that only authenticated users can log out.

Once these key issues are fixed, your project will be in a much better state. You're on the right track!


✨ Please rate this review in the Platform's notification center1. I will be grateful for your feedback! ✨

Important

Fix the issues, commit the changes, and then re-request my review using the Re-request review button2 in the Reviewers tab.

Tip

If you have any comments about this review, please leave a message in the Add a comment section below and mention me with the @mateacademy-ai-mentor tag3.
I will read your message during my next review of your pull request. Please do not reply directly to my comments, as that feature is not supported yet.

Caution

Do not close the pull request until the review is complete. Closing it early can lead to unexpected behavior and disrupt the review process.

Footnotes

  1. Rate AI review example

  2. Re-request AI review example

  3. Add AI review comments example

@@ -0,0 +1,22 @@
// const { Request, Response, NextFunction } = require('express');
const { jwt } = require('./../service/jwt.service.js');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This require statement is attempting to import from jwt.service.js, which uses ES Module export syntax. This will not work as expected in a CommonJS environment. To fix this, jwt.service.js should also use module.exports.

// const { Request, Response, NextFunction } = require('express');
const { jwt } = require('./../service/jwt.service.js');

export function authMiddleware(req, res, next) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're using export, which is ES Module syntax. However, this file is being imported in src/router/user.router.js using require, which is CommonJS. This will cause an error. To align with the rest of the project, you should use module.exports instead.

@@ -0,0 +1,143 @@
'use strict';

const serviceUser = require('./../service/users.service');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The path to the user service module appears to be incorrect. Based on the file structure, it should likely be './../service/user.service.js' instead of './../service/users.service'. This will cause a MODULE_NOT_FOUND error at runtime.

if (passwordError) {
return res.status(400).json({
errors: { password: passwordError },
maeesage: 'Validation error',

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a typo in the response key. maeesage should be message to maintain consistency and ensure client applications can parse the error response correctly.

const isValid = await bcrypt.compare(oldPassword, user.password);

if (!isValid) {
return res.status(401).send('Confirmation do not match');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message "Confirmation do not match" is misleading here. This check validates the oldPassword. A more accurate message would be something like "Incorrect old password" to better inform the user.

}
};

const updateUserEmail = async (req, res) => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This asynchronous function is missing a try...catch block. Any error during the database operations or sending the email notification will crash the server. It's important to wrap the logic in a try...catch block to handle potential errors gracefully, similar to the other functions in this file.

const isValidPassword = await bcrypt.compare(password, user.password);

if (!isValidPassword) {
return res.status(401).send('Wrong passsword');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a typo in the error message. It should be Wrong password.

return res.status(404).json({ message: 'User not found' });
}

user.accessToken = null;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The User model does not have an accessToken property. To activate the user, you should nullify the activationToken. The current implementation will not correctly activate the user account.

}

sendAuthentification(res, user);
res.redirect('/profile');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to the requirements, the user should be redirected to the profile page after a successful login. However, the sendAuthentification function on the previous line already sends a JSON response. You cannot send a response and then perform a redirect in the same request, as this will cause a ERR_HTTP_HEADERS_SENT error. You should choose one method: either send data back and let the client handle the redirect, or perform the redirect from the server.

};

const refresh = (req, res) => {
const { refreshToken } = req.cookies.refreshToken;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The refreshToken is being destructured from req.cookies.refreshToken, which is the token string itself, not an object. This will result in refreshToken being undefined. It should probably be const { refreshToken } = req.cookies; or const refreshToken = req.cookies.refreshToken;.

user.password = bcrypt.hashSync(password, 10);
user.resetToken = null;

await userService.updateUserPassword(user.id, user.password);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The User model defines the primary key as userId, not id. Using user.id will pass undefined to the updateUserPassword service, and the user's password will not be updated.

'Token',
{
refreshToken: {
type: DataTypes.INTEGER,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The refreshToken is a JWT string, but its type is defined as DataTypes.INTEGER. This will cause an error when trying to save the token to the database. The type should be DataTypes.STRING or DataTypes.TEXT to accommodate the token string.

},
);

Token.belongsTo(this.User, { foreignKey: 'user_id', onDelete: 'CASCADE' });

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The use of this.User is incorrect here. Since User was imported at the top of the file, you should use the User variable directly to define the association, like so: Token.belongsTo(User, ...). Using this in this context does not refer to the module exports and will cause a runtime error.

Comment on lines 25 to 27
module.exports = {
User,
};

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This module defines the Token model, but it only exports the User model which was imported. To make the Token model available to other parts of your application, you should export it. For example: module.exports = { Token };.


const router = express.Router();

router.post('/auth', authController.register);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The route path /auth for user registration is a bit ambiguous. It's a common convention to use a more descriptive path like /register to make the API's intent clearer.

router.get('/activate/:activationToken', authController.activate);
router.post('/login', authController.loginUser);
router.get('/refresh', authController.refresh);
router.get('/logout', authController.logout);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The task requirements state that logout should only be for authenticated users. This route is currently public. You should add the authMiddleware here to ensure only logged-in users can access it.

@@ -0,0 +1,12 @@
const express = require('express');
const userController = require('./../controller/user.controller.js');
const authMiddleware = require('./../middlewares/auth.middleware.js');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are using require to import the authMiddleware, but the auth.middleware.js file uses ES Module export syntax. This will not work correctly, and authMiddleware will not be the expected middleware function, causing a runtime error. To ensure compatibility, the middleware should be exported using module.exports.


const router = express.Router();

router.get('/', authMiddleware, userController.getAllUsers);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The requirements for the 'Profile page' specify that an authenticated user can manage their own data. This route, however, fetches all users, which is typically an admin-level function. It would be more appropriate to have an endpoint like /profile or /me that fetches only the authenticated user's data.

Comment on lines 30 to 35
export const jwt = {
generateAccessToken,
generateRefreshToken,
validateAccessToken,
validateRefreshToken,
};

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file uses the ES Module export syntax. However, other files in the project, such as auth.controller.js and auth.middleware.js, use the CommonJS require() function to import it. This will lead to an ERR_REQUIRE_ESM error at runtime. To fix this, you should use the CommonJS export syntax, for example: module.exports = { jwt };.

};

const findUserById = async (userId) => {
const user = User.findOne({

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The User.findOne method is asynchronous and returns a promise. You are missing the await keyword here. As a result, this function will return a pending promise instead of the user object, which will cause issues in any controller that calls this method.

Comment on lines 54 to 59
export const mailer = {
send,
sendActivationLink,
sendResetPasswordNotification,
sendChangeEmailNotification,
};

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file uses ES Module export syntax, but it is being imported into the controllers using CommonJS require. This will cause a runtime error because the two module systems are not compatible in this setup. To fix this, you should convert this file to use the CommonJS module system by replacing the export statements with module.exports.

Copy link

@mateacademy-ai-mentor mateacademy-ai-mentor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Summary

Excellent progress on the project! You've successfully fixed several important issues from the previous review. I am requesting a few more changes, as there are still some critical bugs that cause the application to crash at runtime or fail key requirements.

Please address the following blockers:

  • Module System Inconsistency: In src/util/mailer.js, you're still using ES Module export statements. Since the project uses CommonJS, this will cause a SyntaxError. Please remove the export keywords.
  • Multiple Responses on Login: The loginUser function in src/controller/auth.controller.js sends two responses, which will crash the server. Please remove the res.redirect() call and only send the JSON response.
  • Incorrect Middleware Import: In src/router/auth.router.js, the middleware is imported incorrectly. You need to destructure the import to get the function: const { authMiddleware } = require(...).
  • Service Import Typo: In src/controller/user.controller.js, the path to the user service is misspelled as users.service.js. It should be user.service.js.
  • Missing Activation Redirect: The requirement to redirect after account activation is not met because the relevant line in src/controller/auth.controller.js is commented out.

Once these issues are resolved, the application should be fully functional. You're very close!


✨ Please rate this review in the Platform's notification center1. I will be grateful for your feedback! ✨

Important

Fix the issues, commit the changes, and then re-request my review using the Re-request review button2 in the Reviewers tab.

Tip

If you have any comments about this review, please leave a message in the Add a comment section below and mention me with the @mateacademy-ai-mentor tag3.
I will read your message during my next review of your pull request. Please do not reply directly to my comments, as that feature is not supported yet.

Caution

Do not close the pull request until the review is complete. Closing it early can lead to unexpected behavior and disrupt the review process.

Footnotes

  1. Rate AI review example

  2. Re-request AI review example

  3. Add AI review comments example

@@ -0,0 +1,147 @@
'use strict';

const serviceUser = require('./../service/users.service.js');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The filename for the user service is user.service.js, but it's being imported here as users.service.js (plural). This typo will cause a MODULE_NOT_FOUND error when the application tries to run this code.

});
}

const activationToken = bcrypt.genSaltSync(10);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using bcrypt.genSaltSync to generate an activation token is not its intended purpose. This function is designed to create salts for password hashing. For generating unique tokens, a library like uuid (which you're already using for password resets) or Node's built-in crypto module would be a more appropriate and secure choice.

user.activationToken = null;
await user.save();

// res.redirect('/profile');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The requirement is to redirect the user to their profile page after successful activation. This line is currently commented out. For the redirect to work as expected, the user should also be authenticated. Consider calling the sendAuthentification function here before redirecting.

Comment on lines +104 to +105
sendAuthentification(res, user);
res.redirect('/profile');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function still attempts to send two responses to a single request: one from sendAuthentification (which calls res.send) and another from res.redirect. This will cause an ERR_HTTP_HEADERS_SENT error and crash the application, as pointed out in the previous review.

For an API serving a front-end application, you should typically send the JSON response with tokens and let the client handle the redirection. In that case, res.redirect('/profile') should be removed.

user.password = bcrypt.hashSync(password, 10);
user.resetToken = null;

await userService.updateUserPassword(user.userId, user.password);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After modifying the user instance on the lines above, you can simply call await user.save() to persist the changes. Calling userService.updateUserPassword here is redundant as it performs a separate database query to update a field that has already been changed in memory.

@@ -0,0 +1,15 @@
const express = require('express');
const authController = require('./../controller/auth.controller.js');
const authMiddleware = require('./../middlewares/auth.middleware.js');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The auth.middleware.js file exports an object: module.exports = { authMiddleware }. This import assigns that entire object to the authMiddleware constant. When used in router.get on line 11, it passes an object instead of a function, which will cause an error.

You should use destructuring to extract the function correctly, like this:

const { authMiddleware } = require('./../middlewares/auth.middleware.js');

},
});

export function send(email, subject, html) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The export keyword is part of the ES Module system. Since the rest of your project uses CommonJS (require/module.exports), this will cause a syntax error. Please remove export from this function declaration.

});
}

export function sendActivationLink(email, activationToken) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to the send function above, using export here is incorrect for a CommonJS module. This function is already correctly included in the module.exports object at the end of the file, so the export keyword should be removed.

Copy link

@mateacademy-ai-mentor mateacademy-ai-mentor left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review Summary

I am approving this submission as an educational override to help you progress, but there are a few critical issues in the authentication flow that need your attention. You've done an excellent job structuring your services, models, and middleware! The main problem lies in src/controller/auth.controller.js, where the loginUser, activate, and refresh functions don't send the accessToken back to the client, which is essential for accessing protected routes. The activate function also needs to redirect to the profile page as required, not the login page. Additionally, there's a small but critical import error in src/router/user.router.js; you need to destructure the middleware import: const { authMiddleware } = require(...). You are very close to a complete solution, keep up the great work!


✨ Please rate this review in the Platform's notification center1. I will be grateful for your feedback! ✨

Footnotes

  1. Rate AI review example

user.activationToken = null;
await user.save();

res.redirect('/login?activated=true');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The task description requires redirecting to the Profile page after activation. Currently, the user is redirected to the login page. To meet the requirement, you could consider logging the user in automatically upon successful activation and then performing the redirect to their profile.

Comment on lines +103 to +104
sendAuthentification(res, user);
res.redirect('/profile');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This implementation doesn't send the accessToken to the client. The sendAuthentification function returns it, but it's ignored. Without the access token, the client cannot make authenticated API calls. As mentioned in the previous review, you should remove the res.redirect() and instead send a JSON response containing the accessToken. The client-side application will then be responsible for redirecting the user to the profile page.

Comment on lines +107 to +115
const refresh = (req, res) => {
const refreshToken = req.cookies.refreshToken;

if (!jwt.validateRefreshToken(refreshToken)) {
return res.status(401);
}

sendAuthentification(res, jwt.validateRefreshToken(refreshToken));
};

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This refresh endpoint is not fully implemented and will cause client requests to hang.

  1. On line 111, res.status(401) only sets the HTTP status code but does not send a response or terminate the request. You should use res.sendStatus(401) or res.status(401).send().
  2. The call to sendAuthentification on line 114 returns a new accessToken, but you are not sending it back to the client. This function needs to send a JSON response with the new token to be useful.

@@ -0,0 +1,12 @@
const express = require('express');
const userController = require('./../controller/user.controller.js');
const authMiddleware = require('./../middlewares/auth.middleware.js');

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The authMiddleware is being imported incorrectly. The middleware file exports an object { authMiddleware }, so you are currently passing an object to your routes instead of the middleware function. You need to destructure the import to get the function itself, like this: const { authMiddleware } = require('./../middlewares/auth.middleware.js');.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants