Skip to content

Commit

Permalink
feat(comment edit history): Get edit history
Browse files Browse the repository at this point in the history
- The user should be able to see the edit history of a comment which is saved when a user changes the comment

[Delivers #161966628]
  • Loading branch information
SilasKenneth committed Dec 21, 2018
1 parent 43eafe7 commit 6af6bba
Show file tree
Hide file tree
Showing 10 changed files with 304 additions and 95 deletions.
26 changes: 26 additions & 0 deletions authors/apps/articles/migrations/0006_commentedithistory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Generated by Django 2.1 on 2018-12-21 07:07

from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):

dependencies = [
('articles', '0005_auto_20181219_1816'),
]

operations = [
migrations.CreateModel(
name='CommentEditHistory',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('body', models.CharField(max_length=1000)),
('updated_at', models.DateTimeField(auto_now_add=True)),
('comment', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='articles.Comment')),
],
options={
'db_table': 'comment_edits',
},
),
]
13 changes: 13 additions & 0 deletions authors/apps/articles/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,7 @@ class BookMarkArticle(models.Model):
"""
model for holding users bookmarks. Allow user to bookmark an article only once
"""

class Meta:
"""
allow user to bookmark an article only once
Expand All @@ -197,3 +198,15 @@ def __str__(self):
return the name of the bookmarked article
"""
return self.article.article_slug


class CommentEditHistory(models.Model):
"""Model to hold the comment edit history"""
# The only thing needed is just a relationship to the which has been edited
comment = models.ForeignKey(Comment, on_delete=models.CASCADE)
body = models.CharField(max_length=1000)
updated_at = models.DateTimeField(auto_now_add=True)

class Meta:
"""Change the base table name"""
db_table = "comment_edits"
25 changes: 17 additions & 8 deletions authors/apps/articles/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,19 @@
from rest_framework.exceptions import ParseError

from authors.apps.profiles.serializers import ProfileSerializer
from .models import Article, Rating, ReportArticle, Comment, Reply, BookMarkArticle
from ..authentication.serializers import UserSerializer
from .models import Article, Rating, ReportArticle, Comment, Reply, BookMarkArticle, CommentEditHistory
from ..authentication.models import User
from rest_framework.validators import UniqueTogetherValidator
from ..authentication.serializers import UserSerializer


class ArticleTagSerializer(serializers.Field):
"""
class for handling article tags serialization.
"""

def to_internal_value(self, data):
if type(data) is not list:
raise ParseError("Expect 'tags' to be a list." )
raise ParseError("Expect 'tags' to be a list.")
return data

def to_representation(self, obj):
Expand All @@ -33,7 +34,7 @@ class ArticleSerializer(serializers.ModelSerializer):
author = serializers.HiddenField(
default=serializers.CurrentUserDefault()
)

class Meta:
"""
Method defines what fields of an article object should be displayed.
Expand Down Expand Up @@ -89,7 +90,7 @@ class ArticleAuthorSerializer(serializers.ModelSerializer):
title = serializers.CharField(max_length=200)
description = serializers.CharField()
body = serializers.CharField()
author = UserSerializer(read_only = True)
author = UserSerializer(read_only=True)
tags = serializers.SerializerMethodField(method_name='show_tags')
like = serializers.SerializerMethodField(method_name='like_article')
dislike = serializers.SerializerMethodField(method_name='dislike_article')
Expand Down Expand Up @@ -121,7 +122,6 @@ def dislike_article(self, instance):
user_id = request.user.id
return {'dislikeCount': instance.dislike.count()}


def favorite(self, instance):
"""favorite an article"""
request = self.context.get('request')
Expand Down Expand Up @@ -262,15 +262,24 @@ class Meta:
model = ReportArticle
fields = ('article', 'reported_by', 'report')


class BookMarkArticleSerializer(serializers.ModelSerializer):
"""
class to serialize bookmarked articles
"""
article_slug = serializers.CharField(source='article.article_slug')

class Meta:
model = BookMarkArticle
fields = [
'article_slug',
'id'
]


class CommentEditHistorySerializer(serializers.ModelSerializer):
class Meta:
model = CommentEditHistory
fields = [
'body',
'updated_at'
]
126 changes: 126 additions & 0 deletions authors/apps/articles/tests/test_comment_edit_history.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
import json

from django.test import TestCase, Client
from django.urls import reverse
from rest_framework import status
from rest_framework.test import APITestCase, APIClient


class TestCommentHistory(APITestCase):
def setUp(self):
self.client = APIClient()
self.token = self.login().get('token', 'badtoken')
self.COMMENT_URL = reverse("articles:update-delete-comment", kwargs={
"article_slug": "good-article",
"comment_pk": 1
})
self.comment = dict(
comment=dict(
body="I love playing nothing around"
)
)
self.modified_comment = dict(
comment=dict(
body="I love playing guitar around"
)
)
self.create_article()
self.create_comment()

def test_cannot_save_no_change(self):
url = self.COMMENT_URL.replace("/1/",
"/"+str(self.create_comment().get("comment",
{}).get('id', 1))+"/")
self.COMMENT_URL = url
response = self.client.put(url,
data=json.dumps(self.comment),
content_type="application/json",
HTTP_AUTHORIZATION="Token " + self.token)
url = self.COMMENT_URL.replace("/1/",
"/"+str(self.create_comment().get("comment",
{}).get('id', 1))+"/")
self.COMMENT_URL = url
response3 = self.client.get(url)
self.assertEqual(response3.status_code, status.HTTP_200_OK)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response3.data.get("previous_versions", [])), 0)

def test_can_save_edits(self):
url = self.COMMENT_URL.replace("/1/",
"/"+str(self.create_comment().get("comment",
{}).get('id', 1))+"/")
self.COMMENT_URL = url
response = self.client.put(url,
data=json.dumps(self.modified_comment),
content_type="application/json",
HTTP_AUTHORIZATION="Token " + self.token)
response2 = self.client.put(self.COMMENT_URL,
data=json.dumps(self.comment),
content_type="application/json",
HTTP_AUTHORIZATION="Token " + self.token)
response3 = self.client.get(self.COMMENT_URL)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response2.status_code, status.HTTP_200_OK)
self.assertEqual(2, len(response3.data.get("previous_versions", [])))

def test_can_get_edits(self):
url = self.COMMENT_URL.replace("/1/",
"/"+str(self.create_comment().get("comment",
{}).get('id', 1))+"/")
self.COMMENT_URL = url
self.update_comment()
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertNotEqual(response.data.get('previous_versions', ''), '')

def test_cannot_get_no_edits(self):
url = self.COMMENT_URL.replace("/1/",
"/"+str(self.create_comment().get("comment",
{}).get('id', 1))+"/")
response = self.client.get(url)
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data.get('previous_versions', ''), '')

def create_comment(self):
data = self.client.post(reverse("articles:list-create-comment", kwargs={
"article_slug": "good-article"
}),
data=json.dumps(self.comment),
content_type="application/json",
HTTP_AUTHORIZATION="Token " + self.token)
return data.data

def login(self):
self.register()
user_test = dict(user=dict(
email='silaskenn@gmail.com',
username='silaskenn',
password='Password@2019'
))
logged = self.client.post(reverse("authentication:user-login"), data=json.dumps(user_test),
content_type="application/json")
return logged.data

def register(self):
user_test = dict(user=dict(
email='silaskenn@gmail.com',
username='silaskenn',
password='Password@2019'
))
self.client.post(reverse("authentication:user-signup"), data=json.dumps(user_test),
content_type="application/json")

def create_article(self):
article = dict(article=dict(
title="Good article",
description='This article is too good for authorshaven',
body='Sometimes you just have to write code that only you understands'
))
self.client.post(reverse("articles:articles"), data=json.dumps(article),
content_type="application/json", HTTP_AUTHORIZATION='Token ' + self.token)

def update_comment(self):
res = self.client.put(self.COMMENT_URL,
data=json.dumps(self.modified_comment),
content_type="application/json",
HTTP_AUTHORIZATION="Token " + self.token)
6 changes: 3 additions & 3 deletions authors/apps/articles/tests/test_commenting_articles.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ def test_getting_a_non_existing_article_comments(self):
)
response = self.get_comments(token, invalid_url)
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
self.assertEqual(response.data['error'], 'Article with this slug not found')
self.assertEqual(response.data['error'], 'Article with that slug not found')

# test updating comment
def test_updating_a_comment(self):
Expand Down Expand Up @@ -155,7 +155,7 @@ def test_updating_missing_comment(self):
HTTP_AUTHORIZATION=token
)
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
self.assertEqual(response.data['error'], 'Comment with this ID not found')
self.assertEqual(response.data['error'], 'Comment with that ID not found')

def test_non_logged_in_user_cannot_update(self):
""" Test a user has to login before updating. """
Expand Down Expand Up @@ -239,7 +239,7 @@ def test_updating_comment_for_non_existing_article_slug(self):
data=self.comment_data2,
)
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
self.assertEqual(response.data['error'], 'Article with this slug not found')
self.assertEqual(response.data['error'], 'Article with that slug not found')

def test_deleting_comment_for_non_exisiting_article_slug(self):
"""
Expand Down
3 changes: 1 addition & 2 deletions authors/apps/articles/tests/test_ratings.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
APITestCase)
from rest_framework import status

@unittest.skip("Skip this class")
@unittest.skip("Not implemented")

class TestRatings(APITestCase):
def setUp(self):
self.token = self.login().get("token", "")
Expand Down
6 changes: 3 additions & 3 deletions authors/apps/articles/tests/test_replying_comments.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def test_replying_to_non_existing_article_comment(self):
HTTP_AUTHORIZATION=token
)
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
self.assertEqual(response.data['error'], 'Comment with that ID does not exist')
self.assertEqual(response.data['error'], 'Comment with this ID not found')

def test_replying_to_article_comment_with_invalid_article_slug(self):
"""
Expand All @@ -54,7 +54,7 @@ def test_replying_to_article_comment_with_invalid_article_slug(self):
url = reverse(
"articles:list-create-reply",
kwargs={
"article_slug": 'non-existing-article-slug',
"article_slug": 'non-existing-article-slugs',
'comment_pk': comment_id
}
)
Expand All @@ -65,7 +65,7 @@ def test_replying_to_article_comment_with_invalid_article_slug(self):
HTTP_AUTHORIZATION=token
)
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
self.assertEqual(response.data['error'], 'Article with that slug not found')
self.assertEqual(response.data['error'], 'Article with this slug not found')

def test_geting_comment_replies(self):
"""
Expand Down
1 change: 1 addition & 0 deletions authors/apps/articles/views/articles.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ def delete(self, request, slug):
except Exception:
return Response({'message': "article not found."})


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

Expand Down
Loading

0 comments on commit 6af6bba

Please sign in to comment.