Essential backend functionality, including logins.
This commit is contained in:
49
api/controllers/bookController.js
Normal file
49
api/controllers/bookController.js
Normal file
@@ -0,0 +1,49 @@
|
||||
'use strict';
|
||||
|
||||
const mongoose = require('mongoose'),
|
||||
Book = mongoose.model('Book');
|
||||
|
||||
exports.list_all = function(req, res) {
|
||||
Book.find({}, function(error, books) {
|
||||
if (error) res.status(400).send(error);
|
||||
else res.json(books);
|
||||
});
|
||||
};
|
||||
|
||||
exports.create = function(req, res) {
|
||||
// TODO authenticate
|
||||
const book = new Book(req.body);
|
||||
book.save(function(error, book) {
|
||||
if (error) res.status(400).send(error);
|
||||
else res.json(book);
|
||||
});
|
||||
};
|
||||
|
||||
exports.get = function(req, res) {
|
||||
Book.findById(req.params.bookId, function(error, book) {
|
||||
if (error) res.status(400).send(error);
|
||||
else res.json(book);
|
||||
});
|
||||
};
|
||||
|
||||
exports.update = function(req, res) {
|
||||
Book.findOneAndUpdate({
|
||||
_id: req.params.bookId
|
||||
}, req.body, {
|
||||
new: true
|
||||
}, function(error, book) {
|
||||
if (error) res.status(400).send(error);
|
||||
else res.json(book);
|
||||
});
|
||||
};
|
||||
|
||||
exports.delete = function(req, res) {
|
||||
Book.remove({
|
||||
_id: req.params.bookId
|
||||
}, function(error, book) {
|
||||
if (error) res.status(400).send(error);
|
||||
else res.json({
|
||||
message: 'Book ' + book.title + ' deleted'
|
||||
});
|
||||
});
|
||||
};
|
||||
75
api/controllers/borrowController.js
Normal file
75
api/controllers/borrowController.js
Normal file
@@ -0,0 +1,75 @@
|
||||
'use strict';
|
||||
|
||||
const mongoose = require('mongoose');
|
||||
const User = mongoose.model('User'),
|
||||
Book = mongoose.model('Book');
|
||||
|
||||
exports.list_all = function(req, res) {
|
||||
res.json(req.user.borrowing);
|
||||
};
|
||||
|
||||
exports.update = function(req, res) {
|
||||
Book.findOne({
|
||||
_id: req.body.bookId
|
||||
}).then((book) => {
|
||||
if (!book) {
|
||||
res.status(400).send("Book not found.");
|
||||
} else {
|
||||
// TODO check that the book isn't already borrowed
|
||||
req.user.borrowing.push({
|
||||
bookId: book._id,
|
||||
date: Date.now()
|
||||
});
|
||||
User.findOneAndUpdate({
|
||||
_id: req.user._id
|
||||
}, req.user, {
|
||||
useFindAndModify: false
|
||||
}).exec();
|
||||
book.amount_loaned += 1;
|
||||
Book.findOneAndUpdate({
|
||||
_id: book._id
|
||||
}, book, {
|
||||
useFindAndModify: false
|
||||
}).exec();
|
||||
res.json(req.user.borrowing);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// TODO
|
||||
exports.delete = function(req, res) {
|
||||
Book.findOne({
|
||||
_id: req.body.bookId
|
||||
}).then((book) => {
|
||||
if (!book) {
|
||||
res.status(400).send("Book not found.");
|
||||
} else {
|
||||
let isBookLoaned = false;
|
||||
for (let i = 0; i < req.user.borrowing.length; i++) {
|
||||
const b = req.user.borrowing[i];
|
||||
console.log(`${typeof b.bookId}, ${typeof book.id}`);
|
||||
if (b.bookId.toString() === book.id) {
|
||||
console.log(`${b.bookId}, ${book._id}`);
|
||||
req.user.borrowing.splice(i, 1);
|
||||
isBookLoaned = true;
|
||||
}
|
||||
}
|
||||
if (isBookLoaned) {
|
||||
User.findOneAndUpdate({
|
||||
_id: req.user._id
|
||||
}, req.user, {
|
||||
useFindAndModify: false
|
||||
}).exec();
|
||||
book.amount_loaned -= 1;
|
||||
Book.findOneAndUpdate({
|
||||
_id: book._id
|
||||
}, book, {
|
||||
useFindAndModify: false
|
||||
}).exec();
|
||||
res.json(req.user.borrowing);
|
||||
} else {
|
||||
res.status(400).send("You haven't loaned this book.")
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
86
api/controllers/userController.js
Normal file
86
api/controllers/userController.js
Normal file
@@ -0,0 +1,86 @@
|
||||
'use strict';
|
||||
|
||||
const mongoose = require('mongoose'),
|
||||
User = mongoose.model('User'),
|
||||
bcrypt = require('bcrypt');
|
||||
const saltRounds = 10; // TODO make this configurable.
|
||||
|
||||
exports.list_all = function(req, res) {
|
||||
User.find({}, function(err, users) {
|
||||
if (err) res.status(400).send(err);
|
||||
else res.json(users);
|
||||
});
|
||||
};
|
||||
|
||||
exports.create = function(req, res) {
|
||||
User.findOne({
|
||||
"username": req.body.username
|
||||
}, function(err, user) {
|
||||
if (err) res.status(400).send(err);
|
||||
else if (user) res.status(400).send("User with that username already exists.");
|
||||
else { // user doesn't exist, allow creation of new one
|
||||
const user = new User(req.body);
|
||||
bcrypt.hash(user.password, saltRounds, function(err, hash) {
|
||||
if (err) res.status(500).send(err);
|
||||
else {
|
||||
user.password = hash;
|
||||
user.save(function(err, user) {
|
||||
if (err) res.status(400).send(err);
|
||||
else res.json(user);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
exports.get = function(req, res) {
|
||||
User.findById(req.params.userId, function(error, user) {
|
||||
if (error) res.status(400).send(error);
|
||||
else res.json(user);
|
||||
});
|
||||
};
|
||||
|
||||
exports.update = function(req, res) {
|
||||
function updateUser(newUser) {
|
||||
User.findOneAndUpdate({
|
||||
_id: req.params.userId
|
||||
}, req.body, {
|
||||
new: true,
|
||||
useFindAndModify: false
|
||||
}, function(error, user) {
|
||||
if (error) res.status(400).send(error);
|
||||
res.json(user);
|
||||
});
|
||||
}
|
||||
|
||||
if (req.body.password) {
|
||||
req.body.password = bcrypt.hash(req.body.password, saltRounds).then(hash => {
|
||||
req.body.password = hash;
|
||||
updateUser(req.body);
|
||||
});
|
||||
} else {
|
||||
updateUser(req.body);
|
||||
}
|
||||
};
|
||||
|
||||
exports.delete = function(req, res) {
|
||||
User.findById(req.params.userId, function(error, user) {
|
||||
if (error) {
|
||||
res.status(400).send(error);
|
||||
} else if (user.loaning.length > 0) {
|
||||
res.status(403).json({
|
||||
message: 'User ' + user.username + ' must return books before deletion.'
|
||||
})
|
||||
} else {
|
||||
User.deleteOne({
|
||||
_id: req.params.userId
|
||||
}, function(error) {
|
||||
if (error) res.status(400).send(error);
|
||||
else res.json({
|
||||
message: 'User deleted.'
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
28
api/models/bookModel.js
Normal file
28
api/models/bookModel.js
Normal file
@@ -0,0 +1,28 @@
|
||||
'use strict';
|
||||
const mongoose = require('mongoose');
|
||||
const Schema = mongoose.Schema;
|
||||
|
||||
const BookSchema = new Schema({
|
||||
title: {
|
||||
type: String,
|
||||
required: 'Book title missing'
|
||||
},
|
||||
publication_date: {
|
||||
type: Date,
|
||||
default: Date(0)
|
||||
},
|
||||
quantity: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
amount_loaned: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
isbn13: {
|
||||
type: String,
|
||||
required: 'Book ISBN-13 missing'
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = mongoose.model('Book', BookSchema);
|
||||
70
api/models/userModel.js
Normal file
70
api/models/userModel.js
Normal file
@@ -0,0 +1,70 @@
|
||||
'use strict';
|
||||
const mongoose = require('mongoose');
|
||||
const Schema = mongoose.Schema;
|
||||
|
||||
const permission_set = {
|
||||
add_books: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
update_books: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
borrow_books: {
|
||||
type: Boolean,
|
||||
default: true
|
||||
},
|
||||
add_users: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
delete_users: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
delete_books: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
update_users: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
change_permissions: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
};
|
||||
|
||||
const UserSchema = new Schema({
|
||||
username: {
|
||||
type: String,
|
||||
required: 'Username missing'
|
||||
},
|
||||
password: {
|
||||
type: String,
|
||||
required: 'Password missing'
|
||||
},
|
||||
email: String,
|
||||
student_card: String,
|
||||
borrowing: [{
|
||||
bookId: Schema.Types.ObjectId,
|
||||
date: Date
|
||||
}],
|
||||
permissions: permission_set
|
||||
});
|
||||
|
||||
UserSchema.set('toJSON', {
|
||||
transform: function(doc, ret, options) {
|
||||
const json = {
|
||||
username: ret.username,
|
||||
borrowing: ret.borrowing,
|
||||
permissions: ret.permissions,
|
||||
_id: ret._id
|
||||
};
|
||||
return json;
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = mongoose.model('User', UserSchema);
|
||||
21
api/routes/baseRouter.js
Normal file
21
api/routes/baseRouter.js
Normal file
@@ -0,0 +1,21 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const userRouter = require('./userRouter'),
|
||||
bookRouter = require('./bookRouter'),
|
||||
borrowRouter = require('./borrowRouter');
|
||||
|
||||
// logger
|
||||
router.use(function(req, res, next) {
|
||||
if (req.user) {
|
||||
console.log("User %s: %s %s", req.user.username, req.method, req.url);
|
||||
} else {
|
||||
console.log('%s %s', req.method, req.url);
|
||||
}
|
||||
next();
|
||||
});
|
||||
|
||||
router.use('/users', userRouter);
|
||||
router.use('/books', bookRouter);
|
||||
router.use('/borrow', borrowRouter);
|
||||
|
||||
module.exports = router
|
||||
17
api/routes/bookRouter.js
Normal file
17
api/routes/bookRouter.js
Normal file
@@ -0,0 +1,17 @@
|
||||
'use strict';
|
||||
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const book = require('../controllers/bookController');
|
||||
const requirePermission = require('../../utils/requirePermission');
|
||||
|
||||
router.route('/')
|
||||
.get(book.list_all)
|
||||
.post(requirePermission("borrow_books"), book.create);
|
||||
|
||||
router.route('/:bookId')
|
||||
.get(book.get)
|
||||
.put(book.update)
|
||||
.delete(book.delete);
|
||||
|
||||
module.exports = router;
|
||||
14
api/routes/borrowRouter.js
Normal file
14
api/routes/borrowRouter.js
Normal file
@@ -0,0 +1,14 @@
|
||||
'use strict';
|
||||
|
||||
const express = require('express')
|
||||
const router = express.Router()
|
||||
const borrow = require('../controllers/borrowController');
|
||||
const requirePermission = require('../../utils/requirePermission');
|
||||
|
||||
router.all(requirePermission("borrow_books"));
|
||||
router.route('/')
|
||||
.get(borrow.list_all)
|
||||
.put(borrow.update)
|
||||
.delete(borrow.delete);
|
||||
|
||||
module.exports = router;
|
||||
17
api/routes/userRouter.js
Normal file
17
api/routes/userRouter.js
Normal file
@@ -0,0 +1,17 @@
|
||||
'use strict';
|
||||
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const user = require('../controllers/userController');
|
||||
const requirePermission = require('../../utils/requirePermission');
|
||||
|
||||
router.route('/')
|
||||
.get(user.list_all)
|
||||
.post(requirePermission("add_users"), user.create);
|
||||
|
||||
router.route('/:userId')
|
||||
.get(user.get)
|
||||
.put(requirePermission("update_users"), user.update)
|
||||
.delete(requirePermission("delete_users"), user.delete);
|
||||
|
||||
module.exports = router;
|
||||
Reference in New Issue
Block a user