Skip to content

Commit

Permalink
feat(like article): like and dislike article
Browse files Browse the repository at this point in the history
 - create like/dislike model
 - create like dislike views
 - add like and dislike views in urls
 - write tests

[finishes #161254667]
  • Loading branch information
Gidraf committed Nov 12, 2018
1 parent 1249189 commit 6ae16ee
Show file tree
Hide file tree
Showing 9 changed files with 450 additions and 89 deletions.
146 changes: 146 additions & 0 deletions authors/apps/article/likes_dislike_views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import IsAuthenticated
from .models import (Article,
LikeDislikeArticle)


LOOKUP_FIELD = 'slug'
no_article = "No article found"
undisliked_response = "article successfully undisliked"
disliked_article_response = "article successfully disliked"


def get_article(kwargs):
"""
query article
"""
slug = kwargs.get('slug')
article = Article.objects.get(slug=slug)
return article


class Like(APIView):
"""
Like views
"""

permission_classes = (IsAuthenticated,)

def post(self, request, **kwargs):
"""
Like an article.
"""
article = None
try:
slug = kwargs.get('slug')
article = Article.objects.get(slug=slug)
liker = request.user
except Exception:
return Response({"response": "No article found"},
status=status.HTTP_204_NO_CONTENT)
try:
like = LikeDislikeArticle.objects.get(
article=article, liker=liker)
if like.is_liked:
like.is_liked = False
like.save()
return Response(
{"response": "article successfully unliked"},
status=status.HTTP_200_OK)
like.is_disliked = False
like.is_liked = True
like.save()
return Response(
{"response": "article successfully liked"},
status=status.HTTP_200_OK)
except Exception:
like = LikeDislikeArticle(
liker=liker,
article=article,
is_liked=True)
like.save()
return Response(
{"response": "article successfully liked"},
status=status.HTTP_200_OK)

def get(self, request, **kwargs):
"""
Return likes of an article
"""

likes = None
slug = kwargs.get('slug')
try:
article = Article.objects.get(slug=slug)
except Exception:
return Response({"response": no_article},
status=status.HTTP_204_NO_CONTENT)
likes = LikeDislikeArticle.objects.filter(article=article)
return Response({"response": len(
[like for like in likes if like.is_liked])},
status=status.HTTP_200_OK)


class Dislike(APIView):
"""
Dislike views
"""

permission_classes = (IsAuthenticated,)

def get(self, request, **kwargs):
"""
Return dislikes of an article
"""

try:
disliked_article = get_article(kwargs)
except Exception:
return Response({"response": "No article found"},
status=status.HTTP_204_NO_CONTENT)
dislikes = LikeDislikeArticle.objects.filter(
article=disliked_article)
dislikes_number = [
dislike for dislike in dislikes if dislike.is_disliked]
return Response({"response": len(dislikes_number)},
status=status.HTTP_200_OK)

def post(self, request, **kwargs):
"""
Like an article.
"""
disliked_article = None
disliker = None
try:
disliked_article = get_article(kwargs)
disliker = request.user
except Exception:
return Response({"response": "No article found"},
status=status.HTTP_204_NO_CONTENT)

try:
dislike = LikeDislikeArticle.objects.get(
article=disliked_article,
liker=disliker)
if dislike.is_disliked:
dislike.is_disliked = False
dislike.save()
return Response(
{"response": undisliked_response},
status=status.HTTP_200_OK)
dislike.is_liked = False
dislike.is_disliked = True
dislike.save()
return Response(
{"response": disliked_article_response},
status=status.HTTP_200_OK)
except Exception as e:
LikeDislikeArticle(
liker=disliker,
article=disliked_article,
is_disliked=True).save()
return Response(
{"response": "article successfully disliked"},
status=status.HTTP_200_OK)
29 changes: 29 additions & 0 deletions authors/apps/article/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,32 @@ def __str__(self):
Return a human readable format
"""
return self.rate


class LikeDislikeArticle(models.Model):
"""
This model holds likes of an article in a boolean format.
"""
liker = models.ForeignKey(
"authentication.User",
related_name="likearticle",
on_delete=models.CASCADE
)
article = models.ForeignKey(
"article.Article",
related_name="likearticle",
on_delete=models.CASCADE)
is_liked = models.BooleanField(
default=False,
null=False,
blank=False
)
is_disliked = models.BooleanField(
default=False,
null=False,
blank=False
)

def __str__(self):
"return human readable format"
return self.is_liked
80 changes: 80 additions & 0 deletions authors/apps/article/tests/base_like_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
from django.urls import reverse
import os
from ...authentication.models import User
from ..models import Article
from rest_framework.test import APIClient
from rest_framework.test import APITestCase


class BaseLikeTest(APITestCase):
""" class for testing like and dislike"""

def setUp(self):
"""
Prepare test environment for each testcase
"""

self.client = APIClient()
self.article = Article()
self.signup_url = reverse('authentication:register')
self.user_details = {
'user': {
'username': 'user1',
'email': 'evajohnson714@gmail.com',
'password': 'somepass12345',
}
}
self.user_details_2 = {
'user': {
'username': 'user2',
'email': 'evajohnson715s@gmail.com',
'password': 'somepass12345',
}
}
resp = self.client.post(
self.signup_url,
self.user_details,
format='json')
res = self.client.post(
self.signup_url,
self.user_details_2,
format='json')
self.token_2 = res.data['token']
self.token = resp.data['token']
self.email = "test_user@gmail.com"
self.name = "test"
self.user = User(username=self.name, email=self.email)
self.user.set_password("@Winners11")
self.user.save()
self.user_id = User.objects.get(email=self.email).pk
self.slug = "this-is-a-question"
title = "this is a question"
description = "this is a description"
body = "this is a body"
author = self.user
article = Article(
user=author,
slug=self.slug,
body=body,
title=title,
description=description
)
article.save()
self.rate_details = {
"user": {
"slug": self.slug,
"rate": 3
}
}
self.data = {}
self.rate_url = os.environ["URL"] + \
"api/article/" + self.slug + "/rate/"
self.view_rates_url = os.environ["URL"] + "api/article/rate/"
self.dislike_url = os.environ["URL"] + \
"api/article/" + "dislike/" + self.slug + "/"
self.view_dislikes_url = os.environ["URL"] + "api/article/rate/"
self.like_url = os.environ["URL"] + \
"api/article/" + "like/" + self.slug + "/"
self.view_likes_url = os.environ["URL"] + "api/article/rate/"
self.articles_url = os.environ["URL"] + "api/article/"
self.create_articles_url = os.environ["URL"] + "api/article/create"
5 changes: 0 additions & 5 deletions authors/apps/article/tests/templates/activate_account.html

This file was deleted.

81 changes: 81 additions & 0 deletions authors/apps/article/tests/test_dislike_an_article.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
from .base_like_test import BaseLikeTest
import os
from rest_framework import status


class TestDislikeArticle(BaseLikeTest):
"""Test dislike article class"""

def test_dislike_article_without_token(self):
"""
Test whether dislike request without token will fail
"""
response = self.client.post(self.dislike_url, self.data, format='json')
self.assertIn(
"Authentication credentials were not provided", str(
response.data))
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

def test_dislike_article_of_article_not_found(self):
"""
test whether dislike request with
an article slug that doesn't exist will fail
"""
slug = "s-sss-ss-s"
self.dislike_url = os.environ["URL"] + \
"api/article/" + "dislike/" + slug + "/"
self.client.credentials(HTTP_AUTHORIZATION='Bearer ' + self.token)
response = self.client.post(self.dislike_url, self.data, format='json')
self.assertIn("No article found", str(response.data))
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)

def test_dislike_article(self):
"""
test dislike article
"""

self.dislike_url = os.environ["URL"] + \
"api/article/" + "dislike/" + self.slug + "/"
self.client.credentials(HTTP_AUTHORIZATION='Bearer ' + self.token)
response = self.client.post(self.dislike_url, self.data, format='json')
self.assertIn("article successfully disliked", str(response.data))
self.assertEqual(response.status_code, status.HTTP_200_OK)

def test_get_dislike_article_with_no_likes(self):
"""
test dislike article
"""

self.dislike_url = os.environ["URL"] + \
"api/article/" + "dislike/" + self.slug + "/"
self.client.credentials(HTTP_AUTHORIZATION='Bearer ' + self.token)
response = self.client.get(self.dislike_url, self.data, format='json')
self.assertIn("0", str(response.data))
self.assertEqual(response.status_code, status.HTTP_200_OK)

def test_dislike_twice_article(self):
"""
test whether like request to an
already disliked article will undisliked it
"""

self.dislike_url = os.environ["URL"] + \
"api/article/" + "dislike/" + self.slug + "/"
self.client.credentials(HTTP_AUTHORIZATION='Bearer ' + self.token)
self.client.post(self.dislike_url, self.data, format='json')
response = self.client.post(self.dislike_url, self.data, format='json')
self.assertIn("article successfully undisliked", str(response.data))
self.assertEqual(response.status_code, status.HTTP_200_OK)

def test_get_dislikes_article(self):
"""
test get article dislikes
"""

self.dislike_url = os.environ["URL"] + \
"api/article/" + "dislike/" + self.slug + "/"
self.client.credentials(HTTP_AUTHORIZATION='Bearer ' + self.token)
response = self.client.post(self.dislike_url, self.data, format='json')
response = self.client.get(self.dislike_url, format='json')
self.assertIn("1", str(response.data))
self.assertEqual(response.status_code, status.HTTP_200_OK)
Loading

0 comments on commit 6ae16ee

Please sign in to comment.