Skip to content

Commit

Permalink
Merge dd71295 into 5371141
Browse files Browse the repository at this point in the history
  • Loading branch information
kleva-j committed Mar 20, 2019
2 parents 5371141 + dd71295 commit de19e18
Show file tree
Hide file tree
Showing 17 changed files with 758 additions and 406 deletions.
70 changes: 35 additions & 35 deletions .eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,37 +1,37 @@
{
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module"
},
"root": true,
"extends": "airbnb-base",
"env": {
"node": true,
"es6": true,
"mocha": true
},
"rules": {
"one-var": 0,
"one-var-declaration-per-line": 0,
"new-cap": 0,
"consistent-return": 0,
"no-param-reassign": 0,
"comma-dangle": 0,
"curly": ["error", "multi-line"],
"import/no-unresolved": [2, { "commonjs": true }],
"no-shadow": ["error", { "allow": ["req", "res", "err"] }],
"valid-jsdoc": ["error", {
"requireReturn": true,
"requireReturnType": true,
"requireParamDescription": false,
"requireReturnDescription": true
}],
"require-jsdoc": ["error", {
"require": {
"FunctionDeclaration": true,
"MethodDefinition": true,
"ClassDeclaration": true
}
}]
}
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module"
},
"root": true,
"extends": "airbnb-base",
"env": {
"node": true,
"es6": true,
"mocha": true
},
"rules": {
"one-var": 0,
"one-var-declaration-per-line": 0,
"new-cap": 0,
"consistent-return": 0,
"no-param-reassign": 0,
"comma-dangle": 0,
"curly": ["error", "multi-line"],
"import/no-unresolved": [2, { "commonjs": true }],
"no-shadow": ["error", { "allow": ["req", "res", "err"] }],
"valid-jsdoc": ["error", {
"requireReturn": true,
"requireReturnType": true,
"requireParamDescription": false,
"requireReturnDescription": true
}],
"require-jsdoc": ["error", {
"require": {
"FunctionDeclaration": true,
"MethodDefinition": true,
"ClassDeclaration": true
}
}]
}
}
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Authors Haven - A Social platform for the creative at heart.

[![Build Status](https://travis-ci.com/andela/vidar-ah-backend.svg?branch=develop)](https://travis-ci.com/andela/vidar-ah-backend) [![Coverage Status](https://coveralls.io/repos/github/andela/vidar-ah-backend/badge.svg?branch=ft-create-user-article-%23164139686)](https://coveralls.io/github/andela/vidar-ah-backend?branch=ft-create-user-article-%23164139686) [![](https://img.shields.io/badge/Protected_by-Hound-a873d1.svg)](https://houndci.com)
[![Build Status](https://travis-ci.com/andela/vidar-ah-backend.svg?branch=develop)](https://travis-ci.com/andela/vidar-ah-backend) [![Coverage Status](https://coveralls.io/repos/github/andela/vidar-ah-backend/badge.svg?branch=develop)](https://coveralls.io/github/andela/vidar-ah-backend?branch=develop) [![](https://img.shields.io/badge/Protected_by-Hound-a873d1.svg)](https://houndci.com)
=======

## Vision
Expand Down
40 changes: 38 additions & 2 deletions controllers/articles.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Article, User } from '../models';
import { Article, User, Ratings } from '../models';
import Paginate from '../helpers/paginate';

/**
Expand Down Expand Up @@ -39,7 +39,43 @@ export default class ArticleController {
article: result,
});
} catch (error) {
return res.status(500).json({ success: false, error: [error.message] });
return res.status(500).json({ success: false, errors: [error.message] });
}
}

/**
* @description - Rate an article
* @static
* @param {Object} req - the request object
* @param {Object} res - the response object
* @memberof ArticleController
* @returns {Object} class instance
*/
static async rateArticle(req, res) {
const { id } = req.user;
const rating = Number(req.body.rating);
const { articleId } = req.params;
try {
const previousRating = await Ratings.findOne({ where: { userId: id, articleId } });
if (previousRating) {
const updatedRating = await previousRating.update({ rating });
return res.status(201).json({
success: true,
message: `Article rating has been updated as ${rating}`,
rating: updatedRating
});
}
return res.status(200).json({
success: true,
message: `Article has been rated as ${rating}`,
articleRating: (await Ratings.create({
userId: id,
articleId,
rating
}))
});
} catch (error) {
return res.status(400).json({ success: false, errors: ['Error rating this article'] });
}
}

Expand Down
117 changes: 39 additions & 78 deletions doc.json
Original file line number Diff line number Diff line change
Expand Up @@ -231,69 +231,41 @@
}
}
},
"/category": {
"post": {
"description": "endpoint to create a category",
"summary": "adds a new category to the category table",
"tags": [
"create category"
],
"operationId": "CategoryPost",
"deprecated": false
}
},
"/requestpasswordreset": {
"/articles": {
"post": {
"tags": [
"Reset password"
"Articles"
],
"summary": "Send reset link to user email",
"description": "Send reset link to user email",
"summary": "Create an article",
"description": "",
"operationId": "addArticle",
"consumes": [
"application/x-www-form-urlencoded",
"application/json"
],
"produces": [
"application/json"
],
"parameters": [
{
"name": "Content-Type",
"in": "header",
"required": true,
"type": "string",
"description": ""
},
{
"name": "x-access-token",
"name": "authorization",
"in": "header",
"description": "A token to verify the user",
"required": true,
"type": "string",
"description": ""
"type": "string"
},
{
"name": "Body",
"in": "body",
"required": true,
"description": "",
"schema": {
"$ref": "#/definitions/createcategory",
"in": "body",
"name": "Request body",
"description": "Reset user password",
"name": "body",
"description": "Create user article",
"required": true,
"schema": {
"$ref": "#/definitions/requestPasswordReset"
"$ref": "#/definitions/articles"
}
}
}
],
"responses": {
"201": {
"description": "Save password reset key in database and send link to email"
},
"404": {
"description": "User not registered or verified."
"description": "New article created successfully"
},
"422": {
"description": "Email is invalid"
Expand Down Expand Up @@ -424,14 +396,14 @@
}
}
},
"/articles": {
"/articles/rate/:articleId": {
"post": {
"tags": [
"Articles"
],
"summary": "Create an article",
"description": "",
"operationId": "addArticle",
"summary": "Rate an article",
"description": "Give ratings on an article",
"operationId": "rateArticle",
"consumes": [
"application/json"
],
Expand All @@ -448,20 +420,26 @@
},
{
"in": "body",
"name": "body",
"description": "Update user profile",
"name": "rating",
"description": "Rate an article",
"required": true,
"schema": {
"$ref": "#/definitions/articles"
"$ref": "#/definitions/rating"
}
}
],
"responses": {
"201": {
"description": "New article created successfully"
"description": "Article has been rated as (rating)"
},
"422": {
"description": "Invalid title/description/body supplied"
"description": "Please provide a valid rating for this article"
},
"404": {
"description": "This article does not exist"
},
"403": {
"description": "Permission denied, user cannot rate their own article"
}
}
},
Expand Down Expand Up @@ -604,22 +582,6 @@
}
}
},
"requestPasswordReset": {
"type": "object",
"properties": {
"email": {
"type": "string"
}
}
},
"resetPassword": {
"type": "object",
"properties": {
"password": {
"type": "string"
}
}
},
"articles": {
"type": "object",
"properties": {
Expand All @@ -634,24 +596,23 @@
}
}
},
"createcategory": {
"title": "adds a new category to the category table",
"example": {
"category": "Sport Bulletin"
},
"rating": {
"type": "object",
"properties": {
"category": {
"rating": {
"type": "integer"
},
"articleId": {
"type": "string"
},
"userId": {
"type": "number"
}
},
"required": [
"category"
],
"externalDocs": {
"description": "Find out more about Swagger",
"url": "http://swagger.io"
}
}
},
"externalDocs": {
"description": "Find out more about Swagger",
"url": "http://swagger.io"
}
}
27 changes: 27 additions & 0 deletions middleware/checkIfArticleExist.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@

import { Article } from '../models';

export default async (req, res, next) => {
const { id } = req.user;
const { articleId } = req.params;
try {
const articleExist = await Article.findOne({ where: { id: articleId } });
if (articleExist) {
if (articleExist.dataValues.userId === id) {
return res.status(403).json({
success: false,
errors: ['Permission denied, user cannot rate their own article']
});
} return next();
}
return res.status(404).json({
success: false,
errors: ['This article does not exist']
});
} catch (error) {
return res.status(500).json({
success: false,
errors: ['Error rating article']
});
}
};
16 changes: 16 additions & 0 deletions middleware/validation.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,19 @@ export const validateSearch = [
.isString()
.withMessage('Please provide a valid search term.')
];

export const validateArticleRating = [
check('rating')
.exists()
.withMessage('Please provide a rating for this article.')
.custom(value => `${Number(value)}` !== 'NaN')
.withMessage('Rating should be a number.')
.custom(value => [1, 2, 3, 4, 5].indexOf(Number(value)) !== -1)
.withMessage('Ratings should have values ranging from 1 to 5.')
];

export const validateArticleId = [
check('articleId')
.isUUID()
.withMessage('Please provide a valid id for the article')
];
Loading

0 comments on commit de19e18

Please sign in to comment.