server/src/controllers/userBooks.js
import { toDate } from 'validator';
import models from '../models';
import pagination from '../controllers/helpers/pagination';
const {
User, Books, Userlevel, UserBooks, Notifications
} = models;
export default {
/**
* Route: POST: /users/loanbook
*
* @description Loan a book
*
* @param {object} req - request object
*
* @param {object} res - respond object
*
* @returns {object} message
*
* @memmberOf UserBooks Controller
*/
loanBook(req, res) {
const userId = req.user.id.id || req.user.id;
const { bookId } = req.body;
if (!req.body.returnDate) {
return res
.status(404)
.send({ message: 'Please specify a valid return date' });
}
if (toDate(req.body.returnDate) <= (Date.now() - (24 * 60 * 60 * 1000))) {
return res
.status(422)
.send({ message: 'Please provide a valid return date' });
}
const returnDate = new Date(req.body.returnDate);
User
.findById(
userId,
{
include: [{
model: Userlevel,
as: 'level',
attributes: ['levelName', 'maxBooks', 'maxDays']
}]
}
)
.then((user) => {
const userLevelDate = new Date(Date.now() +
(user.level.maxDays * (24 * 60 * 60 * 1000)));
if (!user) {
return res
.status(404)
.send({
message: 'User does not exist, Please register to borrow'
});
}
if (returnDate > userLevelDate) {
return res
.status(409)
.send({
message: 'To loan this book for more days,' +
' You need to upgrade your user level,' +
'Please contact the administrator'
});
}
if (user.borrowCount > user.level.maxBooks) {
return res.status(400)
.send({
message:
'You have exceeded your borrow limit, Why not return a book'
});
}
user.update({
borrowCount: (user.borrowCount + 1)
});
UserBooks.findOne({
where: {
userId,
bookId,
returnStatus: false
},
include: [
{
model: Books,
as: 'book',
required: true
}
]
}).then((bookFound) => {
if (bookFound) {
return res
.status(409)
.send({
success: false,
message: 'You have already borrowed this book'
});
}
UserBooks
.create({
userId,
bookId,
returnDate
})
.then(() => {
Books
.findOne({
where: {
id: bookId
}
})
.then((bookToBorrow) => {
if (!bookToBorrow || bookToBorrow.quantity === 0) {
return res
.status(404)
.send({
success: false,
message: "Sorry we can't find this book or " +
'all copies of this book are on loan'
});
}
bookToBorrow
.update({
quantity: (bookToBorrow.quantity -= 1)
});
Notifications.create({
userId,
bookId,
action: 'Book Borrowed',
})
.then(() => {
const borrowedBook = {
username: user.username,
book: bookToBorrow.title,
borrowed: bookToBorrow.createdAt,
expectedReturnDate: bookToBorrow.returnDate,
userLevel: user.level.levelName
};
res
.status(200)
.send({
message: `${borrowedBook.book} successfully loaned`
});
});
});
});
});
})
.catch((error) => {
res
.status(500)
.send({ success: false, message: ` ${error.message}` });
});
},
/**
* Route: GET: /users/getborrowedBooklist
*
* @description Get list of borrowed books
*
* @param {object} req - request object
*
* @param {object} res - respond object
*
* @returns {object} book list
*
* @memmberOf UserBooks Controller
*/
getBorrowedBookList(req, res) {
const offset = req.query.offset || 0;
const limit = req.query.limit || 3;
const userId = req.user.id.id || req.user.id;
if (!req.query.returned) {
return res
.status(404)
.send({ message: 'Please specify a value for returned books' });
}
return UserBooks.findAndCountAll({
where: {
userId,
returnStatus: req
.query
.returned
.trim()
},
include: [
{
model: Books,
as: 'book',
required: true
}
],
limit,
offset
}).then((book) => {
if (book.length === 0) {
return res
.status(404)
.send({ success: false, message: 'You have not loaned any books' });
}
res
.status(200)
.send({
books: book.rows,
pagination: pagination(offset, limit, book)
});
}).catch(error => res.status(400).send(error.message));
},
/**
* Route: PUT: /users/returnbook
*
* @description Return a book
*
* @param {object} req - request object
*
* @param {object} res - response object
*
* @returns {object} book - returned book
*
* @memmberOf UserBooks Controller
*/
returnBook(req, res) {
const userId = req.user.id.id || req.user.id;
const bookId = req.body.bookId;
UserBooks.findOne({
where: {
bookId,
userId,
returnStatus: false
},
include: [
{
model: Books,
as: 'book',
required: true
}
]
}).then((history) => {
if (!history) {
return res
.status(409)
.send({ message: 'You did not borrow this book' });
}
history.update({
returnStatus: true,
userReturnDate: Date.now()
}, {
where: {
userId,
bookId
}
}).then(() => {
Books
.findOne({
where: {
id: bookId
}
})
.then((bookToReturn) => {
if (!bookToReturn) {
return res
.status(404)
.send({ message: 'The book is not in our library' });
}
bookToReturn
.update({
quantity: bookToReturn.quantity + 1
});
User.findById(userId)
.then((user) => {
user.update({
borrowCount: (user.borrowCount - 1),
});
Notifications.create({
userId,
bookId: history.bookId,
action: 'Book Returned',
}).then(() => {
const returnDetail = {
username: user.username,
id: bookToReturn.id,
book: bookToReturn.title,
expectedReturnDate: history.returnDate,
returnedOn: history.userReturnDate
};
if (returnDetail.expectedReturnDate <
(returnDetail.returnedOn - (24 * 60 * 60 * 1000))) {
res
.status(200)
.send({
message:
`You have just returned ${returnDetail.book}
late, A fine will be sent to your registered email`,
returnedBook: returnDetail
});
} else {
res
.status(200)
.send({
message: `You have just returned ${returnDetail.book}`,
returnedBook: returnDetail
});
}
});
});
});
});
}).catch(error => res.status(500).send(error.message));
},
/**
* Route: GET: /users/overduebooks
*
* Method to get all overdue books from the library
* @param {Object} req - request object
*
* @param {Object} res - response object
*
* @return {string} message - returns message from overdue books
*
* @return {Object} books
*
* @return {object} pagination - returns pagination
*
*/
getOverdueBooks(req, res) {
const offset = req.query.offset || 0;
const limit = req.query.limit || 3;
const userId = req.user.id.id || req.user.id;
return UserBooks.findAndCountAll({
where: {
userId,
returnStatus: false,
returnDate: {
$lt: (Date.now() - (24 * 60 * 60 * 1000))
}
},
include: [
{
model: Books,
as: 'book',
required: true
}
],
limit,
offset
})
.then((book) => {
if (book.length === 0) {
return res
.status(404)
.send({ message: 'You have no overdue books' });
}
res
.status(200)
.send({
books: book.rows,
pagination: pagination(offset, limit, book)
});
}).catch(error => res.status(500).send(error.message));
},
/**
* Route: GET: /users/userhistory
*
* Method to get all the loan history
*
* @param {Object} req - request object
*
* @param {Object} res - response object
*
* @return {string} message - returns message
*
* @return {Object} books
*
* @return {object} pagination - returns pagination
*
*/
getLoanHistory(req, res) {
const offset = req.query.offset || 0;
const limit = req.query.limit || 3;
const userId = req.user.id.id || req.user.id;
return UserBooks.findAndCountAll({
where: {
userId
},
include: [
{
model: Books,
as: 'book',
required: true
}
],
attributes: [
'bookId',
'userId',
'returnDate',
'userReturnDate',
'returnStatus',
'overdueAmount'
],
limit,
offset,
order: [
['createdAt', 'DESC']
]
}).then((book) => {
if (book.length === 0) {
return res
.status(404)
.send({ message: 'You have no books on your loan list' });
}
res
.status(200)
.send({
books: book.rows,
pagination: pagination(offset, limit, book)
});
}).catch(error => res.status(400).send(error.message));
}
};