Skip to content

Commit

Permalink
feat(comment): user can comment
Browse files Browse the repository at this point in the history
- add article routes
- add seed to initialise a user, category and article
- create controller to handle comment posts
- create middleware validate user comments
- update documentation to capture new route
- write tests to test endpoint functionality
- refactor usersValidations to confirm with ES6 syntax and not to send descriptive errors when logging in

[Delivers ##159987407]

feat(comment): user can comment

- add article routes
- add seed to initialise a user, category and article
- create controller to handle comment posts
- create middleware validate user comments
- update documentation to capture new route
- write tests to test endpoint functionality

[Delivers ##159987407]

feat(comment): user can comment

- add article routes
- add seed to initialise a user, category and article
- create controller to handle comment posts
- create middleware validate user comments
- update documentation to capture new route
- write tests to test endpoint functionality
- refactor usersValidations to confirm with ES6 syntax and not to send descriptive errors when logging in

[Delivers ##159987407]
  • Loading branch information
tomiadebanjo authored and jamesenejo committed Sep 7, 2018
1 parent b37f5d4 commit a5b2603
Show file tree
Hide file tree
Showing 13 changed files with 303 additions and 60 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"description": "A Social platform for the creative at heart",
"main": "app.js",
"scripts": {
"pretest": "NODE_ENV=test sequelize db:migrate",
"pretest": "NODE_ENV=test sequelize db:migrate && sequelize db:seed:all",
"test": "NODE_ENV=test nyc mocha --exit --require babel-core/register",
"posttest": "NODE_ENV=test sequelize db:migrate:undo:all",
"start": "babel-node server/app.js",
Expand Down
2 changes: 2 additions & 0 deletions server/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import swaggerUi from 'swagger-ui-express';
import jsend from 'jsend';
import swaggerDocument from '../swagger.json';
import userRoutes from './routes/userRoutes';
import articlesRoutes from './routes/articlesRoutes';

const app = express();
const urlencoded = bodyParser.urlencoded({ extended: false });
Expand All @@ -25,6 +26,7 @@ app.use(urlencoded);
app.use(json);

app.use('/api/v1/users', userRoutes);
app.use('/api/v1/articles', articlesRoutes);

app.get('/', (req, res) => res.status(200).jsend.success({
message: 'Welcome to the sims program'
Expand Down
31 changes: 31 additions & 0 deletions server/controllers/commentsController.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import validator from 'validator';
import models from '../models/index';

const { Users, Comments } = models;

const commentsController = {
create: (req, res) => {
const { articleId } = req.params;
const { content } = req.body;
const userId = req.currentUser.id;

const userComment = {
content: validator.escape(content.trim()),
articleId: validator.escape(articleId),
userId
};

Comments
.create(userComment)
.then(comment => Users.findById(userId, {
attributes: ['id', 'username', 'firstname', 'lastname', 'createdAt', 'updatedAt']
})
.then(user => res.status(201).jsend.success({ user, comment })))
.catch(error => res.status(500).jsend.error({
message: 'There was a problem processing your request',
error
}));
}
};

export default commentsController;
22 changes: 22 additions & 0 deletions server/middleware/articlesValidations.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import helpers from '../helpers/helpers';

const articlesValidations = {
/** @description This method validates users' comments and replies
* @param {object} req The request object
* @param {object} res The response object
* @param {object} next the next middleware
* @returns {object} json response
*/

validateComments: (req, res, next) => {
const { content } = req.body;
const { validString } = helpers;

if (!validString(content)) {
return res.status(400).jsend.fail('Comment is empty');
}
return next();
}
};

export default articlesValidations;
4 changes: 2 additions & 2 deletions server/middleware/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ const auth = (req, res, next) => {
message: 'Failed to authenticate token! Valid token required',
});
}
req.currentUser = decoded.id;
next();
req.currentUser = decoded;
return next();
});
};

Expand Down
55 changes: 19 additions & 36 deletions server/middleware/usersValidations.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
import helper from '../helpers/helpers';
import helpers from '../helpers/helpers';

const {
checkProps,
validEmail,
validPassword,
validString
} = helpers;

const usersValidations = {
/** @description This method helps validate a user signups
Expand All @@ -12,8 +19,9 @@ const usersValidations = {
let messages = [];

// Check the passed body for required properties
const { valid, invalidMessages } = helper
.checkProps(req.body, 'username', 'email', 'password');
const {
valid, invalidMessages
} = checkProps(req.body, 'username', 'email', 'password');

if (!valid) {
return res.status(400)
Expand All @@ -23,21 +31,20 @@ const usersValidations = {
}

// Validate the email address provided
if (!helper.validEmail(req.body.email)) {
if (!validEmail(req.body.email)) {
status = 'fail';
messages.push('Invalid email provided');
}


// Validate the password provided
if (!helper.validPassword(req.body.password).valid) {
if (!validPassword(req.body.password).valid) {
status = 'fail';
messages = messages
.concat(helper.validPassword(req.body.password).invalidMessages);
.concat(validPassword(req.body.password).invalidMessages);
}

// validate the firstName;
if (!helper.validString(req.body.username)) {
if (!validString(req.body.username)) {
status = 'fail';
messages.push('username cannot be an empty string');
}
Expand All @@ -59,38 +66,14 @@ const usersValidations = {
* @returns {object} undefined
*/
validateLogin: (req, res, next) => {
let status = 'success';
let messages = [];

// Check the passed body for required properties
const { valid, invalidMessages } = helper
const { valid, invalidMessages } = helpers
.checkProps(req.body, 'email', 'password');

if (!valid) {
return res.status(400)
.jsend.fail({
messages: invalidMessages
});
}

// Validate the email address provided
if (!helper.validEmail(req.body.email)) {
status = 'fail';
messages.push('Invalid email provided');
}


// Validate the password provided
if (!helper.validPassword(req.body.password).valid) {
status = 'fail';
messages = messages.concat(helper.validPassword(req.body.password).invalidMessages);
}

if (status === 'fail') {
return res.status(400)
.jsend.fail({
messages
});
return res.status(400).jsend.fail({
messages: invalidMessages
});
}
return next();
}
Expand Down
13 changes: 13 additions & 0 deletions server/routes/articlesRoutes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import express from 'express';
import commentsController from '../controllers/commentsController';
import articlesValidations from '../middleware/articlesValidations';
import auth from '../middleware/auth';

const articlesRoutes = express.Router();

const { create } = commentsController;
const { validateComments } = articlesValidations;

articlesRoutes.post('/:articleId', auth, validateComments, create);

export default articlesRoutes;
17 changes: 17 additions & 0 deletions server/seeders/20180905193504-demo-user.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module.exports = {
up: queryInterface => queryInterface.bulkInsert('Users', [{
username: 'johndoe',
firstname: 'John',
lastname: 'Doe',
email: 'johndoe@gmail.com',
password: 'johndoe',
bio: 'I like to eat',
image: 'someimgurl',
premium: true,
isVerified: true,
interests: ['Entertainment', 'Science'],
createdAt: '2018-09-05',
updatedAt: '2018-09-05'
}]),
down: queryInterface => queryInterface.bulkDelete('Users')
};
8 changes: 8 additions & 0 deletions server/seeders/20180905193524-categories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = {
up: queryInterface => queryInterface.bulkInsert('Categories', [{
name: 'Science',
createdAt: '2018-09-05',
updatedAt: '2018-09-05'
}]),
down: queryInterface => queryInterface.bulkDelete('Categories')
};
13 changes: 13 additions & 0 deletions server/seeders/20180905195555-demo-article.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module.exports = {
up: queryInterface => queryInterface.bulkInsert('Articles', [{
slug: 'slug-here',
title: 'My Life',
description: 'About my life',
body: 'This is the content of the story of my life',
userId: 1,
categoryId: 1,
createdAt: '2018-09-05',
updatedAt: '2018-09-05'
}]),
down: queryInterface => queryInterface.bulkDelete('Articles')
};
40 changes: 39 additions & 1 deletion swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,33 @@
}
}
}
}
},
"/api/v1/articles/:articleId": {
"post": {
"tags": [ "Articles" ],
"summary": "Route for authenticated users to post comments on an article",
"description": "Returns the user and the user's comment",
"parameters": [
{
"in": "body",
"name": "body",
"description": "comment object to be returned when a user makes a post request",
"required": true,
"schema": {
"$ref": "#/definitions/Comment"
}
}
],
"responses": {
"201": {
"description": "Comment posted successfully"
},
"400": {
"description": "Comment is empty"
}
}
}
}
},
"definitions": {
"Signup": {
Expand Down Expand Up @@ -131,6 +157,18 @@
"json": {
"name": "User"
}
},
"Comment": {
"type": "object",
"properties": {
"content": {
"type": "string",
"example": "Great post!"
}
},
"json": {
"name": "Comment"
}
}
}
}
103 changes: 103 additions & 0 deletions test/test.articles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import chai from 'chai';
import chaiHttp from 'chai-http';
import app from '../server/app';

chai.use(chaiHttp);
const { should } = chai;
should();

let token;

describe('Tests for Articles', () => {
describe('Create comment tests', () => {
before((done) => {
chai
.request(app)
.post('/api/v1/users/auth/signup')
.send({
username: 'enjames',
email: 'enjames@james.com',
password: 'pasS1234',
})
.end((err, res) => {
token = res.body.data.token;
res.body.should.have.property('data');
done();
});
});

it('User should not be able to comment if not authenticated', (done) => {
chai
.request(app)
.post('/api/v1/articles/1')
.send({
content: 'Your post was not inspiring.'
})
.end((err, res) => {
res.body.status.should.equal('error');
res.body.message.should.equal('No token provided');
done();
});
});

it('User should receive an error if authentication fails', (done) => {
chai
.request(app)
.post('/api/v1/articles/1')
.set('Authorization', '8beccb8ef75986c7096888907ddf4165889255315b67be782a3333eeeeee')
.send({
content: 'Your post was not inspiring.'
})
.end((err, res) => {
res.body.status.should.equal('error');
res.body.message.should.equal('Failed to authenticate token! Valid token required');
done();
});
});

it('It should return an object containing a user and a comment object', (done) => {
chai
.request(app)
.post('/api/v1/articles/1')
.set('Authorization', token)
.send({
content: ''
})
.end((err, res) => {
res.body.status.should.equal('fail');
res.body.data.should.equal('Comment is empty');
done();
});
});

it('It should return an object containing a user and a comment object', (done) => {
chai
.request(app)
.post('/api/v1/articles/1')
.set('Authorization', token)
.send({
content: 'Your post was not inspiring.'
})
.end((err, res) => {
res.body.data.should.have.property('user');
res.body.data.comment.content.should.equal('Your post was not inspiring.');
done();
});
});

it('It should return an object containing a user and a comment object', (done) => {
chai
.request(app)
.post('/api/v1/articles/13431')
.set('Authorization', token)
.send({
content: 'Your post was not inspiring.'
})
.end((err, res) => {
res.body.status.should.equal('error');
res.body.message.should.equal('There was a problem processing your request');
done();
});
});
});
});
Loading

0 comments on commit a5b2603

Please sign in to comment.