Skip to content

add solution#508

Open
GabrielSpelchuk wants to merge 2 commits intomate-academy:masterfrom
GabrielSpelchuk:develop
Open

add solution#508
GabrielSpelchuk wants to merge 2 commits intomate-academy:masterfrom
GabrielSpelchuk:develop

Conversation

@GabrielSpelchuk
Copy link
Copy Markdown

No description provided.

Copy link
Copy Markdown

@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

This submission requires changes because the main requirement of the task, which is to implement CRUD functionality for categories, is missing. While the existing code for users and expenses provides a good foundation, the new feature has not been added.

To complete the task, you need to create the necessary components for managing categories:

  • A Category model (src/models/Category.model.js)
  • A service for business logic (src/services/categories.service.js)
  • A router and controller for handling API requests (src/routers/categories.router.js, src/controllers/categories.controller.js)
  • Finally, you must register the new route in src/createServer.js.

Once these parts are implemented, the project will meet the requirements.


✨ 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

Comment on lines +1 to +23
const express = require('express');

const {
getAllExpenses,
getExpenseById,
deleteExpense,
createExpense,
updateExpense,
} = require('../routers/expenses.router.js');

const expensesRoute = express.Router();

expensesRoute.get('/', getAllExpenses);

expensesRoute.get('/:id', getExpenseById);

expensesRoute.post('/', createExpense);

expensesRoute.delete('/:id', deleteExpense);

expensesRoute.patch('/:id', updateExpense);

module.exports = { expensesRoute };
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The core task is to implement CRUD functionality for categories. This file handles expenses, but the new functionality for categories seems to be missing entirely from the project. You'll need to add a new set of files (Category.model.js, categories.service.js, categories.router.js, categories.controller.js) and register the new route in createServer.js.

Comment thread src/createServer.js
const cors = require('cors');

const { expensesRoute } = require('./controllers/expenses.controller.js');
const { usersRoute } = require('./controllers/users.controller.js');
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

It seems you've missed importing the router for categories. To manage categories, you'll need a dedicated controller and router, similar to what you have for expenses and users.

Comment thread src/createServer.js
app.use(express.json());

app.use('/expenses', expensesRoute);
app.use('/users', usersRoute);
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The server is missing the endpoint for categories. You should mount the categories route here using app.use('/categories', categoriesRoute); after you've created and imported it.

Comment on lines +1 to +134
const {
getAll,
getById,
create,
update,
remove,
} = require('../services/expenses.service.js');

const { getById: getByUserId } = require('../services/users.service.js');

const getAllExpenses = async (req, res) => {
const { userId, from, to, categories } = req.query;

const expenses = await getAll({
userId: userId ? Number(userId) : undefined,
from,
to,
categories,
});

res.send(expenses);
};

const getExpenseById = async (req, res) => {
const { id } = req.params;

const expense = await getById(id);

if (!expense) {
res.status(404).send({ message: 'Not found' });

return;
}

res.send(expense);
};

const createExpense = async (req, res) => {
const { userId, spentAt, title, amount, category, note } = req.body;

if (userId == null || spentAt == null || title == null || amount == null) {
res.status(400).send({ message: 'Missing required field' });

return;
}

const user = await getByUserId(userId);

if (!user) {
return res.status(400).send({ message: 'User not found' });
}

if (typeof amount !== 'number' || Number.isNaN(new Date(spentAt).getTime())) {
return res.status(400).send({ message: 'Invalid field' });
}

const expense = await create({
userId,
spentAt,
title,
amount,
category,
note,
});

res.status(201).send(expense);
};

const deleteExpense = async (req, res) => {
const { id } = req.params;

const expense = await remove(id);

if (!expense) {
res.status(404).send({ message: 'Not found' });

return;
}

res.status(204).send();
};

const updateExpense = async (req, res) => {
const { id } = req.params;
const { amount, spentAt } = req.body;

const existingExpense = await getById(id);

if (!existingExpense) {
res.status(404).send({ message: 'Not found' });

return;
}

if (amount !== undefined && typeof amount !== 'number') {
res.status(400).send({ message: 'Invalid field' });

return;
}

if (spentAt !== undefined) {
const date = new Date(spentAt);

if (Number.isNaN(date.getTime())) {
res.status(400).send({ message: 'Invalid field' });

return;
}
}

const updatedData = {
...existingExpense,
...req.body,
id,
};

const expense = await update(updatedData);

if (!expense) {
res.status(404).send({ message: 'Not found' });

return;
}

res.status(200).send(expense);
};

module.exports = {
getAllExpenses,
getExpenseById,
deleteExpense,
createExpense,
updateExpense,
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The core requirement for this task is to implement CRUD functionality for categories. While this file correctly handles expenses, the required functionality for categories is completely missing from the project. You need to create a new set of files for categories (model, service, router, controller) and wire them up in createServer.js.

Copy link
Copy Markdown

@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 work on implementing the full CRUD functionality for categories! Your solution meets all the requirements, and the new feature is well-structured with a model, service, and router. I'm approving your submission.

I have a couple of suggestions to improve your code even further:

  1. Validation Order: In src/routers/categories.router.js and src/routers/users.router.js, consider checking for missing fields (e.g., name === undefined) before checking their type. This will provide more accurate error messages to the user, such as 'Missing required field' instead of 'Invalid field'.

  2. File Naming: As a convention in Express.js, files that define routes are often named *.router.js, while the files containing the request handler logic are named *.controller.js. Swapping the content of your categories.controller.js and categories.router.js would align your project with this common pattern.

These are just best practices to keep in mind for future projects. Great job completing the task!


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

Footnotes

  1. Rate AI review example

Comment on lines +3 to +9
const {
getAllCategories,
getCategoryById,
deleteCategory,
createCategory,
updateCategory,
} = require('../routers/categories.router.js');
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Great job separating concerns! Just a note on naming conventions: typically, this file, which defines the routes, would be named categories.router.js. The file containing the request handler logic (like getAllCategories) would be the controller. You currently have this logic in ../routers/categories.router.js. Swapping the file names or their contents would align your project better with common Express.js patterns and make it more intuitive for other developers.

}

const updatedData = {
...existingExpense,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

existingExpense here is a Sequelize model instance, not a plain JavaScript object. Spreading it includes many internal properties and methods from Sequelize, which is not ideal. It's better to convert it to a plain object first using existingExpense.toJSON() if you need to merge it with other data. A cleaner approach would be to only pass the data that needs to be updated to the update service.

Comment on lines +34 to +44
if (typeof name !== 'string') {
res.status(400).send({ message: 'Invalid field' });

return;
}

if (name === undefined) {
res.status(400).send({ message: 'Missing required field' });

return;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The order of your validation checks could be improved. When the name field is missing from the request (undefined), the first check typeof name !== 'string' evaluates to true, and the response is 'Invalid field'. A more accurate response would be 'Missing required field'. Consider swapping this block with the one below to check for presence (name === undefined) before checking the type. This same logic applies to the updateUser function as well.

Comment on lines +34 to +38
if (typeof name !== 'string') {
res.status(400).send({ message: 'Invalid field' });

return;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The order of validation checks here can lead to a less specific error message. If name is missing (undefined), the typeof name !== 'string' check will trigger first, sending 'Invalid field'. It's better to check for missing fields before checking their types. Consider swapping this if block with the one below.

Comment on lines +73 to +77
if (typeof name !== 'string') {
res.status(400).send({ message: 'Invalid field' });

return;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Similar to the createCategory function, the validation order here should be reversed. Checking for name === undefined before checking its type will ensure a more accurate error message is returned when the field is missing.

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