Skip to content

Commit

Permalink
Merge 9d4e45d into 21646e3
Browse files Browse the repository at this point in the history
  • Loading branch information
johngorithm committed Sep 24, 2018
2 parents 21646e3 + 9d4e45d commit 29f1987
Show file tree
Hide file tree
Showing 4 changed files with 291 additions and 8 deletions.
93 changes: 92 additions & 1 deletion server/controllers/articleController.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ const {
Articles,
Ratings,
ArticleLikes,
Tags
Tags,
Users,
Categories,
Comments
} = models;
const { analyseRatings } = ratingHelpers;

Expand Down Expand Up @@ -44,6 +47,7 @@ const articlesController = {
slug: `${slug(fields.title)}-${uuid()}`,
description: fields.description,
body: fields.body,
categoryId: parseInt(fields.categoryId, 10) || 1,
imageUrl
}).then((createdArticle) => {
// checks if tags exist
Expand Down Expand Up @@ -195,6 +199,93 @@ const articlesController = {
}
});
});
},
/**
* @description This returns details of a single article if it exists
* @param {object} req The HTTP request object
* @param {object} res The HTTP response object
* @returns {object} Undefined
*/
getSingleArticle: async (req, res) => {
const articleId = Number(req.params.articleId);

try {
const article = await Articles.findOne({
where: {
id: articleId
},
include: [{
model: Users,
attributes: ['id', 'image', 'username'],
}, {
model: Tags,
as: 'tags',
attributes: ['id', 'name'],
through: {
attributes: []
}
},
{
model: ArticleLikes,
as: 'articleLikes',
attributes: ['id', 'like', 'dislike']
},
{
model: Categories,
as: 'category',
attributes: ['name']
},
{
model: Comments,
as: 'comments',
attributes: ['id']
}]
});

if (!article) {
return res.status(404).jsend.fail({
message: 'Article not found'
});
}

const likes = article.articleLikes.filter(like => like.like === true).length;
const dislikes = article.articleLikes.filter(like => like.dislike === true).length;

const articleData = {
id: article.id,
slug: article.slug,
title: article.title,
body: article.body,
imageUrl: article.imageUrl,
rating: article.rating,
createdDate: article.createdAt,
updatedDate: article.updatedAt
};

const metadata = {
author: {
id: article.User.id,
username: article.User.username,
imageUrl: article.User.image
},
tags: article.tags,
likes,
dislikes,
commentCounts: article.comments.length,
category: article.category
};

return res.status(200).jsend.success({
message: 'Operation successful',
articleData,
metadata
});
} catch (error) {
res.status(500).jsend.fail({
message: 'Oop!, Something went wrong. Please try again',
error: error.message
});
}
}
};

Expand Down
8 changes: 4 additions & 4 deletions server/controllers/userController.js
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ const userController = {
const {
firstname, lastname, username, email, bio,
} = req.body;
const interest = req.body.interest ? req.body.interest.split(',') : null;
const interests = req.body.interests ? req.body.interests.split(',') : null;
const updateUser = (image) => {
const updates = {
firstname,
Expand All @@ -326,7 +326,7 @@ const userController = {
email,
bio,
image,
interest
interests
};
if (!req.file) {
delete updates.image;
Expand Down Expand Up @@ -375,12 +375,12 @@ const userController = {
Users.findOne({ where: { id: userId } })
.then((user) => {
if (!user || user === undefined) {
res.status(404).jsend.fail({
return res.status(404).jsend.fail({
message: 'No user found'
});
}
delete user.password;
res.status(200).jsend.success({
return res.status(200).jsend.success({
message: 'User details',
user
});
Expand Down
10 changes: 7 additions & 3 deletions server/routes/articleRoutes.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ const {
rateArticle,
create,
like,
getArticles
getArticles,
getSingleArticle
} = articleController;
const { addComment } = commentController;
const { validateArticle, validateComments } = inputValidator;
Expand All @@ -35,10 +36,13 @@ const {
} = reportValidation;

const articleRoutes = express.Router();
articleRoutes.get('/', auth, paginationParamsValidations, getArticles);
articleRoutes.get('/search', searchController);

// POST ARTICLE ROUTE
articleRoutes.get('/', auth, paginationParamsValidations, getArticles);
articleRoutes.post('/:articleId', auth, validArticleId, validateComments, addComment);
articleRoutes.get('/:articleId', auth, checkParams.id, getSingleArticle);

articleRoutes.post(
'/:articleId/comments/like',
auth,
Expand All @@ -64,5 +68,5 @@ articleRoutes.post(
validArticleId,
reportArticle
);
articleRoutes.get('/search', searchController);

export default articleRoutes;
188 changes: 188 additions & 0 deletions test/articles.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -212,3 +212,191 @@ describe('Articles likes test', () => {
});
});
});

describe('GET SINGLE ARTICLE TEST', () => {
it('should fail when article is not found', (done) => {
chai
.request(app)
.get('/api/v1/articles/1008790')
.set('authorization', hashedToken)
.send()
.end((err, res) => {
expect(res.body.status).to.equal('fail');
expect(res.status).to.equal(404);
expect(res.body.data.message).to.equal('Article not found');
done();
});
});

it('should return successfully when article is found', (done) => {
chai
.request(app)
.get('/api/v1/articles/2')
.set('authorization', hashedToken)
.end((err, res) => {
res.status.should.equal(200);
res.body.status.should.equal('success');
res.body.data.should.have.property('articleData');
res.body.data.should.have.property('metadata');
res.body.data.should.have.property('message');
res.body.data.articleData.should.have.property('body');
res.body.data.articleData.id.should.equal(2);
done();
});
});
});

describe('GET ARTICLES WITH PAGINATION', () => {
it('should return articles successfully for an authenticated user', (done) => {
chai
.request(app)
.get('/api/v1/articles')
.set('authorization', hashedToken)
.end((err, res) => {
res.body.status.should.equal('success');
res.status.should.equal(200);
res.body.data.articles.should.be.an('Array');
res.body.data.articles.length.should.be.greaterThan(0);
done();
});
});

it('should return articles successfully with current page = 1 when page number is undefined', (done) => {
chai
.request(app)
.get('/api/v1/articles')
.query({ page: undefined, limit: 1 })
.set('authorization', hashedToken)
.end((err, res) => {
res.body.status.should.equal('success');
res.status.should.equal(200);
res.body.data.articles.should.be.an('Array');
res.body.data.articles.length.should.be.greaterThan(0);
res.body.data.metadata.currentPage.should.equal(1);
done();
});
});

it('should return articles successfully with current page = 1 when page number is not a number', (done) => {
chai
.request(app)
.get('/api/v1/articles')
.query({ page: 'kjhs3w', limit: 1 })
.set('authorization', hashedToken)
.end((err, res) => {
res.body.status.should.equal('success');
res.status.should.equal(200);
res.body.data.articles.should.be.an('Array');
res.body.data.articles.length.should.be.greaterThan(0);
res.body.data.metadata.currentPage.should.equal(1);
done();
});
});

it('should return articles successfully with current page = 1, when page number is less than 1', (done) => {
chai
.request(app)
.get('/api/v1/articles')
.query({ page: -4, limit: 1 })
.set('authorization', hashedToken)
.end((err, res) => {
res.body.status.should.equal('success');
res.status.should.equal(200);
res.body.data.articles.should.be.an('Array');
res.body.data.articles.length.should.be.greaterThan(0);
res.body.data.metadata.currentPage.should.equal(1);
done();
});
});

it('should return default 10 articles article successfully when limit is less than 1', (done) => {
chai
.request(app)
.get('/api/v1/articles')
.query({ limit: -2, page: 1 })
.set('authorization', hashedToken)
.end((err, res) => {
res.body.status.should.equal('success');
res.status.should.equal(200);
res.body.data.articles.should.be.an('Array');
res.body.data.articles.length.should.equal(10);
done();
});
});

it('should return successfully with a default of 10 articles when limit is not a number', (done) => {
chai
.request(app)
.get('/api/v1/articles')
.query({ limit: '', page: [] })
.set('authorization', hashedToken)
.end((err, res) => {
res.body.status.should.equal('success');
res.status.should.equal(200);
res.body.data.articles.should.be.an('Array');
res.body.data.articles.length.should.equal(10);
done();
});
});

it('should return 12 article successfully when limit equals 12', (done) => {
chai
.request(app)
.get('/api/v1/articles')
.query({ limit: 12, page: 1 })
.set('authorization', hashedToken)
.end((err, res) => {
res.body.status.should.equal('success');
res.status.should.equal(200);
res.body.data.articles.should.be.an('Array');
res.body.data.articles.length.should.equal(12);
done();
});
});

it('should fail when token is undefined', (done) => {
chai
.request(app)
.get('/api/v1/articles')
.query({ limit: 12, page: 1 })
.end((err, res) => {
res.status.should.equal(401);
res.body.status.should.equal('fail');
res.body.data.message.should.equal('No token provided');
done();
});
});

it('should return first item first', (done) => {
chai
.request(app)
.get('/api/v1/articles')
.query({ limit: 5, page: 1 })
.set('authorization', hashedToken)
.end((err, res) => {
res.status.should.equal(200);
res.body.status.should.equal('success');
res.body.data.articles.should.be.an('Array');
res.body.data.articles[0].id.should.equal(1);
done();
});
});

it('should return successfully with required metadata', (done) => {
chai
.request(app)
.get('/api/v1/articles')
.query({ limit: 5, page: 1 })
.set('authorization', hashedToken)
.end((err, res) => {
res.status.should.equal(200);
res.body.status.should.equal('success');
res.body.data.articles.should.be.an('Array');
res.body.data.should.have.property('metadata');
res.body.data.metadata.should.have.property('limit');
res.body.data.metadata.should.have.property('currentPage');
res.body.data.metadata.should.have.property('totalPages');
done();
});
});
});

0 comments on commit 29f1987

Please sign in to comment.