Skip to content

Commit

Permalink
Merge aa40616 into a2b6e37
Browse files Browse the repository at this point in the history
  • Loading branch information
verenceLola committed Dec 21, 2018
2 parents a2b6e37 + aa40616 commit 68dd2ee
Show file tree
Hide file tree
Showing 9 changed files with 206 additions and 4 deletions.
9 changes: 8 additions & 1 deletion authors/apps/articles/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
from rest_framework.exceptions import NotFound

class ArticleNotFound(NotFound):
default_detail = 'Article with this slug not found'
default_detail = 'Article with this slug not found'

class CommentNotFound(NotFound):
"""
comment id not found exception
"""

default_detail = 'Comment not found.'
25 changes: 25 additions & 0 deletions authors/apps/articles/migrations/0005_auto_20181219_1816.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Generated by Django 2.1 on 2018-12-19 18:16

from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('articles', '0004_article_tags'),
]

operations = [
migrations.AddField(
model_name='comment',
name='dislikes',
field=models.ManyToManyField(blank=True, related_name='dislikecomment', to=settings.AUTH_USER_MODEL),
),
migrations.AddField(
model_name='comment',
name='likes',
field=models.ManyToManyField(blank=True, related_name='likecomment', to=settings.AUTH_USER_MODEL),
),
]
3 changes: 3 additions & 0 deletions authors/apps/articles/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ class Comment(models.Model):
blank=False,
null=False,
)
# add like and dislike field in the comment
article = models.ForeignKey(Article, related_name='comments', on_delete=models.CASCADE)
author = models.ForeignKey(Profile, related_name='comments', on_delete=models.CASCADE)
# The beginning of the highlight
Expand All @@ -98,6 +99,8 @@ class Comment(models.Model):
highlight_end = models.IntegerField(default=-1)
created_at = models.DateTimeField(auto_now_add=True)
last_update = models.DateTimeField(auto_now=True)
likes = models.ManyToManyField(User, blank=True, related_name='likecomment')
dislikes = models.ManyToManyField(User, blank=True, related_name='dislikecomment')

class Meta:
""""
Expand Down
20 changes: 19 additions & 1 deletion authors/apps/articles/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,22 @@ class to serialize comments data
created_at = serializers.SerializerMethodField(method_name='get_formated_create_at')
last_update = serializers.SerializerMethodField(method_name='get_formated_last_update')
replies = ReplySerializer(many=True, read_only=True)
likes = serializers.SerializerMethodField(method_name='comment_likes')
dislikes = serializers.SerializerMethodField(method_name='comment_dislikes')

def comment_likes(self, instance):
"""method to return a user who has liked an article"""

return {
'count': instance.likes.count()
}

def comment_dislikes(self, instance):
"""method to return a user who has disliked an article"""

return {
'count': instance.dislikes.count()
}

class Meta:
"""
Expand All @@ -189,7 +205,9 @@ class Meta:
'body',
'created_at',
'last_update',
'replies'
'replies',
'likes',
'dislikes'
)

def create(self, validated_data):
Expand Down
28 changes: 27 additions & 1 deletion authors/apps/articles/tests/base_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,33 @@ def create_comment(self, token, article_slug):
HTTP_AUTHORIZATION=token
)
return response


def like_comment_url(self, comment_pk):
"""
return the url for liking a specific comment ID
"""
return reverse('articles:like-comment', kwargs={
'comment_pk': comment_pk
})

def dislike_comment_url(self, comment_pk):
"""
return the url for disking a specific comment ID
"""
return reverse('articles:dislike-comment', kwargs={
'comment_pk': comment_pk
})

def get_comment_id(self):
"""
return comment ID for liking and disliking a comment
"""
self.user_signup()
token = self.user_login()
article_url, saved_article, token = self.create_article()
article_slug = saved_article.data['slug']
comment_response = self.create_comment(token, article_slug)
return comment_response.data['comment']['id'], token

def create_article(self):
"""
Expand Down
57 changes: 57 additions & 0 deletions authors/apps/articles/tests/test_liking_and_disliking_comments.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
from rest_framework import status
from .base_test import BaseTestCase
from django.urls import reverse


class TestLikingComments(BaseTestCase):
"class to test liking and disliking of articles"

def test_like_comment(self):
"""test for liking a comment"""
comment_id, token = self.get_comment_id()
response = self.client.put(self.like_comment_url(comment_id), format='json', HTTP_AUTHORIZATION=token)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data, {'message': 'You have liked this comment'})

def test_dislike_comment(self):
"""test for liking a comment"""
comment_id, token = self.get_comment_id()
response = self.client.put(self.dislike_comment_url(comment_id) , format='json', HTTP_AUTHORIZATION=token)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data, {'message': "You have disliked this comment"})

def test_like_un_like_comment(self):
"""test for liking then disliking a comment"""
comment_id, token = self.get_comment_id()
response = self.client.put(self.like_comment_url(comment_id), format='json', HTTP_AUTHORIZATION=token)
self.assertEqual(response.data, {'message': 'You have liked this comment'})
response = self.client.put(self.like_comment_url(comment_id), format='json', HTTP_AUTHORIZATION=token)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data, {'message': "You have unliked this comment"})

def test_dislike_un_dislike_comment(self):
"""test for liking then unliking a comment"""
comment_id, token = self.get_comment_id()
response = self.client.put(self.dislike_comment_url(comment_id), format='json', HTTP_AUTHORIZATION=token)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data, {'message': "You have disliked this comment"})
response = self.client.put(self.dislike_comment_url(comment_id), format='json', HTTP_AUTHORIZATION=token)
self.assertEqual(response.data, {'message': 'This comment has been un-disliked'})

def test_like_nonexisting_comment(self):
"""test for liking an comment"""
self.user_signup()
token = self.user_login()
non_existing_id = 5 # not existing comment ID
response = self.client.put(self.like_comment_url(non_existing_id), format='json', HTTP_AUTHORIZATION='Token ' + token)
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
self.assertEqual(response.data, {'detail': "Comment not found."})

def test_dislike_nonexisting_comment(self):
"""test for liking an comment"""
self.user_signup()
token = self.user_login()
non_existing_id = 5 # not existing comment ID
response = self.client.put(self.dislike_comment_url(non_existing_id), format='json', HTTP_AUTHORIZATION='Token ' + token)
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
self.assertEqual(response.data, {'detail': "Comment not found."})
7 changes: 7 additions & 0 deletions authors/apps/articles/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
from authors.apps.articles.views.ratings import RatingsAPIView
from authors.apps.articles.views.reply import ReplyListAPIView, UpdateDestroyReplyAPIView
from authors.apps.articles.views.report_articles import ReportArticleAPIView, ReportListAPIView
from authors.apps.articles.views.like_dislike_comments import (
LikeComment,
DislikeComment,
)


urlpatterns = [
path('articles/', ArticleAPIView.as_view(), name='articles'),
Expand All @@ -23,4 +28,6 @@
path('articles/reports/', ReportListAPIView.as_view(), name='report-list'),
path('articles/<str:article_slug>/bookmark/', BookMarkCreateAPIView.as_view(), name='bookmark-article'),
path('articles/bookmarks/', BookMarkListAPIView.as_view(), name='get-bookmarks'),
path('comments/<int:comment_pk>/like/', LikeComment.as_view(), name='like-comment'),
path('comments/<int:comment_pk>/dislike/', DislikeComment.as_view(), name='dislike-comment'),
]
2 changes: 1 addition & 1 deletion authors/apps/articles/views/bookmarks.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def post(self, request, article_slug):
try:
article = Article.objects.get(article_slug=article_slug)
except Article.DoesNotExist:
raise ArticleNotFound()
raise ArticleNotFound
bookmark, created = BookMarkArticle.objects.get_or_create(
user=user,
article=article
Expand Down
59 changes: 59 additions & 0 deletions authors/apps/articles/views/like_dislike_comments.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
from rest_framework.generics import UpdateAPIView
from authors.apps.articles.models import Comment
from rest_framework.response import Response
from rest_framework import status
from authors.apps.articles.exceptions import CommentNotFound

class LikeComment(UpdateAPIView):
"""Class for liking and un-liking an article"""

def update(self, request, comment_pk):
"""This method updates the liking of an article"""
try:
comment = Comment.objects.get(id=comment_pk)
except Comment.DoesNotExist:
raise CommentNotFound

# gets the user of that specific session
user = request.user
# checks for the boolean value of liking an comments
liked = bool(user in comment.likes.all())
if liked is True:
comment.likes.remove(user.id)
message = {"message": "You have unliked this comment"}
return Response(message, status.HTTP_200_OK)

# if like is false, the comment is liked
disliked = bool(user in comment.dislikes.all())
if disliked is True:
comment.dislikes.remove(user.id) # un-dislike if user had disliked
comment.likes.add(user.id) # now like the comment
message = {"message": "You have liked this comment"}
return Response(message, status.HTTP_200_OK)


class DislikeComment(UpdateAPIView):
"""Class for disliking and un-disliking an comment"""

def update(self, request, comment_pk):
"""This method updates the liking of an comment"""
comment = Comment.objects.filter(id=comment_pk).first()
if comment is None:
raise CommentNotFound

# gets the user of that specific session
user = request.user
# checks for the boolean value of disliking an comment
disliked = bool(user in comment.dislikes.all())
if disliked is True:
comment.dislikes.remove(user.id)
message = {"message": "This comment has been un-disliked"}
return Response(message, status.HTTP_200_OK)

# if dislike is false, the comment is disliked
liked = bool(user in comment.likes.all())
if liked is True:
comment.likes.remove(user.id) # unlike if user had liked
comment.dislikes.add(user.id) # now dislike the comment
message = {"message": "You have disliked this comment"}
return Response(message, status.HTTP_200_OK)

0 comments on commit 68dd2ee

Please sign in to comment.