Skip to content

Commit

Permalink
ft(like-and-dislike-a-comment): Allow user to like and dislike a comment
Browse files Browse the repository at this point in the history
 - Add comment id column inside LikeAndDislike table
 - Create 2 routes for liking and disliking the comment
 - Implement functions to allow user like and dislike comments
 - Write unit tests for implemented functions
 - Document my feature using Swagger

[(Finishes #166790108)]
  • Loading branch information
Joseph Nkurunziza committed Jul 22, 2019
1 parent 7f56beb commit baa26df
Show file tree
Hide file tree
Showing 12 changed files with 333 additions and 30 deletions.
3 changes: 1 addition & 2 deletions .coveralls.yml
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
service_name: travis-pro
repo_token: 5wHJgqAVMocmuMfz7Nr26hEBqmO7gtzJJ
repo_token: G3KUaGgIQZdYITPWuU0uIfjZckwOlOq8C
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[![Build Status](https://travis-ci.com/andela/ah-jawans-backend.svg?branch=develop)](https://travis-ci.com/andela/ah-jawans-backend)
[![Reviewed by Hound](https://img.shields.io/badge/Reviewed_by-Hound-8E64B0.svg)](https://houndci.com)
[![Reviewed by Hound](https://img.shields.io/github/issues/andela/ah-jawans-backend.svg?style=flat-square)](https://houndci.com) [![Coverage Status](https://coveralls.io/repos/github/andela/ah-jawans-backend/badge.svg?branch=develop)](https://coveralls.io/github/andela/ah-jawans-backend?branch=develop)
[![Reviewed by Hound](https://img.shields.io/github/issues/andela/ah-jawans-backend.svg?style=flat-square)](https://houndci.com) [![Coverage Status](https://coveralls.io/repos/github/andela/ah-jawans-backend/badge.svg?branch=develop)](https://coveralls.io/github/andela/ah-jawans-backend?branch=develop) [![Maintainability](https://api.codeclimate.com/v1/badges/fbf4e41d7d7846a0bee6/maintainability)](https://codeclimate.com/github/andela/ah-jawans-backend/maintainability)

Authors Haven - A Social platform for the creative at heart.
=======
Expand Down
6 changes: 2 additions & 4 deletions src/controllers/comments.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,8 @@ export default class ArticleComment {
const { articleId, commentId } = req.params;
const findComent = await Comments.findOne({ where: { id: commentId, articleId } });
return findComent
? await Comments.update(
{ body: req.body.body },
{ where: { id: commentId, articleId } },
) && res.status(200).json({ message: 'Comment modified!' })
? await Comments.update({ body: req.body.body },
{ where: { id: commentId, articleId } },) && res.status(200).json({ message: 'Comment modified!' })
: res.status(404).json({ message: 'Comment not found!' });
} catch (error) {
return res.status(500).json(error);
Expand Down
91 changes: 91 additions & 0 deletions src/controllers/helpers/likeCommentHelper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/* eslint-disable require-jsdoc */
import Sequelize from 'sequelize';
import model from '../../models';

const { Op } = Sequelize;

const { LikeAndDislike, Comments } = model;

class LikeCommentHelpers {
static async findOneComment(commentId) {
const foundComment = await Comments.findOne({ where: { id: commentId } });

return foundComment;
}

static async userLikedOrDiskedComment(id, commentId) {
const userReacted = await LikeAndDislike.findAll({ where: { userId: id,
commentId } });

return userReacted;
}

static async findDislikedComment(id, commentId) {
const unlikedArticle = await LikeAndDislike.findAll({ where: { userId: id,
commentId,
[Op.or]: [{ likes: false }, { dislikes: true }] } });

return unlikedArticle;
}

static async findLikedComment(id, commentId) {
const unlikedArticle = await LikeAndDislike.findAll({ where: { userId: id,
commentId,
[Op.or]: [{ dislikes: false }, { likes: true }] } });

return unlikedArticle;
}

static async findDisliked(id, commentId) {
const disliked = await LikeAndDislike.findAll({ where: { userId: id,
commentId,
dislikes: true } });

return disliked;
}

static async ChangeFromDislikeToLike(dislikeId) {
const updateFromDislikeToLike = await LikeAndDislike.update({ dislikes: false, likes: true },
{ where: { id: dislikeId } });

return updateFromDislikeToLike;
}

static async ChangeFromLikeToDisLike(dislikeId) {
const updateFromDislikeToLike = await LikeAndDislike.update({ dislikes: true, likes: false },
{ where: { id: dislikeId } });

return updateFromDislikeToLike;
}

static async findCommentLikes(id, commentId) {
const liked = await LikeAndDislike.findAll({ where: { userId: id,
commentId,
likes: true } });

return liked;
}

static async undoLikeOrDislikeComments(commentLike) {
const unlikeComment = await LikeAndDislike.update({ likes: false, dislikes: false },
{ where: { id: commentLike } });

return unlikeComment;
}

static async countCommentLikes(commentId) {
const likes = await LikeAndDislike.count({ where: { commentId,
likes: true } });

return likes;
}

static async countCommentDislikes(commentId) {
const dislikes = await LikeAndDislike.count({ where: { commentId,
dislikes: true } });

return dislikes;
}
}

export default LikeCommentHelpers;
28 changes: 14 additions & 14 deletions src/controllers/likeAndDislike.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,22 @@ class LikesAndDislikes {
*
* @param {Object} req
* @param {Object} res
* @returns {Object} Liked article and number of likes
* @returns {Object} Number of likes
*/
static async likeArticle(req, res) {
const findArticleId = req.params.id;
const article = await LikesDislikesHelpers.findOneArticle(findArticleId);
const articleId = req.params.id;
const article = await LikesDislikesHelpers.findOneArticle(articleId);

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

const { id } = req.user;

const liked = await LikesDislikesHelpers.findArticleLikes(id, findArticleId);
const disliked = await LikesDislikesHelpers.findDisliked(id, findArticleId);
const liked = await LikesDislikesHelpers.findArticleLikes(id, articleId);
const disliked = await LikesDislikesHelpers.findDisliked(id, articleId);

const unlikedArticle = await LikesDislikesHelpers.findUnlikedArticle(id, findArticleId);
const unlikedArticle = await LikesDislikesHelpers.findUnlikedArticle(id, articleId);

const userReacted = await LikesDislikesHelpers.userLikedOrDiskedArticle(id, findArticleId);
const userReacted = await LikesDislikesHelpers.userLikedOrDiskedArticle(id, articleId);

if (!userReacted[0]) {
await LikeAndDislike.create({ userId: id,
Expand Down Expand Up @@ -59,22 +59,22 @@ class LikesAndDislikes {
/**
* @param {object} req
* @param {object} res
* @return {object} Disliked article and number of Dislikes
* @return {object} Number of Dislikes
*/
static async dislikeArticle(req, res) {
const findArticleId = req.params.id;
const article = await LikesDislikesHelpers.findOneArticle(findArticleId);
const articleId = req.params.id;
const article = await LikesDislikesHelpers.findOneArticle(articleId);

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

const { id } = req.user;

const dislikedArticle = await LikesDislikesHelpers.findDislikedArticle(id, findArticleId);
const dislikedArticle = await LikesDislikesHelpers.findDislikedArticle(id, articleId);

const disliked = await LikesDislikesHelpers.findDisliked(id, findArticleId);
const liked = await LikesDislikesHelpers.findArticleLikes(id, findArticleId);
const disliked = await LikesDislikesHelpers.findDisliked(id, articleId);
const liked = await LikesDislikesHelpers.findArticleLikes(id, articleId);

const userReacted = await LikesDislikesHelpers.userLikedOrDiskedArticle(id, findArticleId);
const userReacted = await LikesDislikesHelpers.userLikedOrDiskedArticle(id, articleId);

if (!userReacted[0]) {
await LikeAndDislike.create({ userId: id,
Expand Down
94 changes: 94 additions & 0 deletions src/controllers/likeComment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import model from '../models';
import LikeCommentHelpers from './helpers/likeCommentHelper';

const { LikeAndDislike } = model;
/**
* This LikeComment class
*/
class LikeComment {
/**
*
* @param {Object} req
* @param {Object} res
* @returns {Object} Number of likes
*/
static async likeComment(req, res) {
const commentId = req.params.commentParamsId;
const { id } = req.user;
const comment = await LikeCommentHelpers.findOneComment(commentId);

if (!comment) return res.status(404).json({ message: 'Comment not found' });

const userReacted = await LikeCommentHelpers.userLikedOrDiskedComment(id, commentId);
const dislikedComment = await LikeCommentHelpers.findDislikedComment(id, commentId);
const liked = await LikeCommentHelpers.findCommentLikes(id, commentId);

if (!userReacted[0]) {
await LikeAndDislike.create({ userId: id,
commentId: comment.id,
likes: true,
dislikes: false });
const likes = await LikeCommentHelpers.countCommentLikes(comment.id);

return res.status(200).json({ likes });
}

if (liked[0]) {
await LikeCommentHelpers.undoLikeOrDislikeComments(liked[0].id);
const likes = await LikeCommentHelpers.countCommentLikes(comment.id);

return res.status(200).json({ likes });
}

if (dislikedComment[0]) {
await LikeCommentHelpers.ChangeFromDislikeToLike(dislikedComment[0].id);
const likes = await LikeCommentHelpers.countCommentLikes(comment.id);

return res.status(200).json({ likes });
}
}

/**
*
* @param {Object} req
* @param {Object} res
* @returns {Object} Number of Dislikes
*/
static async DislikeComment(req, res) {
const commentId = req.params.commentParamsId;
const { id } = req.user;
const comment = await LikeCommentHelpers.findOneComment(commentId);

if (!comment) return res.status(404).json({ message: 'Comment not found' });

const userReacted = await LikeCommentHelpers.userLikedOrDiskedComment(id, commentId);
const likedComment = await LikeCommentHelpers.findLikedComment(id, commentId);
const dislikedComment = await LikeCommentHelpers.findDisliked(id, commentId);

if (!userReacted[0]) {
await LikeAndDislike.create({ userId: id,
commentId: comment.id,
likes: false,
dislikes: true });
const dislikes = await LikeCommentHelpers.countCommentDislikes(comment.id);

return res.status(200).json({ dislikes });
}

if (likedComment[0]) {
await LikeCommentHelpers.ChangeFromLikeToDisLike(likedComment[0].id);
const dislikes = await LikeCommentHelpers.countCommentDislikes(comment.id);

return res.status(200).json({ dislikes });
}

if (dislikedComment[0]) {
await LikeCommentHelpers.undoLikeOrDislikeComments(dislikedComment[0].id);
const dislikes = await LikeCommentHelpers.countCommentDislikes(comment.id);

return res.status(200).json({ dislikes });
}
}
}

export default LikeComment;
1 change: 0 additions & 1 deletion src/helpers/likeAndDislikes.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
/* eslint-disable require-jsdoc */

import Sequelize from 'sequelize';
import model from '../models';

Expand Down
3 changes: 1 addition & 2 deletions src/migrations/20190716151540-create-like-and-dislike.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@


module.exports = { up: (queryInterface, Sequelize) => queryInterface.createTable('LikeAndDislike', { id: { allowNull: false,
autoIncrement: true,
primaryKey: true,
Expand All @@ -8,6 +6,7 @@ userId: { type: Sequelize.INTEGER },
likes: { type: Sequelize.BOOLEAN },
dislikes: { type: Sequelize.BOOLEAN },
articleId: { type: Sequelize.INTEGER },
commentId: { type: Sequelize.INTEGER },
createdAt: { allowNull: false,
type: Sequelize.DATE },
updatedAt: { allowNull: false,
Expand Down
15 changes: 14 additions & 1 deletion src/models/LikeAndDislike.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ export default (sequelize, DataTypes) => {
const LikeAndDislike = sequelize.define('LikeAndDislike', { userId: DataTypes.INTEGER,
likes: DataTypes.BOOLEAN,
dislikes: DataTypes.BOOLEAN,
articleId: DataTypes.INTEGER },
articleId: DataTypes.INTEGER,
commentId: DataTypes.INTEGER },
{ tableName: 'LikeAndDislike' }, {});

LikeAndDislike.associate = (models) => {
Expand All @@ -11,6 +12,18 @@ export default (sequelize, DataTypes) => {
targetkey: 'id',
onUpdate: 'CASCADE',
onDelete: 'CASCADE' });

LikeAndDislike.belongsTo(models.Comments, { foreignKey: 'commentId',
as: 'comment',
targetkey: 'id',
onUpdate: 'CASCADE',
onDelete: 'CASCADE' });

LikeAndDislike.belongsTo(models.User, { foreignKey: 'userId',
as: 'user',
targetkey: 'id',
onUpdate: 'CASCADE',
onDelete: 'CASCADE' });
};

return LikeAndDislike;
Expand Down
4 changes: 4 additions & 0 deletions src/routes/commentRoute.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import express from 'express';
import Comments from '../controllers/comments';
import Auth from '../middlewares/Auth';
import LikeComment from '../controllers/likeComment';
import { commentValidation } from '../middlewares/bodyValidation';

const { verifyToken } = Auth;
Expand All @@ -11,4 +12,7 @@ router.post('/:articleId/comments', verifyToken, commentValidation, Comments.cre
router.delete('/:articleId/comments/:commentId', verifyToken, Comments.deleteComment);
router.get('/:articleId/comments', verifyToken, Comments.getAllcomments);
router.patch('/:articleId/comments/:commentId', verifyToken, commentValidation, Comments.updateComment);

router.post('/comments/:commentParamsId/likes', verifyToken, LikeComment.likeComment);
router.post('/comments/:commentParamsId/dislikes', verifyToken, LikeComment.DislikeComment);
export default router;
Loading

0 comments on commit baa26df

Please sign in to comment.