Skip to content

Commit

Permalink
This is the commit message #2:
Browse files Browse the repository at this point in the history
feature(Likes & Dislikes): Allowing a user to like or dislike an article.

- ensuring that the user can like or dislike an article.

[Delivers #164489935]

changes

changes
  • Loading branch information
Copain Fabrice BIENAIME authored and Copain Fabrice BIENAIME committed Apr 23, 2019
1 parent 4176913 commit 1d79206
Show file tree
Hide file tree
Showing 11 changed files with 392 additions and 8 deletions.
31 changes: 29 additions & 2 deletions controllers/article.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
/* eslint-disable guard-for-in */
import models from '../models/index';
import readingTime from '../helpers/readingTime';

const Article = models.article;
const Votes = models.vote;
/**
* @param {class} --Article controller
*/
Expand Down Expand Up @@ -83,15 +85,40 @@ class ArticleController {
* @returns {Object} return article
*/
static singleArticle(req, res) {
const user = (req.user ? req.user.id : 'nouser');
Article.findByPk(req.params.articleId)
.then((article) => {
if (!article) {
return res.status(404).json({ error: 'Sorry the requested resource could not be found.' });
}
article.dataValues.readingTime = readingTime(article.title + article.body);
// @return article
return res.status(200).json({ status: 200, article });
});
Votes.findAll({ where: { article: req.params.articleId } })
.then((vote) => {
let countLike = 0;
let countDisLike = 0;
let hasLiked = false;
let hasDisliked = false;
// eslint-disable-next-line no-restricted-syntax
for (const i in vote) {
countLike += vote[i].like;
countDisLike += vote[i].dislike;
if (vote[i].user === user) {
hasLiked = vote[i].like;
hasDisliked = vote[i].dislike;
}
}
// @return article

return res.status(200).json({
status: 200, article, likes: countLike, dislike: countDisLike, hasLiked, hasDisliked
});
})
.catch((error) => {
console.log(error);
});
})
.catch(error => res.status(500).json({ error: `Something wrong please try again later. ${error}` }));
}
}

Expand Down
75 changes: 75 additions & 0 deletions controllers/votes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import models from '../models/index';

const Votes = models.vote;

/** *
* @param {request } req request
* @param {response} res response
*/

// eslint-disable-next-line require-jsdoc
class VotesController {
/** *
* @param {request } req request
* @param {response} res response
* @returns {message} message
*/
static async likes(req, res) {
try {
const likeData = {
user: req.user.id,
article: req.params.articleId,
like: true,
dislike: false
};
if (req.vote === null) {
await Votes.create(likeData);
return res.status(200).json({ message: 'thanks for the support.' });
} if (req.vote.like === true) {
return res.status(400).json({ error: 'sorry you have already liked this article.' });
}
await Votes.update(likeData, { where: { vote_id: req.vote.vote_id } });
return res.status(200).json({
message: 'thanks for the support.',
userId: req.user.id,
article: req.params.articleId,
});
} catch (error) {
return res.status(500).json({ error: 'something wrong try again later.' });
}
}

/** *
* @param {request } req request
* @param {response} res response
* @returns {message} message
*/

// eslint-disable-next-line require-jsdoc
static async dislikes(req, res) {
try {
const dislikeData = {
user: req.user.id,
article: req.params.articleId,
like: false,
dislike: true
};
if (req.vote === null) {
await Votes.create(dislikeData);
return res.status(200).json({ message: 'thank for support.' });
} if (req.vote.dislike === true) {
return res.status(400).json({ error: 'sorry you have already disliked this article.' });
}
await Votes.update(dislikeData, { where: { vote_id: req.vote.vote_id } });
return res.status(200).json({
message: 'You have disliked this article.',
userId: req.user.id,
article: req.params.articleId,
});
} catch (error) {
return res.status(500).json({ error: 'something wrong try again later.' });
}
}
}

export default VotesController;
13 changes: 13 additions & 0 deletions middlewares/isAuth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import passport from 'passport';

const isAuth = (req, res, next) => {
passport.authenticate('jwt', { session: false }, (error, user) => {
if (error) {
next(error);
}
req.user = user;
next();
})(req, res, next);
};

export default isAuth;
24 changes: 24 additions & 0 deletions middlewares/votes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import models from '../models/index';

const Vote = models.vote;

// eslint-disable-next-line import/prefer-default-export
const checkVote = async (req, res) => {
try {
const search = await Vote.findOne({ where: { user: req.user.id } });
return search;
} catch (error) {
return res.status(500).json({ status: 500, message: `something wrong please try again.${error}` });
}
};
const checkLikes = async (req, res, next) => {
const vote = await checkVote(req, res);
if (!vote) {
req.vote = null;
next();
} else {
req.vote = vote;
next();
}
};
export default checkLikes;
52 changes: 52 additions & 0 deletions migrations/20190409175130-Vote.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@


const voteMigration = {
up: (queryInterface, Sequelize) => queryInterface.createTable('votes',
{
vote_id: {
type: Sequelize.INTEGER,
allowNull: false,
primaryKey: true,
autoIncrement: true
},
user: {
type: Sequelize.INTEGER,
onDelete: 'CASCADE',
allowNull: false,
references: {
model: 'users',
key: 'id'
}

},
article: {
type: Sequelize.INTEGER,
allowNull: false,
onDelete: 'CASCADE',
references: {
model: 'articles',
key: 'article_id'
}
},
like: {
type: Sequelize.BOOLEAN,
defaultValue: false
},
dislike: {
type: Sequelize.BOOLEAN,
defaultValue: false
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
default: true
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
}),
down: queryInterface => queryInterface.dropTable('votes')
};

export default voteMigration;
2 changes: 1 addition & 1 deletion models/article.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const articleModel = (Sequelize, DataTypes) => {
key: 'id'
}
},
image: { type: DataTypes.STRING, allowNull: true }
image: { type: DataTypes.STRING, allowNull: true },
}, {});
Article.associate = (models) => {
Article.hasMany(models.comments, {
Expand Down
18 changes: 18 additions & 0 deletions models/votes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const voteModels = (Sequelize, DataTypes) => {
const Votes = Sequelize.define('vote', {
vote_id: {
type: DataTypes.INTEGER, allowNull: false, primaryKey: true, autoIncrement: true
},
user: { type: DataTypes.INTEGER, references: { model: 'user', key: 'id' } },
article: { type: DataTypes.INTEGER, references: { model: 'article', key: 'article_id' } },
like: { type: DataTypes.BOOLEAN },
dislike: { type: DataTypes.BOOLEAN },
}, {});
Votes.associate = (models) => {
Votes.belongsTo(models.article, { as: 'articlefkey', foreignKey: 'article' });
Votes.belongsTo(models.user, { as: 'userfkey', foreignKey: 'user' });
};
return Votes;
};

export default voteModels;
14 changes: 11 additions & 3 deletions routes/api/article.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import passport from 'passport';
import Article from '../../controllers/article';
import Comment from '../../controllers/comment';
import multer from '../../middlewares/multerConfiguration';
import { checkingArticle } from '../../middlewares/article';
import validateComment from '../../helpers/validateComment';
import checkComment from '../../middlewares/checkComment';
import Rate from '../../controllers/rate';
Expand All @@ -12,8 +11,15 @@ import checkArticle from '../../middlewares/checkArticle';
import asyncHandler from '../../helpers/errors/asyncHandler';
import shareArticle from '../../helpers/shareArticles';

import { checkingArticle, findArticleExist } from '../../middlewares/article';
import Votes from '../../controllers/votes';
import checkVote from '../../middlewares/votes';
import isAuth from '../../middlewares/isAuth';

const router = express.Router();
const auth = passport.authenticate('jwt', { session: false });
const auth = passport.authenticate('jwt', {
session: false
});
// @Method POST
// @Desc create article
router.post('/', auth, multer, Article.create);
Expand All @@ -25,12 +31,14 @@ router.get('/:articleId/comments/', auth, asyncHandler(checkArticle), Comment.ge
router.put('/:idArticle/comments/:commentId', auth, checkComment, Comment.updateComment);
// @Mehtod delete a given comment
router.delete('/:idArticle/comments/:commentId', auth, checkComment, Comment.deleteComment);
router.post('/:articleId/like', auth, findArticleExist, checkVote, Votes.likes);
router.post('/:articleId/dislike', auth, findArticleExist, checkVote, Votes.dislikes);
// @Method GET
// @Desc get all created article
router.get('/', Article.getArticle);
// @Method GET
// @desc get single article
router.get('/:articleId', Article.singleArticle);
router.get('/:articleId', isAuth, Article.singleArticle);
// @Method PUT
// @Desc update articles
router.put('/:articleId', auth, checkingArticle, multer, Article.updateArticle);
Expand Down
Loading

0 comments on commit 1d79206

Please sign in to comment.