Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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 .github/workflows/test.yml-template
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: Test

on:
pull_request:
branches: [ master ]

jobs:
build:

runs-on: ubuntu-latest

strategy:
matrix:
node-version: [20.x]

steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm install
- run: npm test
9 changes: 5 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
},
"devDependencies": {
"@mate-academy/eslint-config": "latest",
"@mate-academy/scripts": "^1.8.6",
"@mate-academy/scripts": "^2.1.3",
"eslint": "^8.57.0",
"eslint-plugin-jest": "^28.6.0",
"eslint-plugin-node": "^11.1.0",
Expand Down
111 changes: 111 additions & 0 deletions src/controllers/expensesCtrl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
'use strict';

const expensesService = require('../services/expensesSvc');
const usersService = require('../services/usersSvc');

const expensesController = {
create(req, res) {
const { userId, spentAt, title, amount, category, note } = req.body;

// Check if required fields are provided
if (
userId === undefined ||
!spentAt ||
!title ||
amount === undefined ||
!category ||
!note
) {
res.status(400).json({ error: 'missing required fields' });

return;
}

// Check if user exists
const user = usersService.getById(userId);

if (!user) {
res.status(404).json({ error: 'user not found' });

return;
}

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

res.status(201).json(expense);
},

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

const filters = {};

if (userId) {
filters.userId = Number(userId);
}

if (from) {
filters.from = from;
}

if (to) {
filters.to = to;
}

if (categories) {
filters.categories = categories.split(',').map((c) => c.trim());
}

const expenses = expensesService.getAll(filters);

res.status(200).json(expenses);
},

getById(req, res) {
const { id } = req.params;
const expense = expensesService.getById(Number(id));

if (!expense) {
res.status(404).json({ error: 'expense not found' });

return;
}

res.status(200).json(expense);
},

update(req, res) {
const { id } = req.params;
const expense = expensesService.update(Number(id), req.body);

if (!expense) {
res.status(404).json({ error: 'expense not found' });

return;
}

res.status(200).json(expense);
},

delete(req, res) {
const { id } = req.params;
const deleted = expensesService.delete(Number(id));

if (!deleted) {
res.status(404).json({ error: 'expense not found' });

return;
}

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

module.exports = expensesController;
66 changes: 66 additions & 0 deletions src/controllers/usersCtrl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
'use strict';

const usersService = require('../services/usersSvc');

const usersController = {
create(req, res) {
const { name } = req.body;

if (!name) {
res.status(400).json({ error: 'name is required' });

return;
}

const user = usersService.create(name);

res.status(201).json(user);
},

getAll(req, res) {
const users = usersService.getAll();

res.status(200).json(users);
},

getById(req, res) {
const { id } = req.params;
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

According to the task requirements, when an expected entity doesn't exist, the response should be 404. Here, a non-existent user returns 400, but it should be 404 since 'user not found' is about a missing entity.

const user = usersService.getById(Number(id));

if (!user) {
res.status(404).json({ error: 'user not found' });

return;
}

res.status(200).json(user);
},

update(req, res) {
const { id } = req.params;
const user = usersService.update(Number(id), req.body);

if (!user) {
res.status(404).json({ error: 'user not found' });

return;
}

res.status(200).json(user);
},

delete(req, res) {
const { id } = req.params;
const deleted = usersService.delete(Number(id));

if (!deleted) {
res.status(404).json({ error: 'user not found' });

return;
}

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

module.exports = usersController;
20 changes: 16 additions & 4 deletions src/createServer.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,23 @@
'use strict';

// const express = require('express');
const express = require('express');
const usersService = require('./services/usersSvc');
const expensesService = require('./services/expensesSvc');
const usersRouter = require('./routes/usersRt');
const expensesRouter = require('./routes/expensesRt');

function createServer() {
// Use express to create a server
// Add a routes to the server
// Return the server (express app)
usersService.clear();
expensesService.clear();

const app = express();

app.use(express.json());

app.use('/users', usersRouter);
app.use('/expenses', expensesRouter);

return app;
}

module.exports = {
Expand Down
14 changes: 14 additions & 0 deletions src/routes/expensesRt.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
'use strict';

const express = require('express');
const expensesController = require('../controllers/expensesCtrl');

const router = express.Router();

router.post('/', (req, res) => expensesController.create(req, res));
router.get('/', (req, res) => expensesController.getAll(req, res));
router.get('/:id', (req, res) => expensesController.getById(req, res));
router.patch('/:id', (req, res) => expensesController.update(req, res));
router.delete('/:id', (req, res) => expensesController.delete(req, res));

module.exports = router;
14 changes: 14 additions & 0 deletions src/routes/usersRt.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
'use strict';

const express = require('express');
const usersController = require('../controllers/usersCtrl');

const router = express.Router();

router.post('/', (req, res) => usersController.create(req, res));
router.get('/', (req, res) => usersController.getAll(req, res));
router.get('/:id', (req, res) => usersController.getById(req, res));
router.patch('/:id', (req, res) => usersController.update(req, res));
router.delete('/:id', (req, res) => usersController.delete(req, res));

module.exports = router;
104 changes: 104 additions & 0 deletions src/services/expensesSvc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
'use strict';

let expenses = [];
let expenseId = 1;

const expensesService = {
clear() {
expenses = [];
expenseId = 1;
},

create(expenseData) {
const expense = {
id: expenseId,
...expenseData,
};

expenses.push(expense);
expenseId += 1;

return expense;
},

getAll(filters = {}) {
let result = expenses;

if (filters.userId) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Per the task requirements ('return 404 with any message if expected entity doesn't exist' for every request), this should return 404 when the referenced user doesn't exist, not 400.

result = result.filter((e) => e.userId === filters.userId);
}

if (filters.from) {
result = result.filter(
(e) => new Date(e.spentAt) >= new Date(filters.from),
);
}

if (filters.to) {
result = result.filter(
(e) => new Date(e.spentAt) <= new Date(filters.to),
);
}

if (filters.categories) {
const categoryList = Array.isArray(filters.categories)
? filters.categories
: [filters.categories];

result = result.filter((e) => categoryList.includes(e.category));
}

return result;
},

getById(id) {
return expenses.find((e) => e.id === id);
},

update(id, data) {
const expense = this.getById(id);

if (!expense) {
return null;
}

if (data.userId !== undefined) {
expense.userId = data.userId;
}

if (data.spentAt !== undefined) {
expense.spentAt = data.spentAt;
}

if (data.title !== undefined) {
expense.title = data.title;
}

if (data.amount !== undefined) {
expense.amount = data.amount;
}

if (data.category !== undefined) {
expense.category = data.category;
}

if (data.note !== undefined) {
expense.note = data.note;
}

return expense;
},

delete(id) {
const index = expenses.findIndex((e) => e.id === id);

if (index === -1) {
return false;
}
expenses.splice(index, 1);

return true;
},
};

module.exports = expensesService;
Loading
Loading