src/controllers/BeerController.js
// Import the neccesary modules.
import { Types } from 'mongoose';
import Beer from '../models/beer';
import User from '../models/user';
import { pageSize } from '../config/constants';
/** Class for CRUD operations for beers. */
export default class BeerController {
/** Create a new BeerController object */
constructor() {
/**
* The projection used for getting multiple beers.
* @type {Object}
*/
BeerController._projection = {
name: 1,
style: 1,
type: 1,
abv: 1,
ebu: 1
};
}
/**
* Attatch a beer object to the req.
* @param {Request} req - The express request object.
* @param {Response} res - The express response object.
* @param {function} next - The next function for Express.
* @param {String} id - The id of the beer to attach.
* @returns {Response} - A request with a beer object attatched.
*/
preLoadBeer(req, res, next, id) {
return Beer.findOne({
_id: id
}).then(beer => {
if (!beer) return next(new Error('Can\'t find beer!'));
req.beer = beer;
return next();
}).catch(err => res.json(err));
}
/**
* Get a list of beers based on the page number and search query.
* @param {Request} req - The express request object.
* @param {Response} res - The express response object.
* @param {function} next - The next function for Express.
* @returns {JSON} - Get a list of beers.
*/
getBeers(req, res, next) {
const query = {};
const data = req.query;
const page = data.page ? data.page - 1 : 0;
const offset = page * pageSize;
data.order = data.order ? parseInt(data.order, 10) : -1;
let sort = {
name: data.order
};
if (data.search) {
const words = data.search.split(' ');
let regex = '^';
for (const w in words) {
words[w] = words[w].replace(/[^a-zA-Z0-9]/g, '');
regex += `(?=.*\\b${RegExp.escape(words[w].toLowerCase())}\\b)`;
}
query.name = {
$regex: new RegExp(`${regex}.*`),
$options: 'gi'
};
}
if (data.sort) {
if (data.sort.match(/name/i)) sort = {
name: data.order
};
if (data.sort.match(/style/i)) sort = {
style: data.order
};
if (data.sort.match(/type/i)) sort = {
type: data.order
};
if (data.sort.match(/abv/i)) sort = {
abv: data.order
};
if (data.sort.match(/ebu/i)) sort = {
ebu: data.order
};
}
return Beer.aggregate([{
$sort: sort
}, {
$match: query
}, {
$project: BeerController._projection
}, {
$skip: offset
}, {
$limit: pageSize
}]).exec()
.then(docs => res.json(docs))
.catch(err => next(err));
}
/**
* Get a beer based on the id.
* @param {Request} req - The express request object.
* @param {Response} res - The express response object.
* @param {function} next - The next function for Express.
* @returns {JSON} - A beer based on the given id.
*/
getBeer(req, res, next) {
return Beer.findOne({
_id: new Types.ObjectId(req.params.beer)
}).exec()
.then(beer => res.json(beer))
.catch(err => next(err));
}
/**
* Create update an existing beer or create a new beer if not exists.
* @param {Request} req - The express request object.
* @param {Response} res - The express response object.
* @param {function} next - The next function for Express.
* @returns {JSON} - The created or updated beer.
*/
createBeer(req, res, next) {
const { name, style, type, abv, ebu, thumbnail } = req.body;
const beer = new Beer({
name,
style,
type,
abv,
ebu,
thumbnail
})
beer.user = req.payload.username;
return beer.save(err => {
if (err) return next(err);
return res.json(beer)
});
}
/**
* Create update an existing beer or create a new beer if not exists.
* @param {Request} req - The express request object.
* @param {Response} res - The express response object.
* @param {function} next - The next function for Express.
* @returns {JSON} - The updated beer.
*/
updateBeer(req, res, next) {
const { name, style, type, abv, ebu, thumbnail } = req.body;
return Beer.findOneAndUpdate({
_id: new Types.ObjectId(req.params.beer),
user: req.payload.username
}, {
name,
style,
type,
abv,
ebu,
thumbnail
}, {
new: true
}).exec()
.then(beer => res.json(beer))
.catch(err => next(err));
}
/**
* Delete an beer based on the id.
* @param {Request} req - The express request object.
* @param {Response} res - The express response object.
* @param {function} next - The next function for Express.
* @returns {JSON} - The deleted beer.
*/
deleteBeer(req, res, next) {
return Beer.findOneAndRemove({
_id: new Types.ObjectId(req.params.beer),
user: req.payload.username
}).exec()
.then(beer => res.json(beer))
.catch(err => next(err))
}
/**
* Upvote or downvote an beer based on the id.
* @param {Request} req - The express request object.
* @param {Response} res - The express response object.
* @param {function} next - The next function for Express.
* @returns {JSON} - The voted beer.
*/
voteBeer(req, res, next) {
return User.findOne({
username: req.payload.username
}).exec().then(user => {
const beer = user.beers.find(el => el === req.beer.name);
if (beer) {
return user.removeBeer(req.beer)
.then(() => req.beer.downvote())
.then(newBeer => res.json(newBeer));
}
return user.addBeer(req.beer)
.then(() => req.beer.upvote())
.then(newBeer => res.json(newBeer));
}).catch(err => next(err));
}
}