Skip to content

Commit

Permalink
Merge 327c662 into d0478e1
Browse files Browse the repository at this point in the history
  • Loading branch information
danprocoder committed Mar 2, 2019
2 parents d0478e1 + 327c662 commit 9a1901b
Show file tree
Hide file tree
Showing 6 changed files with 160 additions and 14 deletions.
73 changes: 65 additions & 8 deletions server/controllers/article.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,29 @@
/* eslint-disable max-len */
/* eslint-disable valid-jsdoc */
import slugify from 'slug';
import { validationResult } from 'express-validator/check';
import response, { validationErrors } from '../utils/response';
import db from '../database/models';

const { Article } = db;
const { Article, User } = db;

/**
* @class ArticleController
* @exports ArticleController
*/
class ArticleController {
/**
* Creates a new
*
* @param {object} req The request object
* @param {object} res The response object
*/
constructor() {
this.defaultLimit = 20;
}

/**
* @method create
* @description Creates a new
* @param {object} req - The request object
* @param {object} res - The response object
* @returns {null} - Returns nothing
*/
create(req, res) {
const errors = validationResult(req);
Expand All @@ -26,23 +39,23 @@ class ArticleController {

// Insert into database
Article.create({
userId: 2,
userId: req.user.id,
title,
description,
body,
}).then((article) => {
slug = slug.concat(`-${article.id}`);
article.slug = slug;

// Append id to slug and update.
// Append id to slug and update.
return Article.update({
slug,
}, {
where: {
id: article.id,
}
}).then(dbRes => article);
}).then(article => {
}).then((article) => {
article.userId = undefined;

response(res).created({
Expand All @@ -51,6 +64,50 @@ class ArticleController {
});
}
}

/**
* @method getAll
* @param {object} req The request object from the route
* @param {object} res The response object from the route
*/
getAll(req, res) {
let limit = this.defaultLimit; // Default limit.
let offset = 0; // Default offset.

const { query } = req;
// If limit is specified.
if (query.limit) {
limit = query.limit;
}
// If page is specified.
if (query.page) {
offset = (query.page - 1) * limit;
}

const sequelizeOptions = {
where: {},
offset, // Default is page 1
limit,
include: [{
model: User,
attributes: ['username', 'bio', 'image'],
}],
attributes: ['id', 'slug', 'title', 'description', 'body', 'totalClaps', 'createdAt', 'updatedAt'],
};

// If query author=? is in url, filter by author.
if (query.author) {
sequelizeOptions.where['$User.username$'] = query.author;
}

Article
.findAll(sequelizeOptions)
.then((articles) => {
response(res).success({
articles,
});
});
}
}

export default ArticleController;
2 changes: 1 addition & 1 deletion server/controllers/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ export default class Users {
};
try {
const createUser = await User.create(formInputs);
const token = HelperUtils.generateToken(formInputs);
const token = HelperUtils.generateToken({ ...formInputs, id: createUser.id });
const name = typeof username !== 'undefined' ? username : `${lastname}, ${firstname}`;
HelperUtils.sendMail(
email,
Expand Down
4 changes: 3 additions & 1 deletion server/database/models/article.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ export default (sequelize, DataTypes) => {
slug: DataTypes.STRING,
}, {});
Article.associate = (models) => {
// associations can be defined here
Article.belongsTo(models.User, {
foreignKey: 'userId',
});
};
return Article;
};
3 changes: 3 additions & 0 deletions server/database/models/user.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ export default (sequelize, DataTypes) => {
}, {});
User.associate = (models) => {
// associations can be defined here
User.hasMany(models.Article, {
foreignKey: 'id',
});
};
return User;
};
6 changes: 4 additions & 2 deletions server/routes/articles.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ const router = express.Router();
const controller = new ArticleController();

router.post('/articles',
AuthenticateUser.verifyUser,
createArticleValidation,
AuthenticateUser.verifyUser, // User must be logged in first
createArticleValidation, // Validate user input
controller.create.bind(controller));

router.get('/articles', controller.getAll.bind(controller));

export default router;
86 changes: 84 additions & 2 deletions server/test/articles.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ let token = null;
describe('Testing articles endpoint', () => {

// Register a user to get jwt token.
it('It should create a new user', (done) => {
it('should create a new user', (done) => {
const data = {
firstname: 'Great',
lastname: 'Author',
Expand All @@ -45,7 +45,7 @@ describe('Testing articles endpoint', () => {
});

// Test creating article.
it('It should create a new article', (done) => {
it('should create a new article', (done) => {
const data = {
title: 'This is an article',
description: 'This is the description of the article',
Expand All @@ -69,4 +69,86 @@ describe('Testing articles endpoint', () => {
done();
});
});

// Test endpoint to get all articles.
describe('Test endpoint to get all articles.', () => {
let pageOneFirstArticle = null;

it('should get an array containing the article created above', (done) => {
chai
.request(app)
.get('/api/articles')
.end((err, res) => {
expect(res.status).to.equal(200);

const { articles } = res.body;
expect(articles).to.be.an('array');
expect(articles.length).to.be.at.least(1);

pageOneFirstArticle = articles[0];

done();
});
});

// Test limit.
it('should return an empty array given limit is 0', (done) => {
chai
.request(app)
.get('/api/articles?limit=0')
.end((err, res) => {
expect(res.status).to.equal(200);

const { articles } = res.body;
expect(articles).to.be.an('array');
expect(articles.length).to.equal(0);

done();
});
});

// The second article article will be used to test pagination
it('should create another article', (done) => {
chai
.request(app)
.post('/api/articles')
.set('authorization', `Bearer ${token}`)
.send({
title: 'The second article',
description: 'This is the description of the second article',
body: 'Welcome to the second article',
})
.end((err, res) => {
expect(res.status).to.equal(201);

done();
});
});

// Test pagination.
it('should return the articles on page 2', (done) => {
chai
.request(app)
.get('/api/articles?page=2&limit=1')
.end((err, res) => {
expect(res.status).to.equal(200);

const { articles } = res.body;
expect(articles).to.be.an('array');

expect(articles).to.satisfy((articles) => {
if (articles.length === 0) { // Assuming there is nothing on page 2
return true;
} else {
// Given that page=2 and limit=1, the id of first item on page 2 should 1 greater than
// the id of the first element on page 1 since the table contains only the 2
// articles created in this test file.
return articles[0].id === (pageOneFirstArticle.id + 1);
}
});

done();
});
});
});
});

0 comments on commit 9a1901b

Please sign in to comment.