├── .gitignore ├── public ├── text │ └── data.txt ├── img │ └── img1.jpg └── css │ └── style.css ├── config ├── roles_list.js ├── allowedOrigins.js ├── dbConn.js └── corsOptions.js ├── routes ├── auth.js ├── logout.js ├── register.js ├── refresh.js ├── root.js └── api │ └── employees.js ├── model ├── employees.json └── users.json ├── middleware ├── errorHandler.js ├── credentials.js ├── verifyRoles.js ├── verifyJWT.js └── logEvents.js ├── views ├── 404.html └── index.html ├── package.json ├── README.md ├── logs └── reqLog.txt ├── controllers ├── refreshTokenController.js ├── logoutController.js ├── registerController.js ├── authController.js └── employeesController.js └── server.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | -------------------------------------------------------------------------------- /public/text/data.txt: -------------------------------------------------------------------------------- 1 | Just some random text. -------------------------------------------------------------------------------- /public/img/img1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitdagray/mongodb_mongoose_intro/HEAD/public/img/img1.jpg -------------------------------------------------------------------------------- /config/roles_list.js: -------------------------------------------------------------------------------- 1 | const ROLES_LIST = { 2 | "Admin": 5150, 3 | "Editor": 1984, 4 | "User": 2001 5 | } 6 | 7 | module.exports = ROLES_LIST -------------------------------------------------------------------------------- /config/allowedOrigins.js: -------------------------------------------------------------------------------- 1 | const allowedOrigins = [ 2 | 'https://www.yoursite.com', 3 | 'http://127.0.0.1:5500', 4 | 'http://localhost:3500' 5 | ]; 6 | 7 | module.exports = allowedOrigins; -------------------------------------------------------------------------------- /routes/auth.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | const authController = require('../controllers/authController'); 4 | 5 | router.post('/', authController.handleLogin); 6 | 7 | module.exports = router; -------------------------------------------------------------------------------- /model/employees.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 1, 4 | "firstname": "Dave", 5 | "lastname": "Gray" 6 | }, 7 | { 8 | "id": 2, 9 | "firstname": "John", 10 | "lastname": "Smith" 11 | } 12 | ] -------------------------------------------------------------------------------- /routes/logout.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | const logoutController = require('../controllers/logoutController'); 4 | 5 | router.get('/', logoutController.handleLogout); 6 | 7 | module.exports = router; -------------------------------------------------------------------------------- /routes/register.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | const registerController = require('../controllers/registerController'); 4 | 5 | router.post('/', registerController.handleNewUser); 6 | 7 | module.exports = router; -------------------------------------------------------------------------------- /routes/refresh.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | const refreshTokenController = require('../controllers/refreshTokenController'); 4 | 5 | router.get('/', refreshTokenController.handleRefreshToken); 6 | 7 | module.exports = router; -------------------------------------------------------------------------------- /routes/root.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | const path = require('path'); 4 | 5 | router.get('^/$|/index(.html)?', (req, res) => { 6 | res.sendFile(path.join(__dirname, '..', 'views', 'index.html')); 7 | }); 8 | 9 | module.exports = router; -------------------------------------------------------------------------------- /public/css/style.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | padding: 0; 4 | box-sizing: border-box; 5 | } 6 | 7 | body { 8 | font-size: 36px; 9 | min-height: 100vh; 10 | color: #fff; 11 | background-color: #000; 12 | display: grid; 13 | place-content: center; 14 | } 15 | -------------------------------------------------------------------------------- /middleware/errorHandler.js: -------------------------------------------------------------------------------- 1 | const { logEvents } = require('./logEvents'); 2 | 3 | const errorHandler = (err, req, res, next) => { 4 | logEvents(`${err.name}: ${err.message}`, 'errLog.txt'); 5 | console.error(err.stack) 6 | res.status(500).send(err.message); 7 | } 8 | 9 | module.exports = errorHandler; -------------------------------------------------------------------------------- /middleware/credentials.js: -------------------------------------------------------------------------------- 1 | const allowedOrigins = require('../config/allowedOrigins'); 2 | 3 | const credentials = (req, res, next) => { 4 | const origin = req.headers.origin; 5 | if (allowedOrigins.includes(origin)) { 6 | res.header('Access-Control-Allow-Credentials', true); 7 | } 8 | next(); 9 | } 10 | 11 | module.exports = credentials -------------------------------------------------------------------------------- /config/dbConn.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | const connectDB = async () => { 4 | try { 5 | await mongoose.connect(process.env.DATABASE_URI, { 6 | useUnifiedTopology: true, 7 | useNewUrlParser: true 8 | }); 9 | } catch (err) { 10 | console.error(err); 11 | } 12 | } 13 | 14 | module.exports = connectDB -------------------------------------------------------------------------------- /views/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 404 9 | 10 | 11 | 12 | 13 |

404

14 | 15 | 16 | -------------------------------------------------------------------------------- /views/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Index 9 | 10 | 11 | 12 | 13 |

Index

14 | 15 | 16 | -------------------------------------------------------------------------------- /config/corsOptions.js: -------------------------------------------------------------------------------- 1 | const allowedOrigins = require('./allowedOrigins'); 2 | 3 | const corsOptions = { 4 | origin: (origin, callback) => { 5 | if (allowedOrigins.indexOf(origin) !== -1 || !origin) { 6 | callback(null, true) 7 | } else { 8 | callback(new Error('Not allowed by CORS')); 9 | } 10 | }, 11 | optionsSuccessStatus: 200 12 | } 13 | 14 | module.exports = corsOptions; -------------------------------------------------------------------------------- /middleware/verifyRoles.js: -------------------------------------------------------------------------------- 1 | const verifyRoles = (...allowedRoles) => { 2 | return (req, res, next) => { 3 | if (!req?.roles) return res.sendStatus(401); 4 | const rolesArray = [...allowedRoles]; 5 | const result = req.roles.map(role => rolesArray.includes(role)).find(val => val === true); 6 | if (!result) return res.sendStatus(401); 7 | next(); 8 | } 9 | } 10 | 11 | module.exports = verifyRoles -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "13tut", 3 | "version": "1.0.0", 4 | "description": "MongoDB tutorial", 5 | "main": "server.js", 6 | "scripts": { 7 | "start": "node server", 8 | "dev": "nodemon server" 9 | }, 10 | "author": "Dave Gray", 11 | "license": "ISC", 12 | "dependencies": { 13 | "bcrypt": "^5.0.1", 14 | "cookie-parser": "^1.4.5", 15 | "cors": "^2.8.5", 16 | "date-fns": "^2.23.0", 17 | "dotenv": "^10.0.0", 18 | "express": "^4.17.1", 19 | "jsonwebtoken": "^8.5.1", 20 | "mongoose": "^6.0.11", 21 | "uuid": "^8.3.2" 22 | }, 23 | "devDependencies": { 24 | "nodemon": "^2.0.12" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /middleware/verifyJWT.js: -------------------------------------------------------------------------------- 1 | const jwt = require('jsonwebtoken'); 2 | 3 | const verifyJWT = (req, res, next) => { 4 | const authHeader = req.headers.authorization || req.headers.Authorization; 5 | if (!authHeader?.startsWith('Bearer ')) return res.sendStatus(401); 6 | const token = authHeader.split(' ')[1]; 7 | jwt.verify( 8 | token, 9 | process.env.ACCESS_TOKEN_SECRET, 10 | (err, decoded) => { 11 | if (err) return res.sendStatus(403); //invalid token 12 | req.user = decoded.UserInfo.username; 13 | req.roles = decoded.UserInfo.roles; 14 | next(); 15 | } 16 | ); 17 | } 18 | 19 | module.exports = verifyJWT -------------------------------------------------------------------------------- /routes/api/employees.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | const employeesController = require('../../controllers/employeesController'); 4 | const ROLES_LIST = require('../../config/roles_list'); 5 | const verifyRoles = require('../../middleware/verifyRoles'); 6 | 7 | router.route('/') 8 | .get(employeesController.getAllEmployees) 9 | .post(verifyRoles(ROLES_LIST.Admin, ROLES_LIST.Editor), employeesController.createNewEmployee) 10 | .put(verifyRoles(ROLES_LIST.Admin, ROLES_LIST.Editor), employeesController.updateEmployee) 11 | .delete(verifyRoles(ROLES_LIST.Admin), employeesController.deleteEmployee); 12 | 13 | router.route('/:id') 14 | .get(employeesController.getEmployee); 15 | 16 | module.exports = router; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # "Node JS Tutorial Series - MongoDB with Mongoose" 2 | 3 | ✅ [Check out my YouTube Channel with all of my tutorials](https://www.youtube.com/DaveGrayTeachesCode). 4 | 5 | **Description:** 6 | 7 | This repository shares the code applied during the Youtube tutorial. The tutorial is part of a [Node.js & Express for Beginners Playlist](https://www.youtube.com/playlist?list=PL0Zuz27SZ-6PFkIxaJ6Xx_X46avTM1aYw) on my channel. 8 | 9 | [YouTube Tutorial](https://youtu.be/-PdjUx9JZ2E) for this repository. 10 | 11 | I suggest completing my [8 hour JavaScript course tutorial video](https://youtu.be/EfAl9bwzVZk) if you are new to Javascript. 12 | 13 | ### Academic Honesty 14 | 15 | **DO NOT COPY FOR AN ASSIGNMENT** - Avoid plagiargism and adhere to the spirit of this [Academic Honesty Policy](https://www.freecodecamp.org/news/academic-honesty-policy/). 16 | -------------------------------------------------------------------------------- /model/users.json: -------------------------------------------------------------------------------- 1 | [{"username":"dave1","roles":{"User":2001},"password":"$2b$10$oEbHZlazDHE1YnnJ4XdpGuGh9a/JZOO7Xe6WZtRRsSMgprxMXnKza","refreshToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImRhdmUxIiwiaWF0IjoxNjMzOTkyMjkwLCJleHAiOjE2MzQwNzg2OTB9.U85HVX_gcDZkHHSRWeo7AHfIe7q9i03dGW2ed3fHqAk"},{"username":"walt2","roles":{"User":2001,"Editor":1984},"password":"$2b$10$cvfmz./teMWDccIMChAxZ.HqgL3eoQGYTm1z9lGy5iRf8D7NNargC","refreshToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IndhbHQyIiwiaWF0IjoxNjMzOTkyNDU2LCJleHAiOjE2MzQwNzg4NTZ9.wRVJbN7_67JyTW9PALMWWEsO4BMkehyy5kXq6WilvWc"},{"username":"walt1","roles":{"User":2001,"Editor":1984,"Admin":5150},"password":"$2b$10$33Q9jtAoaXC4aUX9Bjihxum2BHG.ENB6JyoCvPjnuXpITtUd8x8/y","refreshToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6IndhbHQxIiwiaWF0IjoxNjMzOTkyNTY0LCJleHAiOjE2MzQwNzg5NjR9.gE2CgbtEuqE42LeJ4dP6APmqyGTNBh53WXVyDdP47yM"}] -------------------------------------------------------------------------------- /middleware/logEvents.js: -------------------------------------------------------------------------------- 1 | const { format } = require('date-fns'); 2 | const { v4: uuid } = require('uuid'); 3 | 4 | const fs = require('fs'); 5 | const fsPromises = require('fs').promises; 6 | const path = require('path'); 7 | 8 | const logEvents = async (message, logName) => { 9 | const dateTime = `${format(new Date(), 'yyyyMMdd\tHH:mm:ss')}`; 10 | const logItem = `${dateTime}\t${uuid()}\t${message}\n`; 11 | 12 | try { 13 | if (!fs.existsSync(path.join(__dirname, '..', 'logs'))) { 14 | await fsPromises.mkdir(path.join(__dirname, '..', 'logs')); 15 | } 16 | 17 | await fsPromises.appendFile(path.join(__dirname, '..', 'logs', logName), logItem); 18 | } catch (err) { 19 | console.log(err); 20 | } 21 | } 22 | 23 | const logger = (req, res, next) => { 24 | logEvents(`${req.method}\t${req.headers.origin}\t${req.url}`, 'reqLog.txt'); 25 | console.log(`${req.method} ${req.path}`); 26 | next(); 27 | } 28 | 29 | module.exports = { logger, logEvents }; 30 | -------------------------------------------------------------------------------- /logs/reqLog.txt: -------------------------------------------------------------------------------- 1 | 20211011 17:44:50 9c6f8dae-33e6-4e75-aa26-9705f6f63c24 POST undefined /auth 2 | 20211011 17:45:07 a1c02ef1-8bb5-4e11-a7db-7dc3e9fb742b GET undefined /employees 3 | 20211011 17:45:19 fc1f8b2b-064a-4751-be68-59442092914d POST undefined /employees 4 | 20211011 17:46:56 98a170c4-3830-48f9-bc19-ac2f80c42d54 POST undefined /auth 5 | 20211011 17:47:10 0a3231e2-3083-42b8-bf71-2e699508452b POST undefined /employees 6 | 20211011 17:47:26 b880f8d2-4af3-4f8a-acfc-64635b35b81f DELETE undefined /employees 7 | 20211011 17:47:36 f0fe0150-44a9-4f1c-a7d7-ec8e4ce8d1dd POST undefined /auth 8 | 20211011 17:47:52 6b9200a7-d769-4464-a404-423b67b5cf0c DELETE undefined /employees 9 | 20211011 17:48:48 bcdb46f9-4364-4d9c-97f8-55795cd8c413 POST undefined /auth 10 | 20211011 17:49:03 d692da66-f505-444c-8fa6-5b87ef9972c3 DELETE undefined /employees 11 | 20211011 17:49:24 2b74f46b-65d3-4041-9c87-65e0982d46ad POST undefined /auth 12 | 20211011 17:49:38 32899fb9-23b8-49fc-95ac-631462d7174c POST undefined /employees 13 | 20211011 17:49:44 df0482cf-3962-4078-9a8e-b4712e1d8658 DELETE undefined /employees 14 | -------------------------------------------------------------------------------- /controllers/refreshTokenController.js: -------------------------------------------------------------------------------- 1 | const usersDB = { 2 | users: require('../model/users.json'), 3 | setUsers: function (data) { this.users = data } 4 | } 5 | const jwt = require('jsonwebtoken'); 6 | 7 | const handleRefreshToken = (req, res) => { 8 | const cookies = req.cookies; 9 | if (!cookies?.jwt) return res.sendStatus(401); 10 | const refreshToken = cookies.jwt; 11 | 12 | const foundUser = usersDB.users.find(person => person.refreshToken === refreshToken); 13 | if (!foundUser) return res.sendStatus(403); //Forbidden 14 | // evaluate jwt 15 | jwt.verify( 16 | refreshToken, 17 | process.env.REFRESH_TOKEN_SECRET, 18 | (err, decoded) => { 19 | if (err || foundUser.username !== decoded.username) return res.sendStatus(403); 20 | const roles = Object.values(foundUser.roles); 21 | const accessToken = jwt.sign( 22 | { 23 | "UserInfo": { 24 | "username": decoded.username, 25 | "roles": roles 26 | } 27 | }, 28 | process.env.ACCESS_TOKEN_SECRET, 29 | { expiresIn: '30s' } 30 | ); 31 | res.json({ accessToken }) 32 | } 33 | ); 34 | } 35 | 36 | module.exports = { handleRefreshToken } -------------------------------------------------------------------------------- /controllers/logoutController.js: -------------------------------------------------------------------------------- 1 | const usersDB = { 2 | users: require('../model/users.json'), 3 | setUsers: function (data) { this.users = data } 4 | } 5 | const fsPromises = require('fs').promises; 6 | const path = require('path'); 7 | 8 | const handleLogout = async (req, res) => { 9 | // On client, also delete the accessToken 10 | 11 | const cookies = req.cookies; 12 | if (!cookies?.jwt) return res.sendStatus(204); //No content 13 | const refreshToken = cookies.jwt; 14 | 15 | // Is refreshToken in db? 16 | const foundUser = usersDB.users.find(person => person.refreshToken === refreshToken); 17 | if (!foundUser) { 18 | res.clearCookie('jwt', { httpOnly: true, sameSite: 'None', secure: true }); 19 | return res.sendStatus(204); 20 | } 21 | 22 | // Delete refreshToken in db 23 | const otherUsers = usersDB.users.filter(person => person.refreshToken !== foundUser.refreshToken); 24 | const currentUser = { ...foundUser, refreshToken: '' }; 25 | usersDB.setUsers([...otherUsers, currentUser]); 26 | await fsPromises.writeFile( 27 | path.join(__dirname, '..', 'model', 'users.json'), 28 | JSON.stringify(usersDB.users) 29 | ); 30 | 31 | res.clearCookie('jwt', { httpOnly: true, sameSite: 'None', secure: true }); 32 | res.sendStatus(204); 33 | } 34 | 35 | module.exports = { handleLogout } -------------------------------------------------------------------------------- /controllers/registerController.js: -------------------------------------------------------------------------------- 1 | const usersDB = { 2 | users: require('../model/users.json'), 3 | setUsers: function (data) { this.users = data } 4 | } 5 | const fsPromises = require('fs').promises; 6 | const path = require('path'); 7 | const bcrypt = require('bcrypt'); 8 | 9 | const handleNewUser = async (req, res) => { 10 | const { user, pwd } = req.body; 11 | if (!user || !pwd) return res.status(400).json({ 'message': 'Username and password are required.' }); 12 | // check for duplicate usernames in the db 13 | const duplicate = usersDB.users.find(person => person.username === user); 14 | if (duplicate) return res.sendStatus(409); //Conflict 15 | try { 16 | //encrypt the password 17 | const hashedPwd = await bcrypt.hash(pwd, 10); 18 | //store the new user 19 | const newUser = { 20 | "username": user, 21 | "roles": { "User": 2001 }, 22 | "password": hashedPwd 23 | }; 24 | usersDB.setUsers([...usersDB.users, newUser]); 25 | await fsPromises.writeFile( 26 | path.join(__dirname, '..', 'model', 'users.json'), 27 | JSON.stringify(usersDB.users) 28 | ); 29 | console.log(usersDB.users); 30 | res.status(201).json({ 'success': `New user ${user} created!` }); 31 | } catch (err) { 32 | res.status(500).json({ 'message': err.message }); 33 | } 34 | } 35 | 36 | module.exports = { handleNewUser }; -------------------------------------------------------------------------------- /controllers/authController.js: -------------------------------------------------------------------------------- 1 | const usersDB = { 2 | users: require('../model/users.json'), 3 | setUsers: function (data) { this.users = data } 4 | } 5 | const bcrypt = require('bcrypt'); 6 | 7 | const jwt = require('jsonwebtoken'); 8 | const fsPromises = require('fs').promises; 9 | const path = require('path'); 10 | 11 | const handleLogin = async (req, res) => { 12 | const { user, pwd } = req.body; 13 | if (!user || !pwd) return res.status(400).json({ 'message': 'Username and password are required.' }); 14 | const foundUser = usersDB.users.find(person => person.username === user); 15 | if (!foundUser) return res.sendStatus(401); //Unauthorized 16 | // evaluate password 17 | const match = await bcrypt.compare(pwd, foundUser.password); 18 | if (match) { 19 | const roles = Object.values(foundUser.roles); 20 | // create JWTs 21 | const accessToken = jwt.sign( 22 | { 23 | "UserInfo": { 24 | "username": foundUser.username, 25 | "roles": roles 26 | } 27 | }, 28 | process.env.ACCESS_TOKEN_SECRET, 29 | { expiresIn: '30s' } 30 | ); 31 | const refreshToken = jwt.sign( 32 | { "username": foundUser.username }, 33 | process.env.REFRESH_TOKEN_SECRET, 34 | { expiresIn: '1d' } 35 | ); 36 | // Saving refreshToken with current user 37 | const otherUsers = usersDB.users.filter(person => person.username !== foundUser.username); 38 | const currentUser = { ...foundUser, refreshToken }; 39 | usersDB.setUsers([...otherUsers, currentUser]); 40 | await fsPromises.writeFile( 41 | path.join(__dirname, '..', 'model', 'users.json'), 42 | JSON.stringify(usersDB.users) 43 | ); 44 | res.cookie('jwt', refreshToken, { httpOnly: true, sameSite: 'None', secure: true, maxAge: 24 * 60 * 60 * 1000 }); 45 | res.json({ accessToken }); 46 | } else { 47 | res.sendStatus(401); 48 | } 49 | } 50 | 51 | module.exports = { handleLogin }; -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config(); 2 | const express = require('express'); 3 | const app = express(); 4 | const path = require('path'); 5 | const cors = require('cors'); 6 | const corsOptions = require('./config/corsOptions'); 7 | const { logger } = require('./middleware/logEvents'); 8 | const errorHandler = require('./middleware/errorHandler'); 9 | const verifyJWT = require('./middleware/verifyJWT'); 10 | const cookieParser = require('cookie-parser'); 11 | const credentials = require('./middleware/credentials'); 12 | const mongoose = require('mongoose'); 13 | const connectDB = require('./config/dbConn'); 14 | const PORT = process.env.PORT || 3500; 15 | 16 | // Connect to MongoDB 17 | connectDB(); 18 | 19 | // custom middleware logger 20 | app.use(logger); 21 | 22 | // Handle options credentials check - before CORS! 23 | // and fetch cookies credentials requirement 24 | app.use(credentials); 25 | 26 | // Cross Origin Resource Sharing 27 | app.use(cors(corsOptions)); 28 | 29 | // built-in middleware to handle urlencoded form data 30 | app.use(express.urlencoded({ extended: false })); 31 | 32 | // built-in middleware for json 33 | app.use(express.json()); 34 | 35 | //middleware for cookies 36 | app.use(cookieParser()); 37 | 38 | //serve static files 39 | app.use('/', express.static(path.join(__dirname, '/public'))); 40 | 41 | // routes 42 | app.use('/', require('./routes/root')); 43 | app.use('/register', require('./routes/register')); 44 | app.use('/auth', require('./routes/auth')); 45 | app.use('/refresh', require('./routes/refresh')); 46 | app.use('/logout', require('./routes/logout')); 47 | 48 | app.use(verifyJWT); 49 | app.use('/employees', require('./routes/api/employees')); 50 | 51 | app.all('*', (req, res) => { 52 | res.status(404); 53 | if (req.accepts('html')) { 54 | res.sendFile(path.join(__dirname, 'views', '404.html')); 55 | } else if (req.accepts('json')) { 56 | res.json({ "error": "404 Not Found" }); 57 | } else { 58 | res.type('txt').send("404 Not Found"); 59 | } 60 | }); 61 | 62 | app.use(errorHandler); 63 | 64 | mongoose.connection.once('open', () => { 65 | console.log('Connected to MongoDB'); 66 | app.listen(PORT, () => console.log(`Server running on port ${PORT}`)); 67 | }); -------------------------------------------------------------------------------- /controllers/employeesController.js: -------------------------------------------------------------------------------- 1 | const data = { 2 | employees: require('../model/employees.json'), 3 | setEmployees: function (data) { this.employees = data } 4 | } 5 | 6 | const getAllEmployees = (req, res) => { 7 | res.json(data.employees); 8 | } 9 | 10 | const createNewEmployee = (req, res) => { 11 | const newEmployee = { 12 | id: data.employees?.length ? data.employees[data.employees.length - 1].id + 1 : 1, 13 | firstname: req.body.firstname, 14 | lastname: req.body.lastname 15 | } 16 | 17 | if (!newEmployee.firstname || !newEmployee.lastname) { 18 | return res.status(400).json({ 'message': 'First and last names are required.' }); 19 | } 20 | 21 | data.setEmployees([...data.employees, newEmployee]); 22 | res.status(201).json(data.employees); 23 | } 24 | 25 | const updateEmployee = (req, res) => { 26 | const employee = data.employees.find(emp => emp.id === parseInt(req.body.id)); 27 | if (!employee) { 28 | return res.status(400).json({ "message": `Employee ID ${req.body.id} not found` }); 29 | } 30 | if (req.body.firstname) employee.firstname = req.body.firstname; 31 | if (req.body.lastname) employee.lastname = req.body.lastname; 32 | const filteredArray = data.employees.filter(emp => emp.id !== parseInt(req.body.id)); 33 | const unsortedArray = [...filteredArray, employee]; 34 | data.setEmployees(unsortedArray.sort((a, b) => a.id > b.id ? 1 : a.id < b.id ? -1 : 0)); 35 | res.json(data.employees); 36 | } 37 | 38 | const deleteEmployee = (req, res) => { 39 | const employee = data.employees.find(emp => emp.id === parseInt(req.body.id)); 40 | if (!employee) { 41 | return res.status(400).json({ "message": `Employee ID ${req.body.id} not found` }); 42 | } 43 | const filteredArray = data.employees.filter(emp => emp.id !== parseInt(req.body.id)); 44 | data.setEmployees([...filteredArray]); 45 | res.json(data.employees); 46 | } 47 | 48 | const getEmployee = (req, res) => { 49 | const employee = data.employees.find(emp => emp.id === parseInt(req.params.id)); 50 | if (!employee) { 51 | return res.status(400).json({ "message": `Employee ID ${req.params.id} not found` }); 52 | } 53 | res.json(employee); 54 | } 55 | 56 | module.exports = { 57 | getAllEmployees, 58 | createNewEmployee, 59 | updateEmployee, 60 | deleteEmployee, 61 | getEmployee 62 | } --------------------------------------------------------------------------------