Skip to content

Commit

Permalink
Merge ca31e83 into b8e6f86
Browse files Browse the repository at this point in the history
  • Loading branch information
Black Developa committed Mar 21, 2019
2 parents b8e6f86 + ca31e83 commit 0bca681
Show file tree
Hide file tree
Showing 10 changed files with 221 additions and 2 deletions.
59 changes: 59 additions & 0 deletions server/controllers/comment-controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import db from '../models';
import {
successResponse,
errorResponse,
validate,
validationErrorResponse
} from '../utils/helpers';
import { commentSchema } from '../utils/validators';

const { Comment, Recipe } = db;

// const userFilter = {
// attributes: {
// include: [],
// exclude: []
// }
// };

/**
* The controllers for comment route
*
* @class CommentController
*/
class CommentController {
/**
* Comment registeration controller
* @static
* @param {*} req Express request object
* @param {*} res Express request object
* @memberof RecipeController
* @returns {undefined}
*/
static async create(req, res) {
const {
params: { slug },
body: { body },
user: { id: userId }
} = req;
try {
await validate(req.body, commentSchema);
const recipe = await Recipe.findOne({ where: { slug } });
if (!recipe) {
return errorResponse(res, 'does not exist', 400);
}
const {
dataValues: { id: recipeId }
} = recipe;
Comment.create({ userId, recipeId, body }, { returning: true })
.then(({ dataValues }) => {
successResponse(res, dataValues, 201);
})
.catch(err => errorResponse(res, err, 400));
} catch (err) {
return validationErrorResponse(res, err.details);
}
}
}

export default CommentController;
23 changes: 23 additions & 0 deletions server/migrations/20190319030801-create-comment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module.exports = {
up: (queryInterface, Sequelize) =>
queryInterface.createTable('Comments', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
body: {
type: Sequelize.TEXT
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
}),
down: (queryInterface /* Sequelize */) => queryInterface.dropTable('Comments')
};
20 changes: 20 additions & 0 deletions server/models/Comment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
module.exports = (sequelize, DataTypes) => {
const Comment = sequelize.define(
'Comment',
{
body: DataTypes.TEXT
},
{}
);
Comment.associate = models => {
Comment.belongsTo(models.Recipe, {
foreignKey: 'recipeId',
onDelete: 'SET NULL'
});
Comment.belongsTo(models.User, {
foreignKey: 'userId',
onDelete: 'SET NULL'
});
};
return Comment;
};
4 changes: 4 additions & 0 deletions server/models/User.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ module.exports = (sequelize, DataTypes) => {
foreignKey: 'userId',
as: 'recipe'
});
User.hasMany(models.Comment, {
foreignKey: 'userId',
as: 'comments'
});
};

return User;
Expand Down
4 changes: 4 additions & 0 deletions server/models/recipe.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ module.exports = (sequelize, DataTypes) => {
foreignKey: 'userId',
onDelete: 'CASCADE'
});
Recipe.hasMany(models.Comment, {
foreignKey: 'recipeId',
as: 'comments'
});
};

return Recipe;
Expand Down
2 changes: 2 additions & 0 deletions server/routes/recipe-routes.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { Router } from 'express';
import controller from '../controllers/recipe-controller';
import User from '../middlewares/users-middleware';
import CommentController from '../controllers/comment-controller';

const router = Router();

router.post('/', User.validUser, controller.create);
router.get('/', controller.getRecipes);
router.get('/:slug', controller.getRecipeBySlug);
router.post('/:slug/comments', User.validUser, CommentController.create);
router.put('/:slug', User.validUser, controller.updateRecipe);
router.delete('/:slug', User.validUser, controller.deleteRecipe);

Expand Down
5 changes: 5 additions & 0 deletions server/utils/validators.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,5 +64,10 @@ export const changePasswordSchema = Joi.object().keys({
password: Joi.string()
.alphanum()
.min(8)
});

export const commentSchema = Joi.object().keys({
body: Joi.string()
.max(1500)
.required()
});
92 changes: 92 additions & 0 deletions test/comments.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import chai, { expect } from 'chai';
import chaiHttp from 'chai-http';
import server from '../server';
import { generateToken } from '../server/utils/helpers';
import { comment, commentTestUser, recipe } from './fixtures';

chai.use(chaiHttp);

const runtimeFixture = {};

describe('Comments', () => {
before(() =>
chai
.request(server)
.post('/api/users')
.send(commentTestUser)
.then(res => {
const { token } = res.body.user;
runtimeFixture.token = token;
})
);
describe('POST /api/recipes/:slug/comments', () => {
before(done => {
chai
.request(server)
.post('/api/recipes')
.set({ authorization: runtimeFixture.token })
.send(recipe)
.end((err, res) => {
const { slug } = res.body.recipe;
runtimeFixture.slug = slug;
done(err);
});
});

it('should create new recipe comment when a token is provided', done => {
chai
.request(server)
.post(`/api/recipes/${runtimeFixture.slug}/comments`)
.set({ authorization: runtimeFixture.token })
.send(comment)
.end((err, res) => {
const { body } = res;
expect(res).to.have.status(201);
expect(body.body).to.equal(body.body);
done(err);
});
});

it('should not create a comment when token is invalid', done => {
chai
.request(server)
.post(`/api/recipes/${runtimeFixture.slug}/comments`)
.set({ authorization: generateToken({ id: 1000 }) })
.send(comment)
.end((err, res) => {
const { body } = res;
expect(res).to.have.status(404);
expect(body.errors).to.contain('User does not exist');
done(err);
});
});

it('should not create a comment when token is absent', done => {
chai
.request(server)
.post(`/api/recipes/${runtimeFixture.slug}/comments`)
.set({})
.send(comment)
.end((err, res) => {
const { body } = res;
expect(res).to.have.status(400);
expect(body.errors).to.contain('Token is not provided');
done(err);
});
});

it('should not create comment when body is not present', done => {
chai
.request(server)
.post(`/api/recipes/${runtimeFixture.slug}/comments`)
.set({ authorization: runtimeFixture.token })
.send()
.end((err, res) => {
const { body } = res;
expect(res).to.have.status(400);
expect(body.errors).to.haveOwnProperty('body');
done(err);
});
});
});
});
10 changes: 10 additions & 0 deletions test/fixtures.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,16 @@ export const recipeTestUser = {
password: 'jakejake'
};

export const commentTestUser = {
username: 'Jacob2',
email: 'jake2@jake.jake',
password: 'jakejake'
};

export const comment = {
body: 'This is a new comment'
};

/**
* generate random user details
* @return {object} random user
Expand Down
4 changes: 2 additions & 2 deletions test/recipes.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ describe('Recipes', () => {

describe('GET /api/recipes', () => {
before(async () => {
await db.Recipe.destroy({ truncate: true });
await db.Recipe.destroy({ truncate: true, cascade: true });
});

describe('Fetching before create', () => {
Expand Down Expand Up @@ -191,7 +191,7 @@ describe('Recipes', () => {

describe('GET api/recipes/:slug', () => {
before(async () => {
await db.Recipe.destroy({ truncate: true });
await db.Recipe.destroy({ truncate: true, cascade: true });
});

describe('Fetching before create', () => {
Expand Down

0 comments on commit 0bca681

Please sign in to comment.