Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions src/controllers/expenses.controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,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 };
Comment on lines +1 to +23
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.

23 changes: 23 additions & 0 deletions src/controllers/users.controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const express = require('express');

const {
getAllUsers,
getUsersById,
deleteUser,
createUser,
updateUser,
} = require('../routers/users.router.js');

const usersRoute = express.Router();

usersRoute.get('/', getAllUsers);

usersRoute.get('/:id', getUsersById);

usersRoute.post('/', createUser);

usersRoute.delete('/:id', deleteUser);

usersRoute.patch('/:id', updateUser);

module.exports = { usersRoute };
21 changes: 18 additions & 3 deletions src/createServer.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,23 @@
'use strict';

const createServer = () => {
// your code goes here
};
const express = require('express');
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.


function createServer() {
const app = express();

app.use(cors());

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.


return app;
}

module.exports = {
createServer,
Expand Down
2 changes: 1 addition & 1 deletion src/db.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const sequelize = new Sequelize({
host: POSTGRES_HOST || 'localhost',
dialect: 'postgres',
port: POSTGRES_PORT || 5432,
password: POSTGRES_PASSWORD || '123',
password: POSTGRES_PASSWORD || '12345',
});

module.exports = {
Expand Down
37 changes: 36 additions & 1 deletion src/models/Expense.model.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,44 @@
'use strict';

const { DataTypes } = require('sequelize');
const { sequelize } = require('../db.js');

const Expense = sequelize.define(
// your code goes here
'Expense',
{
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
userId: {
type: DataTypes.INTEGER,
allowNull: false,
},
spentAt: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW,
},
title: {
type: DataTypes.STRING,
allowNull: false,
},
amount: {
type: DataTypes.INTEGER,
allowNull: false,
},
category: {
type: DataTypes.STRING,
},
note: {
type: DataTypes.STRING,
},
},
{
tableName: 'expenses',
timestamps: false,
},
);

module.exports = {
Expand Down
18 changes: 17 additions & 1 deletion src/models/User.model.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,25 @@
'use strict';

const { DataTypes } = require('sequelize');
const { sequelize } = require('../db.js');

const User = sequelize.define(
// your code goes here
'User',
{
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true,
},
name: {
type: DataTypes.STRING,
allowNull: false,
},
},
{
tableName: 'users',
timestamps: false,
},
);

module.exports = {
Expand Down
134 changes: 134 additions & 0 deletions src/routers/expenses.router.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,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,
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.

...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,
};
Comment on lines +1 to +134
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.

106 changes: 106 additions & 0 deletions src/routers/users.router.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
const express = require('express');
const {
getAll,
getById,
create,
update,
remove,
} = require('../services/users.service.js');

const usersRoute = express.Router();

const getAllUsers = async (req, res) => {
const users = await getAll();

res.send(users);
};

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

const idNum = Number(id);

const user = await getById(idNum);

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

return;
}

res.send(user);
};

const createUser = async (req, res) => {
const { name } = req.body;

if (typeof name !== 'string') {
res.status(400).send({ message: 'Invalid field' });

return;
}

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

return;
}
Comment on lines +34 to +44
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.


const user = await create({ name });

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

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

const idNum = Number(id);

const user = await remove(idNum);

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

return;
}

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

const updateUser = async (req, res) => {
const { id } = req.params;
const { name } = req.body;

const idNum = Number(id);

if (typeof name !== 'string') {
res.status(400).send({ message: 'Invalid field' });

return;
}

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

return;
}

const user = await update({ id: idNum, name });

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

return;
}

res.send(user);
};

module.exports = {
usersRoute,
getAllUsers,
getUsersById,
createUser,
deleteUser,
updateUser,
};
Loading
Loading