benfluleck/HelloBooks

View on GitHub
server/src/controllers/books.js

Summary

Maintainability
B
4 hrs
Test Coverage
import models from '../models';
import pagination from '../controllers/helpers/pagination';

const { Categories, Books, UserBooks } = models;

export default {
  /**
   * Route: POST: /books
   *
   * @description add a book
   *
   * @param {object} req - request object
   *
   * @param {object} res - respond object
   *
   * @returns {object} book
   *
   * @returns {string} message - returns message
   *
   * @memmberOf BookController
  */
  addBook(req, res) {
    Categories
      .findOne({
        where: {
          id: req.body.categoryId
        }
      })
      .then((foundCategory) => {
        if (!foundCategory) {
          return res
            .status(404)
            .send({ message: 'Category does not exist' });
        }
        Books.findOne({
          where: {
            $and: [
              {
                title: req.body.title
              }, {
                author: req.body.author
              }
            ]
          }
        }).then((bookExists) => {
          if (bookExists !== null) {
            return res
              .status(409)
              .send({
                message:
                'A book with the same title ' +
                 'and author already exists in the library'
              });
          }
          Books
            .create({
              title: req.body.title,
              author: req.body.author,
              quantity: req.body.quantity,
              categoryId: req.body.categoryId,
              description: req.body.description,
              bookImage: req.body.bookImage || process.env.DEFAULT_BOOK_COVER

            })
            .then((newBook) => {
              newBook
                .getCategory()
                .then((category) => {
                  const createdBook = {
                    title: newBook.title,
                    category: category.categoryName,
                    author: newBook.author,
                    description: newBook.description,
                    bookImage: newBook.bookImage
                  };
                  res
                    .status(201)
                    .send({
                      message: `${createdBook.title} ` +
                    `has been added to the library,` +
                    `Category: ${createdBook.category}`,
                      createdBook
                    });
                });
            })
            .catch(error => res.status(400).send(error.message));
        });
      });
  },

  /**
   * Route: PUT: /books/:bookId
   *
   * @description update a book
   *
   * @param {object} req - request object
   *
   * @param {object} res - respond object
   *
   * @returns {object} book - book object
   *
   * @returns {string} message
   *
   * @memmberOf BookController
   */
  updateBook(req, res) {
    return Books
      .findById(req.params.bookId)
      .then((book) => {
        if (req.params.bookId === null) {
          return res
            .send(404)
            .send({ success: false, message: 'No book selected' });
        }
        if (!book) {
          return res
            .status(404)
            .send({ message: 'Book does not exist in this database' });
        }
        Books.findOne({
          where: {
            $and: [
              {
                title: req.body.title
              }, {
                author: req.body.author
              }
            ]
          }
        }).then((bookExists) => {
          if (bookExists !== null &&
            bookExists.id !== parseInt(req.params.bookId, 10)) {
            return res
              .status(409)
              .send({
                message: 'A book with the same title and' +
                'author already exists in the library'
              });
          }
          return book
            .updateAttributes(req.body, {
              fields: Object.keys(req.body)
            })
            .then((editedBook) => {
              editedBook
                .getCategory()
                .then((category) => {
                  const updatedBook = {
                    title: editedBook.title,
                    category: category.categoryName,
                    author: editedBook.author,
                    description: editedBook.description,
                    bookImage: editedBook.bookImage
                  };
                  res
                    .status(200)
                    .send({
                      message: `${updatedBook.title} has been updated`,
                      updatedBook
                    });
                });
            });
        }).catch(error => res.status(400).send(error.message));
      });
  },
  /**
   * Route: GET: /books
   *
   * @description returns a list of all books
   *
   * @param {object} req - request object
   *
   * @param {object} res - respond object
   *
   * @returns {object} books
   *
   * @returns {object} pagination
   *
   * @memmberOf BookController
   */
  getAllBooks(req, res) {
    const offset = req.query.offset || 0;
    const limit = req.query.limit || 3;
    return Books
      .findAndCountAll({
        limit,
        offset,
        attributes: [
          'id',
          'title',
          'author',
          'categoryId',
          'description',
          'bookImage'
        ],
        order: [
          ['createdAt', 'DESC']
        ]
      })
      .then((books) => {
        if (books.count === 0) {
          res.json({
            error: 'Empty',
            message: 'There are no books present in the database'
          });
        } else {
          res
            .status(200)
            .send({
              books: books.rows,
              pagination: pagination(offset, limit, books)
            });
        }
      })
      .catch(error => res.status(501).send(error.message));
  },
  /**
   * Route: GET: /books/search
   *
   * @description returns a list of all books that match the search criteria
   *
   * @param {object} req - request object
   *
   * @param {object} res - respond object
   *
   * @returns {object} books - booksFound
   *
   * @memmberOf BookController
   */
  searchBooks(req, res) {
    const searchQuery = req.query.searchTerm || null;
    const categoryId = req.query.categoryId || null;
    const offset = req.query.offset || 0;
    const limit = req.query.limit || 8;
    const whereSearch = {
      $or: [
        {
          title: {
            $iLike: `%${searchQuery}%`
          }
        }, {
          author: {
            $iLike: `%${searchQuery}%`
          }
        }
      ]
    };
    if (categoryId) {
      whereSearch.$and = [{
        categoryId
      }];
    }
    if (searchQuery === null) {
      return res
        .status(400)
        .send({ message: 'Please enter your search criteria' });
    }
    if (searchQuery.length > 0) {
      Books.findAndCountAll({
        where: whereSearch,
        include: [
          {
            model: Categories,
            as: 'category',
            attributes: ['categoryName'],
            paranoid: false
          }
        ],
        limit,
        offset
      }).then((books) => {
        const booksFound = {
          books: books.rows,
          pagination: pagination(offset, limit, books)
        };
        if (books.rows.length === 0) {
          return res
            .status(404)
            .send({ message: 'Sorry no books match your search criteria' });
        }
        return res
          .status(200)
          .send({ success: true, booksFound });
      }).catch(error => res.status(500).send(error.message));
    }
  },

  /** displays the book matching the bookId parameters
   *
   * @param {object} req - request object
   *
   * @param {object} res - respond object
   *
   * @returns {object} selectedBook
     */
  viewBookDetails(req, res) {
    const bookId = parseInt(req.params.bookId, 10);
    if (isNaN(bookId)) {
      return res
        .status(400)
        .send({ message: 'Please enter a valid bookId' });
    }
    Books
      .findById(bookId, {
        include: [
          {
            model: Categories,
            as: 'category',
            attributes: ['categoryName']
          }
        ]
      })
      .then((book) => {
        if (!book) {
          return res
            .status(404)
            .send({ message: 'This book does not exist in the library' });
        }
        const selectedBook = {
          success: true,
          book
        };
        res
          .status(200)
          .send(selectedBook);
      })
      .catch(error => res.status(500).send(error.message));
  },

  /** deletes the book matching the booKId parameters
   *
   * @param {object} req - request object
   *
   * @param {object} res - respond object
   *
   * @returns {string} message
     */
  deleteBook(req, res) {
    const bookId = parseInt(req.params.bookId, 10);
    if (isNaN(bookId)) {
      return res
        .status(400)
        .send({ message: 'Please enter a valid bookId' });
    }
    Books
      .findById(bookId)
      .then((book) => {
        if (!book) {
          return res
            .status(404)
            .send({ message: 'Book does not exist' });
        }
        UserBooks.findOne({
          where: {
            $and: [
              {
                bookId
              }, {
                returnStatus: false
              }
            ]
          }
        }).then((borrowedBooks) => {
          if (borrowedBooks) {
            return res
              .status(409)
              .send({
                message: 'You can\'t delete this ' +
                'book while there is a copy still out on loan'
              });
          }
          book
            .destroy()
            .then(() => res.status(200).send({
              message: `${book.title} has been deleted`,
              deletedBookId: bookId
            }));
        });
      })
      .catch(error => res.status(500).send(error.message));
  }
};