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
14 changes: 14 additions & 0 deletions api/middleware/check-auth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const jwt = require('jsonwebtoken');

module.exports = (req, res, next) => {
try {
const token = req.headers.authorization.split(" ")[1];
const decoded = jwt.verify(token, process.env.JWT_KEY);
req.userData = decoded;
next();
} catch (error) {
return res.status(401).json({
message: 'Auth failed'
});
}
};
17 changes: 17 additions & 0 deletions api/models/user.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const mongoose = require("mongoose");

const userSchema = mongoose.Schema({
username: {
type: String,
required: true
},
password: {
type: String,
required: true
},
admin: {
type: Boolean,
default: false
}
});
module.exports = mongoose.model("User", userSchema);
129 changes: 72 additions & 57 deletions api/routes/books.js
Original file line number Diff line number Diff line change
@@ -1,78 +1,93 @@
const router = require('express').Router()
const Book = require('../models/book')
const router = require("express").Router();
const Book = require("../models/book");
const checkAuth = require("../middleware/check-auth");

router.get('/', async (req, res, next) => {
const status = 200
const response = await Book.find().select('-__v')

res.json({ status, response })
})
router.get("/", async (req, res, next) => {
const status = 200;
const response = await Book.find().select("-__v");

router.get('/:id', async (req, res, next) => {
const { id } = req.params
const status = 200
res.json({ status, response });
});

router.get("/:id", async (req, res, next) => {
const { id } = req.params;
const status = 200;
try {
const response = await Book.findById(id).select('-__v')
if (!response) throw new Error(`Invalid Book _id: ${id}`)
res.json({ status, response })
const response = await Book.findById(id).select("-__v");
if (!response) throw new Error(`Invalid Book _id: ${id}`);

res.json({ status, response });
} catch (e) {
console.error(e)
const error = new Error(`Cannot find book with id ${id}.`)
error.status = 404
next(error)
console.error(e);
const error = new Error(`Cannot find book with id ${id}.`);
error.status = 404;
next(error);
}
})
});

// You should only be able to create a book if the user is an admin
router.post('/', async (req, res, next) => {
const status = 200
try {
const book = await Book.create(req.body)
if (!book) throw new Error(`Request body failed: ${JSON.stringify(req.body)}`)

const response = await Book.findById(book._id).select('-__v')
res.json({ status, response })
} catch (e) {
console.error(e)
const message = 'Failure to create. Please check request body and try again.'
const error = new Error(message)
error.status = 400
next(error)

router.post("/", async (req, res, next) => {
const token = req.headers.authorization.split("Bearer ")[1];
const payload = verify(token, SECRET_KEY);
const adminUser = await User.findOne({ _id: payload.id });
const status = 200;
if (!adminUser.admin) {
return res.status(401).json({
message: "Not an admin user"
});
} else {
try {
const book = await Book.create(req.body);
if (!book)
throw new Error(`Request body failed: ${JSON.stringify(req.body)}`);

const response = await Book.findById(book._id).select("-__v");
res.json({ status, response });
} catch (e) {
console.error(e);
const message =
"Failure to create. Please check request body and try again.";
const error = new Error(message);
error.status = 400;
next(error);
}
}
})
});

// You should only be able to reserve a book if a user is logged in
router.patch('/:id/reserve', async (req, res, next) => {
const { id } = req.params
// checkAuth does chek the logged in member
router.patch("/:id/reserve", checkAuth, async (req, res, next) => {
const { id } = req.params;
try {
const book = await Book.findById(id)
const book = await Book.findById(id);
if (!book) {
const error = new Error(`Invalid Book _id: ${id}`)
error.message = 404
return next(error)
const error = new Error(`Invalid Book _id: ${id}`);
error.message = 404;
return next(error);
}

book.reserved.status = true
book.reserved.status = true;
// Set the reserved memberId to the current user
await book.save()

const response = await Book.findById(book._id).select('-__v')
const status = 200
res.json({ status, response })
book.reserved.memberId = req.userData;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Wont' this assign the memberId to be the entire object that is userData?

await book.save();

const response = await Book.findById(book._id).select("-__v");
const status = 200;
res.json({ status, response });
} catch (e) {
console.error(e)
console.error(e);
}
})
});

// You should only be able to return a book if the user is logged in
// and that user is the one who reserved the book
router.patch('/:id/return', async (req, res, next) => {
const status = 200
const message = 'You must implement this route!'
console.log(message)
res.status(status).json({ status, message })
})
router.patch("/:id/return", checkAuth, async (req, res, next) => {
const status = 200;
const message = "You must implement this route!";

console.log(message);
res.status(status).json({ status, message });
});
Copy link
Collaborator

Choose a reason for hiding this comment

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

This route yet to be implemented.


module.exports = router
module.exports = router;
138 changes: 138 additions & 0 deletions api/routes/user.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
const express = require("express");
const router = express.Router();
const mongoose = require("mongoose");
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");
const checkAuth = require("../middleware/check-auth");
const User = require("../models/user");

router.post("/signup", (req, res, next) => {
if (req.body.username) {
User.find({ username: req.body.username })
.exec()
.then(user => {
if (user.length >= 1) {
return res.status(409).json({
message: "Username is already taken"
});
} else {
if (req.body.password) {
if (req.body.password.length >= 8) {
bcrypt.hash(req.body.password, 10, (err, hash) => {
if (err) {
return res.status(500).json({
error: err
});
} else {
const user = new User({
_id: new mongoose.Types.ObjectId(),
username: req.body.username,
password: hash
});
user
.save()
.then(result => {
console.log(result);
res.status(201).json({
message: "User created"
});
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
});
});
}
});
} else {
return res.status(409).json({
message: "Password is less than 8 characters"
});
}
} else {
return res.status(409).json({
message: "Password is not provided"
});
}
}
});
} else {
return res.status(409).json({
message: "Username is not provided"
});
}
///
});
Copy link
Collaborator

Choose a reason for hiding this comment

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

This looks good but this function is quite long!

/********************************************************* */
router.post("/login", (req, res, next) => {
User.find({ username: req.body.username })
.exec()
.then(user => {
if (user.length < 1) {
return res.status(401).json({
message: "Username is not found"
});
}
bcrypt.compare(req.body.password, user[0].password, (err, result) => {
if (err) {
return res.status(401).json({
message: "Username and password do not match"
});
}
if (result) {
const token = jwt.sign(
{
username: user[0].username,
userId: user[0]._id
},
process.env.JWT_KEY,
{
expiresIn: "1h"
}
);
return res.status(200).json({
message: "Auth successful",
token: token
});
}
res.status(401).json({
message: "somthing went wrong"
});
});
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
});
});
});
/*************************************************** */
router.patch("/users/:id/permissions", checkAuth, async (req, res, next) => {
User.findById(req.params.id)
.exec()
.then(order => {
if (order) {
if (!order.admin) {
return res.status(401).json({
message: "The JWT token is for a user who is not an admin"
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think this is just checking whether or not the User you just found is an admin, not that the JWT Token is for an admin.

});
}
res.status(204).json({
message: "User has been updated"
});
} else {
res.status(404).json({
message: "User cannot be found"
});
}
})
.catch(err => {
res.status(500).json({
error: err
});
});
});

module.exports = router;
42 changes: 22 additions & 20 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,37 +1,39 @@
const { MONGO_DB_CONNECTION, NODE_ENV, PORT } = process.env
const express = require('express')
const mongoose = require('mongoose')
const app = express()
const { MONGO_DB_CONNECTION, NODE_ENV, PORT } = process.env;
const express = require("express");
const mongoose = require("mongoose");
const app = express();

// Database Connection
if (MONGO_DB_CONNECTION) {
mongoose.connect(MONGO_DB_CONNECTION, { useNewUrlParser: true })
console.log('Connected to database...')
mongoose.connect(MONGO_DB_CONNECTION, { useNewUrlParser: true });
console.log("Connected to database...");
} else {
console.log('Could not connect to database!')
console.log("Could not connect to database!");
}

// Application-level Middleware
if (NODE_ENV === 'development') app.use(require('morgan')('dev'))
app.use(require('body-parser').json())
if (NODE_ENV === "development") app.use(require("morgan")("dev"));
app.use(require("body-parser").json());

// Routes
app.use('/api/books', require('./api/routes/books'))
app.use("/api/books", require("./api/routes/books"));

app.use("/api", require("./api/routes/user"));

// Not Found Handler
app.use((req, res, next) => {
const error = new Error(`Could not ${req.method} ${req.path}`)
error.status = 404
next(error)
})
const error = new Error(`Could not ${req.method} ${req.path}`);
error.status = 404;
next(error);
});

// Error Handler
app.use((err, req, res, next) => {
if (NODE_ENV === 'development') console.error(err)
const { message, status } = err
res.status(status).json({ status, message })
})
if (NODE_ENV === "development") console.error(err);
const { message, status } = err;
res.status(status).json({ status, message });
});

// Open Connection
const listener = () => console.log(`Listening on Port ${PORT}!`)
app.listen(PORT, listener)
const listener = () => console.log(`Listening on Port ${PORT}!`);
app.listen(PORT, listener);
Loading