Conversation
mateacademy-ai-mentor
left a comment
There was a problem hiding this comment.
Review Summary
Great job on setting up the project structure and implementing the main authentication flows! Your use of middleware for route protection is well done. However, there are a few critical issues that need to be addressed before this can be approved.
Here are the main points to focus on:
- Crashing on Errors: In
auth.controller.jsanduser.controller.js, several functions send an error response but don't stop execution. You need to add areturnstatement after sending a response (e.g.,res.status(404).send(...)) to prevent the code from continuing and trying to access properties onnullobjects, which causes the server to crash. - Missing 404 Page: The task requires a 404 handler for any undefined routes. Please add a catch-all middleware in
src/index.jsafter all your other routes are defined. - Password Confirmation Logic: In the
changePasswordfunction inuser.controller.js, you're checking if theconfirmfield exists, but the requirement is to verify thatnewPasswordis identical toconfirm. - Incorrect Email Change Flow: When a user changes their email, the activation link for the new address is incorrectly sent to the old address. The requirement is to send a simple notification to the old address and the activation link to the new one.
Please fix these issues, and I'll be happy to review your work again!
✨ 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
src/controllers/user.controller.js
Outdated
| const { password, newPassword, confirm } = req.body; | ||
|
|
||
| if (!confirm) { |
There was a problem hiding this comment.
The task requires a confirmation field for the new password. The logic should verify that newPassword and confirm are identical. Currently, you are only checking if confirm is truthy, which doesn't meet the requirement.
src/controllers/user.controller.js
Outdated
| const isValid = await bcrypt.compare(password, user.password); | ||
|
|
||
| if (!isValid) { | ||
| res.status(401).send('Invalid credentials'); |
There was a problem hiding this comment.
After sending a response for an invalid old password, you must add a return statement. Without it, the function will continue to execute and will change the password even if the old one was incorrect.
src/controllers/user.controller.js
Outdated
| user.password = await bcrypt.hash(password, 10); | ||
| user.resetToken = null; | ||
| user.save(); | ||
| res.send('password changed'); |
There was a problem hiding this comment.
The task requires showing a success page with a link to login. Simply sending the text 'password changed' is not sufficient. Consider redirecting to a success page or returning a more structured response that the client-side can use to render the correct view.
| res.send('passwords not equil'); | ||
| } | ||
|
|
||
| const user = await User.findOne({ where: { resetToken } }); |
There was a problem hiding this comment.
You should check if a user was found with the provided resetToken. If user is null (because the token is invalid), the subsequent code will throw an error when trying to access user.password. Add a check for user and return an error response if it's not found.
src/controllers/user.controller.js
Outdated
| const isValid = await bcrypt.compare(password, user.password); | ||
|
|
||
| if (!isValid) { | ||
| res.status(401).send('Invalid credentials'); |
There was a problem hiding this comment.
You're missing return statements after sending error responses on lines 38, 46, 88, and 108. Without them, the function continues execution even after an error has been sent, leading to unexpected behavior. For example, here, an invalid password would still allow the email change process to continue.
src/controllers/auth.controller.js
Outdated
| if (!existUser) { | ||
| res.send('User not found'); |
There was a problem hiding this comment.
If the user does not exist, you send a response but do not stop the function's execution. The code will then attempt to access existUser.password on line 74, which will cause a TypeError because existUser is null. You need to add a return statement here.
src/controllers/auth.controller.js
Outdated
| if (!isValid) { | ||
| res.send('Invalid credentials'); |
There was a problem hiding this comment.
Similarly, if the password is not valid, you should return after sending the response. While it might not crash immediately in this case, continuing execution after sending a response is incorrect and can lead to unexpected behavior, such as trying to set headers after they have already been sent.
| app.use(cookieParser()); | ||
| app.use(express.json()); // allow json in body | ||
| app.use(authRouter); | ||
| app.use(userRouter); |
There was a problem hiding this comment.
The task requires you to return a 404 error for any pages that are not defined by your routers. You should add a catch-all middleware here, after all other routes, to handle requests to non-existent pages.
src/routes/auth.routes.js
Outdated
| /* eslint-disable no-unused-vars */ | ||
| const express = require('express'); | ||
| const router = express.Router(); | ||
| const User = require('../models/user.model'); |
There was a problem hiding this comment.
The User model is imported but never used in this file. It's good practice to remove any unused imports to keep the code clean.
src/routes/auth.routes.js
Outdated
|
|
||
| const { authController } = require('../controllers/auth.controller'); | ||
| const { | ||
| authMiddleware, |
There was a problem hiding this comment.
The authMiddleware is imported here but it's not used on any of the routes in this file. This import can be safely removed.
mateacademy-ai-mentor
left a comment
There was a problem hiding this comment.
Review Summary
Excellent progress on this PR! You've fixed all the critical server-crashing bugs from the last review, which is a huge step forward.
I'm requesting a few changes, primarily to align the password reset flow with the task requirements before this can be approved.
Required Changes:
- Password Reset Flow: In
src/controllers/user.controller.js, theresetPasswordConfirmfunction needs two adjustments to meet the requirements:- It should show a success page with a link to the login page, but it currently redirects the user directly to
/login. - The code expects a
repeatPasswordfield, but the requirement specifies it should be namedconfirmation.
- It should show a success page with a link to the login page, but it currently redirects the user directly to
Minor Suggestions:
- HTTP Status Codes: For better API design, consider sending specific error status codes. For example, in
src/controllers/auth.controller.js, useres.status(404).send('User not found')instead of sending a plain message with the default200 OKstatus. - Database Sync: A quick note on
sequelize.sync({ force: true })insrc/index.js— be very careful with this, as it drops all tables on every server restart. It's fine for early development but should be removed for production.
You're very close to finishing this. Just address the password reset flow, and it will be ready to go!
✨ 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
src/controllers/auth.controller.js
Outdated
| 'Activate email', | ||
| `go to link http://localhost:3000/activation/${uuid}`, | ||
| ); | ||
| res.send(201); |
There was a problem hiding this comment.
While res.send(201) works, it's more idiomatic in Express to be explicit with your status codes. Consider using res.sendStatus(201) or res.status(201).send('User created'). This makes the code's intent clearer.
src/controllers/auth.controller.js
Outdated
| const user = await User.findOne({ where: { activationToken } }); | ||
|
|
||
| if (!user) { | ||
| return res.status(404).send('invalind activation token'); |
There was a problem hiding this comment.
There's a small typo here. It should be "invalid".
src/controllers/auth.controller.js
Outdated
| const existUser = await User.findOne({ where: { email } }); | ||
|
|
||
| if (!existUser) { | ||
| return res.send('User not found'); |
There was a problem hiding this comment.
Sending a response without a status code defaults to 200 OK. For an error case like a user not being found, it's better to send an appropriate HTTP status code, such as 404 Not Found. This helps client-side applications correctly interpret the response.
Example: return res.status(404).send('User not found');
src/controllers/auth.controller.js
Outdated
| const isValid = await bcrypt.compare(password, existUser.password); | ||
|
|
||
| if (!isValid) { | ||
| return res.send('Invalid credentials'); |
There was a problem hiding this comment.
Similar to the point above, for invalid credentials, the standard HTTP status code is 401 Unauthorized. Using the correct status code improves API consistency and makes it easier for clients to handle different types of errors.
Example: return res.status(401).send('Invalid credentials');
src/controllers/user.controller.js
Outdated
| user.resetToken = null; | ||
| await user.save(); | ||
|
|
||
| return res.redirect('/login'); |
There was a problem hiding this comment.
The implementation for the password reset confirmation is solid. However, the requirement is to "Show Success page with a link to login". Currently, the user is redirected directly to the login page. Consider sending a success message instead, which the frontend can then display to the user along with a link to the login page.
src/index.js
Outdated
| await sequelize.authenticate(); // connect to database | ||
| console.log('database connected'); | ||
|
|
||
| await sequelize.sync({ force: true }); // create tables |
There was a problem hiding this comment.
Using { force: true } is useful for development as it resets the database on every server start. However, be very careful with this in a production environment, as it will drop all your tables and delete all data. For production apps, it's safer to use database migration tools to manage schema changes.
src/middlewares/auth.middleware.js
Outdated
| const token = req.cookies.token; | ||
|
|
||
| if (!token) { | ||
| return res.status(401).send('unautorised'); |
There was a problem hiding this comment.
There's a small typo here. It should be "unauthorized".
src/routes/user.routes.js
Outdated
| /* eslint-disable no-unused-vars */ | ||
| const express = require('express'); | ||
| const router = express.Router(); | ||
| const User = require('../models/user.model'); |
There was a problem hiding this comment.
This User model is imported but never used within this file. It's a good practice to remove unused imports to keep the code clean.
mateacademy-ai-mentor
left a comment
There was a problem hiding this comment.
Review Summary
I am approving your solution as an educational override so you can keep making progress. You've done a fantastic job on the overall structure and successfully fixed the password reset flow from the last review!
There are just a couple of things to address:
- In
src/controllers/user.controller.js, the task specifies that the password confirmation field should be namedconfirmation. Your code currently usesconfirmfor changing the password andrepeatPasswordfor resetting it. A quick update to these variable names will align it with the requirements. - In
src/controllers/auth.controller.js, the user isn't logged in after activating their account. To create a smoother experience, you should issue a JWT and set the cookie right after activation, just like you do in theloginfunction, before redirecting to the profile page.
These are minor but important fixes. Keep up the excellent work!
✨ Please rate this review in the Platform's notification center1. I will be grateful for your feedback! ✨
Footnotes
|
|
||
| const changePassword = async (req, res) => { | ||
| const userId = req.user.id; | ||
| const { password, newPassword, confirm } = req.body; |
There was a problem hiding this comment.
According to the task requirements, this function should expect fields named newPassword and confirmation for changing the password. The current code is using confirm.
|
|
||
| const resetPasswordConfirm = async (req, res) => { | ||
| const { resetToken } = req.params; | ||
| const { password, repeatPassword } = req.body; |
There was a problem hiding this comment.
The task requirements specify that the password reset confirmation should expect password and confirmation fields. This implementation is using repeatPassword instead.
| user.isActivated = true; | ||
| user.activationToken = null; | ||
| await user.save(); | ||
| res.redirect('http://localhost:3000/profile'); |
There was a problem hiding this comment.
The task requires redirecting to the profile page after activation, which you've done. However, the profile page is protected and requires the user to be authenticated. Currently, after activation, the user isn't logged in, so they'll be blocked from accessing the profile.
To fix this, you should log the user in by creating a JWT and setting it as a cookie, just like you do in the login function, before redirecting them to their profile.
No description provided.