Skip to content

Commit

Permalink
feat(likes): Add user like article functionality
Browse files Browse the repository at this point in the history
- Add user like article
- Add count in article to increment when liked
- Add validation for user not liking same article twice

[Starts #165273480]
  • Loading branch information
JEAN MARCUS authored and JEAN MARCUS committed May 5, 2019
1 parent 0c53010 commit c4f6baf
Show file tree
Hide file tree
Showing 8 changed files with 378 additions and 11 deletions.
2 changes: 2 additions & 0 deletions authors/apps/articles/fixtures/article.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
"body": "The tech startapp harder to get into than Harvard",
"created_at": "2019-04-29T14:13:25.526681Z",
"updated_at": "2019-04-29T14:13:25.526692Z",
"likes_count": 1,
"dislikes_count": 0,
"favorited": false,
"favorite_count": 0,
"author_id": "jeanmarcus"
Expand Down
20 changes: 16 additions & 4 deletions authors/apps/articles/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Generated by Django 2.1 on 2019-05-02 06:27
# Generated by Django 2.1 on 2019-05-02 07:49

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone


class Migration(migrations.Migration):
Expand All @@ -21,11 +21,23 @@ class Migration(migrations.Migration):
('slug', models.SlugField(blank=True, null=True)),
('description', models.TextField()),
('body', models.TextField()),
('created_at', models.DateTimeField(default=django.utils.timezone.now)),
('updated_at', models.DateTimeField(default=django.utils.timezone.now)),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now_add=True)),
('likes_count', models.IntegerField(default=0)),
('dislikes_count', models.IntegerField(default=0)),
('favorited', models.BooleanField(default=False)),
('favorite_count', models.IntegerField(default=0)),
('author', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, to_field='username')),
],
),
migrations.CreateModel(
name='Like_Dislike',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('date_liked', models.DateTimeField(auto_now_add=True)),
('like_or_dislike', models.IntegerField()),
('article', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='articles.Article')),
('reviewer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, to_field='username')),
],
),
]
19 changes: 17 additions & 2 deletions authors/apps/articles/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,10 @@ class Article(models.Model):
null=True)
description = models.TextField()
body = models.TextField()
created_at = models.DateTimeField(default=timezone.now)
updated_at = models.DateTimeField(default=timezone.now)
created_at = models.DateTimeField(auto_now_add=True, editable=False)
updated_at = models.DateTimeField(auto_now_add=True)
likes_count = models.IntegerField(default=0)
dislikes_count = models.IntegerField(default=0)
favorited = models.BooleanField(default=False)
favorite_count = models.IntegerField(default=0)
author = models.ForeignKey(
Expand All @@ -37,3 +39,16 @@ def slug_generator(sender, instance, *args, **kwargs):


pre_save.connect(slug_generator, sender=Article)


class Like_Dislike(models.Model):
"""
Model class for liking or disliking an article
"""
date_liked = models.DateTimeField(auto_now_add=True, editable=False)
like_or_dislike = models.IntegerField()
reviewer = models.ForeignKey(
User, to_field='username', on_delete=models.CASCADE, null=False)
article = models.ForeignKey(
Article, to_field='id', on_delete=models.CASCADE, null=False
)
4 changes: 3 additions & 1 deletion authors/apps/articles/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def validate(self, data):
}

class Meta:
"""class for returning our field."""
"""class for returning our fields."""

comments = CommentSerializer(many=True)

Expand All @@ -59,6 +59,8 @@ class Meta:
'slug',
'created_at',
'updated_at',
'likes_count',
'dislikes_count',
'favorited',
'favorite_count',
'comments'
Expand Down
18 changes: 16 additions & 2 deletions authors/apps/articles/tests/test_article_crud.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

class ArticleCrudTest(BaseTestCase):
"""
Class Test Case for Testing user Login functionality
Class Test Case for Testing article crud functionality
"""
# Initialize fixture for the class Test Case
fixtures = ['authors/apps/articles/fixtures/article.json',
Expand Down Expand Up @@ -182,7 +182,7 @@ def test_delete_article(self):

def test_delete_article_not_found(self):
"""
Method tests deleting the non existant article
Method tests liking the non existant article
"""
url = reverse('articles-list-create')
response = self.client.post(
Expand All @@ -191,3 +191,17 @@ def test_delete_article_not_found(self):
response = self.client.delete(
url, HTTP_AUTHORIZATION=self.auth_header, format="json")
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

def test_delete_article_not_found_message(self):
"""
Method tests disliking the non existant article
"""
url = reverse('articles-list-create')
response = self.client.post(
url, self.create_article_data, HTTP_AUTHORIZATION=self.auth_header, format="json")
url = '/api/articles/1000/'
response = self.client.delete(
url, HTTP_AUTHORIZATION=self.auth_header, format="json")
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)


209 changes: 209 additions & 0 deletions authors/apps/articles/tests/test_likes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
# Django and Rest framework imports
from django.urls import reverse
from rest_framework import status
# Local imports
from .base import BaseTestCase
from authors.apps.authentication.models import User


class LikesTest(BaseTestCase):
"""
Class Test Case for Testing like and dislike functionality
"""
# Initialize fixture for the class Test Case
fixtures = ['authors/apps/articles/fixtures/article.json',
'authors/apps/articles/fixtures/user.json']

def test_user_like_article_status(self):
"""
Method tests the status on like article response
"""
url = reverse('articles-list-create')
response = self.client.post(
url, self.create_article_data, HTTP_AUTHORIZATION=self.auth_header, format="json")
article_id = response.data['id']
url = '/api/articles/{}/like/'.format(article_id)
response = self.client.post(
url, HTTP_AUTHORIZATION=self.auth_header, format="json")
self.assertEqual(response.status_code, status.HTTP_200_OK)

def test_user_like_article_message(self):
"""
Method tests liking the article response message
"""
url = reverse('articles-list-create')
response = self.client.post(
url, self.create_article_data, HTTP_AUTHORIZATION=self.auth_header, format="json")
article_id = response.data['id']
url = '/api/articles/{}/like/'.format(article_id)
response = self.client.post(
url, HTTP_AUTHORIZATION=self.auth_header, format="json")
self.assertEqual(response.data['success'],
"You have successfully liked this article.")

def test_user_like_article_twice_status(self):
"""
Method tests liking article twice status code
"""
url = reverse('articles-list-create')
response = self.client.post(
url, self.create_article_data, HTTP_AUTHORIZATION=self.auth_header, format="json")
article_id = response.data['id']
url = '/api/articles/{}/like/'.format(article_id)
response = self.client.post(
url, HTTP_AUTHORIZATION=self.auth_header, format="json")
response = self.client.post(
url, HTTP_AUTHORIZATION=self.auth_header, format="json")
self.assertEqual(response.status_code, status.HTTP_200_OK)

def test_user_like_article_twice_error_message(self):
"""
Method tests liking article twice error message
"""
url = reverse('articles-list-create')
response = self.client.post(
url, self.create_article_data, HTTP_AUTHORIZATION=self.auth_header, format="json")
article_id = response.data['id']
url = '/api/articles/{}/like/'.format(article_id)
response = self.client.post(
url, HTTP_AUTHORIZATION=self.auth_header, format="json")
response = self.client.post(
url, HTTP_AUTHORIZATION=self.auth_header, format="json")
self.assertEqual(response.data['message'],
"Your like has been revoked")

def test_user_dislike_article_status(self):
"""
Method tests the status on dislike article response
"""
url = reverse('articles-list-create')
response = self.client.post(
url, self.create_article_data, HTTP_AUTHORIZATION=self.auth_header, format="json")
article_id = response.data['id']
url = '/api/articles/{}/dislike/'.format(article_id)
response = self.client.post(
url, HTTP_AUTHORIZATION=self.auth_header, format="json")
self.assertEqual(response.status_code, status.HTTP_200_OK)

def test_user_dislike_article_message(self):
"""
Method tests disliking the article response message
"""
url = reverse('articles-list-create')
response = self.client.post(
url, self.create_article_data, HTTP_AUTHORIZATION=self.auth_header, format="json")
article_id = response.data['id']
url = '/api/articles/{}/dislike/'.format(article_id)
response = self.client.post(
url, HTTP_AUTHORIZATION=self.auth_header, format="json")
self.assertEqual(
response.data['success'], "You have successfully disliked this article.")

def test_user_dislike_article_twice_status(self):
"""
Method tests disliking article twice status code
"""
url = reverse('articles-list-create')
response = self.client.post(
url, self.create_article_data, HTTP_AUTHORIZATION=self.auth_header, format="json")
article_id = response.data['id']
url = '/api/articles/{}/dislike/'.format(article_id)
response = self.client.post(
url, HTTP_AUTHORIZATION=self.auth_header, format="json")
response = self.client.post(
url, HTTP_AUTHORIZATION=self.auth_header, format="json")
self.assertEqual(response.status_code, status.HTTP_200_OK)

def test_user_dislike_article_twice_error_message(self):
"""
Method tests disliking article twice error message
"""
url = reverse('articles-list-create')
response = self.client.post(
url, self.create_article_data, HTTP_AUTHORIZATION=self.auth_header, format="json")
article_id = response.data['id']
url = '/api/articles/{}/dislike/'.format(article_id)
response = self.client.post(
url, HTTP_AUTHORIZATION=self.auth_header, format="json")
response = self.client.post(
url, HTTP_AUTHORIZATION=self.auth_header, format="json")
self.assertEqual(response.data['message'],
"Your dislike has been revoked")

def test_user_like_article_not_found(self):
"""
Method tests response for like of article not found
"""
url = reverse('articles-list-create')
response = self.client.post(
url, self.create_article_data, HTTP_AUTHORIZATION=self.auth_header, format="json")
url = 'api/articles/100000/like'
response = self.client.post(
url, HTTP_AUTHORIZATION=self.auth_header, format="json")
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

def test_user_like_then_dislike_article(self):
"""
Method tests liking then disliking the article
"""
url = reverse('articles-list-create')
response = self.client.post(
url, self.create_article_data, HTTP_AUTHORIZATION=self.auth_header, format="json")
article_id = response.data['id']
url = '/api/articles/{}/like/'.format(article_id)
response = self.client.post(
url, HTTP_AUTHORIZATION=self.auth_header, format="json")
url = '/api/articles/{}/dislike/'.format(article_id)
response = self.client.post(
url, HTTP_AUTHORIZATION=self.auth_header, format="json")
self.assertEqual(response.data['success'],
"Your like for the article has changed to a dislike.")

def test_user_dislike_then_like_article(self):
"""
Method tests disliking then liking the article
"""
url = reverse('articles-list-create')
response = self.client.post(
url, self.create_article_data, HTTP_AUTHORIZATION=self.auth_header, format="json")
article_id = response.data['id']
url = '/api/articles/{}/dislike/'.format(article_id)
response = self.client.post(
url, HTTP_AUTHORIZATION=self.auth_header, format="json")
url = '/api/articles/{}/like/'.format(article_id)
response = self.client.post(
url, HTTP_AUTHORIZATION=self.auth_header, format="json")
self.assertEqual(response.data['success'],
"Your dislike for the article has changed to a like.")

def test_user_dislike_then_like_article_status(self):
"""
Method tests disliking then liking the article status code
"""
url = reverse('articles-list-create')
response = self.client.post(
url, self.create_article_data, HTTP_AUTHORIZATION=self.auth_header, format="json")
article_id = response.data['id']
url = '/api/articles/{}/dislike/'.format(article_id)
response = self.client.post(
url, HTTP_AUTHORIZATION=self.auth_header, format="json")
url = '/api/articles/{}/like/'.format(article_id)
response = self.client.post(
url, HTTP_AUTHORIZATION=self.auth_header, format="json")
self.assertEqual(response.status_code, status.HTTP_200_OK)

def test_user_like_then_dislike_article_status(self):
"""
Method tests disliking then liking the article status response
"""
url = reverse('articles-list-create')
response = self.client.post(
url, self.create_article_data, HTTP_AUTHORIZATION=self.auth_header, format="json")
article_id = response.data['id']
url = '/api/articles/{}/like/'.format(article_id)
response = self.client.post(
url, HTTP_AUTHORIZATION=self.auth_header, format="json")
url = '/api/articles/{}/dislike/'.format(article_id)
response = self.client.post(
url, HTTP_AUTHORIZATION=self.auth_header, format="json")
self.assertEqual(response.status_code, status.HTTP_200_OK)
4 changes: 3 additions & 1 deletion authors/apps/articles/urls.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
from django.urls import path
from .views import ListCreateArticles, RetrieveUpdateDestroyArticle
from .views import ListCreateArticles, RetrieveUpdateDestroyArticle, Like, Dislike


urlpatterns = [
path('articles/', ListCreateArticles.as_view(),
name="articles-list-create"),
path('articles/<int:pk>/', RetrieveUpdateDestroyArticle.as_view(),
name="article-get-update-delete"),
path('articles/<article_id>/like/', Like.as_view(), name="like-article" ),
path('articles/<article_id>/dislike/', Dislike.as_view(), name="dislike-article" )
]
Loading

0 comments on commit c4f6baf

Please sign in to comment.