Skip to content

Commit

Permalink
[Feature #164489789] pagination support for article ratings
Browse files Browse the repository at this point in the history
  • Loading branch information
mystere10 committed May 14, 2019
1 parent bb478f8 commit 3b43267
Show file tree
Hide file tree
Showing 8 changed files with 359 additions and 20 deletions.
32 changes: 32 additions & 0 deletions controllers/article.js
Original file line number Diff line number Diff line change
Expand Up @@ -674,5 +674,37 @@ class Article {
return res.status(500).json({ error });
}
}

/**
* @author Innocent Nkunzi
* @param {*} req
* @param {*} res
* @returns {object} it returns an object of articles
*/
static async articleRatingPagination(req, res) {
const pageNumber = parseInt(req.query.page, 10);
const limitRatings = parseInt(req.query.limit, 10);

if (pageNumber <= 0) {
return res.status(403).json({
error: 'Invalid page number'
});
}
if (limitRatings <= 0) {
return res.status(403).json({
error: 'Invalid limit'
});
}
const offset = limitRatings * (pageNumber - 1);
const listOfRatings = await ratingModel.paginateArticleRatings(limitRatings, offset);
if (listOfRatings.length) {
res.status(200).json({
articles: listOfRatings,
ratingCounts: listOfRatings.length
});
} else {
res.status(404).json({ error: 'No article found' });
}
}
}
export default Article;
12 changes: 0 additions & 12 deletions migrations/20190410060956-create-resetpassword.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,6 @@ module.exports = {
token: {
type: Sequelize.STRING
},
userId: {
type: Sequelize.INTEGER,
allowNull: false
},
articleSlug: {
type: Sequelize.STRING,
allowNull: false
},
rating: {
type: Sequelize.INTEGER,
allowNull: false
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
Expand Down
4 changes: 0 additions & 4 deletions models/article.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ const ArticleModel = (sequelize, DataTypes) => {
Article.createArticle = article => Article.create(article);
Article.getAll = () => Article.findAll();
Article.getOneArticle = slug => Article.findOne({ where: { slug } });
<<<<<<< HEAD
Article.findArticleSlug = (authorid, slug) => Article.findOne({ where: { authorid, slug } });
Article.deleteArticle = slug => Article.destroy({ where: { id: slug } });
Article.getAllPages = (limit, offset) => Article.findAll({ limit, offset });
Expand All @@ -54,9 +53,6 @@ const ArticleModel = (sequelize, DataTypes) => {
return data;
};
Article.addViewer = id => Article.increment('views', { by: 1, where: { id } });
=======
Article.verifyArticle = slug => Article.findOne({ where: { slug } });
>>>>>>> get user from token

Article.associate = (models) => {
Article.belongsTo(models.user, {
Expand Down
1 change: 1 addition & 0 deletions models/rating.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ module.exports = (sequelize, DataTypes) => {
rating.addRate = (rate, article, id) => rating.findOrCreate({ where: { userId: id, articleSlug: article }, defaults: { rating: rate } });
rating.rateUpdate = (rateId, rate) => rating.update({ rating: rate }, { returning: true, where: { id: rateId } });
rating.avgFind = id => rating.findAll({ where: { articleId: id }, attributes: ['articleId', [sequelize.fn('AVG', sequelize.col('rating')), 'avgRating']], group: 'rating.articleId' });
rating.paginateArticleRatings = (limit, offset) => rating.findAll({ limit, offset });
rating.associate = (models) => {
rating.belongsTo(models.user, { foreignKey: 'userId', onDelete: 'CASCADE' });
rating.belongsTo(models.article, { foreignKey: 'articleSlug', onDelete: 'CASCADE' });
Expand Down
1 change: 1 addition & 0 deletions routes/api/articles.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ router.post('/:slug/rate/:rate', AuthToken, articleController.rateArticle);
router.get('/:slug/rates', AuthToken, articleController.fetchArticleRating);
router.delete('/:slug', AuthToken, errorHandler(articleController.deleteArticle));
router.put('/:slug', AuthToken, errorHandler(articleController.updateArticle));
router.get('/rating/articles', errorHandler(articleController.articleRatingPagination));
router.patch(
'/:slug/:likeState',
Strategy.verifyToken,
Expand Down
298 changes: 298 additions & 0 deletions swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -995,3 +995,301 @@ paths:
error:
type: 'String'
example: 'The token you provided is invalid'
/api/articles:
post:
tags:
- Articles
description: Create an article
parameters:
- in: header
name: authorization
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
title:
type: string
example: 'How the universe is beautiful'
body:
type: string
example: Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged.
description:
type: string
example: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry'
tagList:
items:
type: string
example: Sport
responses:
201:
description: article created
content:
application/json:
schema:
type: object
properties:
article:
type: object
properties:
id:
type: integer
example: 1
title:
type: string
example: Lorem Ipsum is simply dummy text
slug:
type: string
example: world-class-devs-77f5d72
body:
type: string
example: Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.
createdAt:
type: string
example: "2019-04-29 15:36:48.352+02"
updatedAt:
type: string
example: "2019-04-29 15:36:48.352+02"
400:
description: Error
/api/articles/{slug}:
get:
tags:
- Articles
description: get article by their slug
parameters:
- in: path
name: slug
required: true
schema:
type: string
responses:
200:
description: Found article
content:
application/json:
schema:
type: object
properties:
article:
type: object
properties:
id:
type: integer
example: 1
title:
type: string
example: Lorem Ipsum is simply dummy text
slug:
type: string
example: world-class-devs-77f5d72
body:
type: string
example: Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.
createdAt:
type: string
example: "2019-04-29 15:36:48.352+02"
updatedAt:
type: string
example: "2019-04-29 15:36:48.352+02"
404:
description: No article found with the specified slug
delete:
tags:
- Articles
description: detes an article by its slug
parameters:
- in: path
name: slug
required: true
schema:
type: string
responses:
200:
description: article deleted
404:
description: no article for you to delete
put:
tags:
- Articles
description: update a single article
parameters:
- in: path
name: slug
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
title:
type: string
example: Lorem Ipsum is simply dummy text
body:
type: string
example: Lorem Ipsum is simply dummy text
description:
type: string
example: 'Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry'
tagList:
items:
type: string
example: Sport
responses:
201:
description: article updated
content:
application/json:
schema:
type: object
properties:
article:
type: object
properties:
id:
type: integer
example: 1
title:
type: string
example: Lorem Ipsum is simply dummy text
slug:
type: string
example: world-class-devs-77f5d72
body:
type: string
example: Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.
createdAt:
type: string
example: "2019-04-29 15:36:48.352+02"
updatedAt:
type: string
example: "2019-04-29 15:36:48.352+02"
/api/articles/all:
get:
tags:
- Articles
description: get all article
responses:
200:
description: list of articles
content:
application/json:
schema:
type: object
properties:
article:
type: object
properties:
id:
type: integer
example: 1
title:
type: string
example: Lorem Ipsum is simply dummy text
slug:
type: string
example: world-class-devs-77f5d72
body:
type: string
example: Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.
createdAt:
type: string
example: "2019-04-29 15:36:48.352+02"
updatedAt:
type: string
example: "2019-04-29 15:36:48.352+02"
404:
description: No article found with the specified slug
/api/articles/rating/articles:
get:
tags:
- Pagination
description: Should return a list of article rating per specified page
parameters:
- in: path
name: page
required: true
schema:
type: string
responses:
200:
description: should return a list of aricle ratings depending on the page
content:
application/json:
schema:
type: object
properties:
articles:
type: object
properties:
id:
type: integer
example: 1
userId:
type: integer
example: 2
articleSlug:
type: string
example: hello-world-5baafd3,
rating:
type: integer
example: 1
createdAt:
type: string
example: "2019-05-02T08:01:26.302Z"
updatedAt:
type: string
example: "2019-05-02T08:01:26.302Z"
400:
description: No article found

/api/articles/rating/articles:
get:
tags:
- Pagination
description: Should return a list of article rating per specified page
parameters:
- in: path
name: page and limit
required: true
schema:
type: string
responses:
200:
description: should return a list of aricle ratings depending on the page
content:
application/json:
schema:
type: object
properties:
articles:
type: object
properties:
id:
type: integer
example: 1
userId:
type: integer
example: 2
articleSlug:
type: string
example: hello-world-5baafd3,
rating:
type: integer
example: 1
createdAt:
type: string
example: "2019-05-02T08:01:26.302Z"
updatedAt:
type: string
example: "2019-05-02T08:01:26.302Z"
400:
description: No article found
Loading

0 comments on commit 3b43267

Please sign in to comment.