From e3b4c86725104c1d5bcd4d3df4db0f69b441b9e0 Mon Sep 17 00:00:00 2001 From: Lesia Date: Tue, 21 May 2024 21:42:04 +0300 Subject: [PATCH 1/2] add solution --- src/controllers/expenses.controller.js | 91 ++++++++++++++++++++++++++ src/controllers/users.controller.js | 82 +++++++++++++++++++++++ src/createServer.js | 18 ++++- src/db.js | 2 +- src/models/Expense.model.js | 39 ++++++++++- src/models/User.model.js | 19 +++++- src/routes/expenses.route.js | 12 ++++ src/routes/users.route.js | 12 ++++ src/services/expenses.service.js | 48 ++++++++++++++ src/services/users.service.js | 33 ++++++++++ src/utils/getFilteredExpenses.js | 35 ++++++++++ src/utils/getNextAvailableId.js | 12 ++++ src/variables/httpStatusCodes.js | 9 +++ 13 files changed, 406 insertions(+), 6 deletions(-) create mode 100644 src/controllers/expenses.controller.js create mode 100644 src/controllers/users.controller.js create mode 100644 src/routes/expenses.route.js create mode 100644 src/routes/users.route.js create mode 100644 src/services/expenses.service.js create mode 100644 src/services/users.service.js create mode 100644 src/utils/getFilteredExpenses.js create mode 100644 src/utils/getNextAvailableId.js create mode 100644 src/variables/httpStatusCodes.js diff --git a/src/controllers/expenses.controller.js b/src/controllers/expenses.controller.js new file mode 100644 index 00000000..4224f474 --- /dev/null +++ b/src/controllers/expenses.controller.js @@ -0,0 +1,91 @@ +// const { User } = require('../models/User.model'); +const expensesService = require('../services/expenses.service'); +const { getById } = require('../services/users.service'); +const HTTP_STATUS_CODES = require('../variables/httpStatusCodes'); + +const getAll = async (req, res) => { + const { query } = req; + + const expenses = await expensesService.getAll(query); + + res.send(expenses); +}; + +const getOne = async (req, res) => { + const { id } = req.params; + + const expense = await expensesService.getById(id); + + if (!expense) { + res.sendStatus(HTTP_STATUS_CODES.NOT_FOUND); + + return; + } + + res.statusCode = HTTP_STATUS_CODES.OK; + res.send(expense); +}; + +const create = async (req, res) => { + const { userId, spentAt, title, amount, category, note } = req.body; + const user = await getById(userId); + + if (!user || !spentAt || !title || !amount) { + res.sendStatus(HTTP_STATUS_CODES.BAD_REQUEST); + + return; + } + + const expense = await expensesService.create({ + userId, + spentAt, + title, + amount, + category, + note, + }); + + res.statusCode = HTTP_STATUS_CODES.CREATED; + res.send(expense); +}; + +const update = async (req, res) => { + const { id } = req.params; + const body = req.body; + + const expense = await expensesService.getById(id); + + if (!expense) { + res.sendStatus(HTTP_STATUS_CODES.NOT_FOUND); + + return; + } + + const updatedExpense = await expensesService.update(id, body); + + res.statusCode = HTTP_STATUS_CODES.OK; + + res.send(updatedExpense); +}; + +const remove = async (req, res) => { + const { id } = req.params; + const expense = await expensesService.getById(id); + + if (!expense) { + res.sendStatus(HTTP_STATUS_CODES.NOT_FOUND); + + return; + } + + await expensesService.remove(id); + res.sendStatus(HTTP_STATUS_CODES.NO_CONTENT); +}; + +module.exports = { + getAll, + getOne, + create, + remove, + update, +}; diff --git a/src/controllers/users.controller.js b/src/controllers/users.controller.js new file mode 100644 index 00000000..03fdef34 --- /dev/null +++ b/src/controllers/users.controller.js @@ -0,0 +1,82 @@ +const usersService = require('../services/users.service'); +const HTTP_STATUS_CODES = require('../variables/httpStatusCodes'); + +const getAll = async (req, res) => { + res.send(await usersService.getAll()); +}; + +const getOne = async (req, res) => { + const { id } = req.params; + + const user = await usersService.getById(id); + + if (!user) { + res.sendStatus(HTTP_STATUS_CODES.NOT_FOUND); + + return; + } + + res.send(user); +}; + +const create = async (req, res) => { + const { name } = req.body; + + if (!name) { + res.sendStatus(HTTP_STATUS_CODES.BAD_REQUEST); + + return; + } + + const user = await usersService.create(name); + + res.statusCode = HTTP_STATUS_CODES.CREATED; + res.send(user); +}; + +const update = async (req, res) => { + const { id } = req.params; + const { name } = req.body; + + const user = await usersService.getById(id); + + if (!user) { + res.sendStatus(HTTP_STATUS_CODES.NOT_FOUND); + + return; + } + + if (typeof name !== 'string') { + res.sendStatus(HTTP_STATUS_CODES.BAD_REQUEST); + + return; + } + + const updatedUser = await usersService.update(id, name); + + res.statusCode = HTTP_STATUS_CODES.OK; + + res.send(updatedUser); +}; + +const remove = async (req, res) => { + const { id } = req.params; + const user = await usersService.getById(id); + + if (!user) { + res.sendStatus(HTTP_STATUS_CODES.NOT_FOUND); + + return; + } + + await usersService.remove(id); + res.sendStatus(HTTP_STATUS_CODES.NO_CONTENT); +}; + +module.exports = { + getAll, + getOne, + create, + remove, + update, +}; diff --git a/src/createServer.js b/src/createServer.js index 1ea5542d..ce9fd5f2 100644 --- a/src/createServer.js +++ b/src/createServer.js @@ -1,8 +1,20 @@ 'use strict'; -const createServer = () => { - // your code goes here -}; +const express = require('express'); +const cors = require('cors'); +const { router: usersRouter } = require('./routes/users.route'); +const { router: expensesRouter } = require('./routes/expenses.route'); + +function createServer() { + const app = express(); + + app.use(cors()); + + app.use('/users', express.json(), usersRouter); + app.use('/expenses', express.json(), expensesRouter); + + return app; +} module.exports = { createServer, diff --git a/src/db.js b/src/db.js index 1ba3046c..85d21814 100644 --- a/src/db.js +++ b/src/db.js @@ -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 || '56789', }); module.exports = { diff --git a/src/models/Expense.model.js b/src/models/Expense.model.js index 567e1c3e..c84f7566 100644 --- a/src/models/Expense.model.js +++ b/src/models/Expense.model.js @@ -1,9 +1,46 @@ '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', + updatedAt: false, + createdAt: false, + }, ); module.exports = { diff --git a/src/models/User.model.js b/src/models/User.model.js index 61861c9e..fb6b83dc 100644 --- a/src/models/User.model.js +++ b/src/models/User.model.js @@ -1,9 +1,26 @@ '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', + updatedAt: false, + createdAt: false, + }, ); module.exports = { diff --git a/src/routes/expenses.route.js b/src/routes/expenses.route.js new file mode 100644 index 00000000..e138bb0e --- /dev/null +++ b/src/routes/expenses.route.js @@ -0,0 +1,12 @@ +const express = require('express'); +const expensesController = require('../controllers/expenses.controller'); + +const router = express.Router(); + +router.get('/', expensesController.getAll); +router.get('/:id', expensesController.getOne); +router.post('/', expensesController.create); +router.delete('/:id', expensesController.remove); +router.patch('/:id', expensesController.update); + +module.exports = { router }; diff --git a/src/routes/users.route.js b/src/routes/users.route.js new file mode 100644 index 00000000..17333098 --- /dev/null +++ b/src/routes/users.route.js @@ -0,0 +1,12 @@ +const express = require('express'); +const usersController = require('../controllers/users.controller'); + +const router = express.Router(); + +router.get('/', usersController.getAll); +router.get('/:id', usersController.getOne); +router.post('/', usersController.create); +router.delete('/:id', usersController.remove); +router.patch('/:id', usersController.update); + +module.exports = { router }; diff --git a/src/services/expenses.service.js b/src/services/expenses.service.js new file mode 100644 index 00000000..40eaa47b --- /dev/null +++ b/src/services/expenses.service.js @@ -0,0 +1,48 @@ +const getFilteredExpenses = require('../utils/getFilteredExpenses'); +const { Expense } = require('../models/Expense.model'); + +const getAll = async (query) => { + const filterParam = getFilteredExpenses(query); + + return Expense.findAll({ where: filterParam }); +}; + +const getById = async (id) => { + return Expense.findByPk(id); +}; + +const create = async ({ + userId, + spentAt, + title, + amount, + category = '', + note = '', +}) => { + return Expense.create({ + userId, + spentAt, + title, + amount, + category, + note, + }); +}; + +const update = async (id, body) => { + await Expense.update({ ...body }, { where: { id } }); + + return Expense.findByPk(id); +}; + +const remove = async (id) => { + return Expense.destroy({ where: { id } }); +}; + +module.exports = { + getAll, + getById, + create, + update, + remove, +}; diff --git a/src/services/users.service.js b/src/services/users.service.js new file mode 100644 index 00000000..88b11ed2 --- /dev/null +++ b/src/services/users.service.js @@ -0,0 +1,33 @@ +const { User } = require('../models/User.model'); + +const getAll = async () => { + const result = await User.findAll(); + + return result; +}; + +const getById = async (id) => { + return User.findByPk(id); +}; + +const create = async (name) => { + return User.create({ name }); +}; + +const update = async (id, name) => { + await User.update({ name }, { where: { id } }); + + return User.findByPk(id); +}; + +const remove = async (id) => { + return User.destroy({ where: { id } }); +}; + +module.exports = { + getAll, + getById, + create, + update, + remove, +}; diff --git a/src/utils/getFilteredExpenses.js b/src/utils/getFilteredExpenses.js new file mode 100644 index 00000000..db558cda --- /dev/null +++ b/src/utils/getFilteredExpenses.js @@ -0,0 +1,35 @@ +const { Op } = require('sequelize'); + +const getFilteredExpenses = ({ userId, categories, from, to }) => { + const queryFilters = {}; + + if (userId) { + queryFilters.userId = userId; + } + + if (categories) { + queryFilters.category = categories; + } + + // if (from && to) { + // queryFilters.spentAt = { + // [Op.between]: [from, to], + // }; + // } + + if (from || to) { + queryFilters.spentAt = {}; + + if (from) { + queryFilters.spentAt[Op.gte] = from; + } + + if (to) { + queryFilters.spentAt[Op.lte] = to; + } + } + + return queryFilters; +}; + +module.exports = getFilteredExpenses; diff --git a/src/utils/getNextAvailableId.js b/src/utils/getNextAvailableId.js new file mode 100644 index 00000000..149e26c5 --- /dev/null +++ b/src/utils/getNextAvailableId.js @@ -0,0 +1,12 @@ +const getNextAvailableId = (array) => { + if (array.length === 0) { + return 1; + } + + const idsArray = array.map((arr) => arr.id); + const nexId = Math.max(...idsArray) + 1; + + return nexId; +}; + +module.exports = getNextAvailableId; diff --git a/src/variables/httpStatusCodes.js b/src/variables/httpStatusCodes.js new file mode 100644 index 00000000..0721951a --- /dev/null +++ b/src/variables/httpStatusCodes.js @@ -0,0 +1,9 @@ +const HTTP_STATUS_CODES = { + OK: 200, + CREATED: 201, + BAD_REQUEST: 400, + NOT_FOUND: 404, + NO_CONTENT: 204, +}; + +module.exports = HTTP_STATUS_CODES; From d0c9b3c4e84ac3db427524eb73eacc88149a8ea8 Mon Sep 17 00:00:00 2001 From: Lesia Date: Wed, 22 May 2024 09:55:18 +0300 Subject: [PATCH 2/2] add small changes --- src/controllers/expenses.controller.js | 15 ++++----------- src/utils/getFilteredExpenses.js | 6 ------ 2 files changed, 4 insertions(+), 17 deletions(-) diff --git a/src/controllers/expenses.controller.js b/src/controllers/expenses.controller.js index 4224f474..8af39ecc 100644 --- a/src/controllers/expenses.controller.js +++ b/src/controllers/expenses.controller.js @@ -27,23 +27,16 @@ const getOne = async (req, res) => { }; const create = async (req, res) => { - const { userId, spentAt, title, amount, category, note } = req.body; - const user = await getById(userId); + const body = req.body; + const user = await getById(body.userId); - if (!user || !spentAt || !title || !amount) { + if (!user) { res.sendStatus(HTTP_STATUS_CODES.BAD_REQUEST); return; } - const expense = await expensesService.create({ - userId, - spentAt, - title, - amount, - category, - note, - }); + const expense = await expensesService.create(body); res.statusCode = HTTP_STATUS_CODES.CREATED; res.send(expense); diff --git a/src/utils/getFilteredExpenses.js b/src/utils/getFilteredExpenses.js index db558cda..d06003d2 100644 --- a/src/utils/getFilteredExpenses.js +++ b/src/utils/getFilteredExpenses.js @@ -11,12 +11,6 @@ const getFilteredExpenses = ({ userId, categories, from, to }) => { queryFilters.category = categories; } - // if (from && to) { - // queryFilters.spentAt = { - // [Op.between]: [from, to], - // }; - // } - if (from || to) { queryFilters.spentAt = {};