Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add comment to a hearing. Closes #55 #62

Merged
merged 1 commit into from
Nov 6, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion kk/models/hearing.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

from .base import ModifiableModel
from .images import WithImageMixin
from .comment import WithCommentMixin


class Label(ModifiableModel):
Expand All @@ -15,7 +16,7 @@ def __str__(self):
return self.label


class Hearing(WithImageMixin, ModifiableModel):
class Hearing(WithCommentMixin, WithImageMixin, ModifiableModel):
COMMENT_OPTION_DISALLOW = '1'
COMMENT_OPTION_REGISTERED = '2'
COMMENT_OPTION_ANONYMOUS = '3'
Expand Down
10 changes: 10 additions & 0 deletions kk/tests/base.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import pytest
import json

from django.contrib.auth.models import User
from django.test.client import Client as DjangoTestClient

from kk.models import Hearing
Expand All @@ -14,6 +15,9 @@ def setup(self):
self.client = DjangoTestClient()
self.base_endpoint = '/v1'
self.hearing_endpoint = '%s/hearing/' % self.base_endpoint
self.username = 'testresident'
self.email = 'testresident@helo.fi'
self.password = 'password'

def get_hearing_detail_url(self, id, element=None):
element = '' if element is None else '/%s' % element
Expand All @@ -22,6 +26,12 @@ def get_hearing_detail_url(self, id, element=None):
def get_data_from_response(self, response):
return json.loads(response.content.decode('utf-8'))

def user_login(self):
user = User.objects.create_user(self.username, self.email, self.password)
assert user is not None
result = self.client.login(username=self.username, password=self.password)
assert result is True


@pytest.mark.django_db
class BaseKKDBTest(BaseKKTest):
Expand Down
63 changes: 63 additions & 0 deletions kk/tests/test_comment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import pytest
import datetime
import urllib
import os

from django.conf import settings

from kk.models import Hearing, Comment
from kk.tests.base import BaseKKDBTest, default_hearing


class TestComment(BaseKKDBTest):

def setup(self):
super(TestComment, self).setup()

self.default_content = 'I agree with you sir Lancelot. My favourite colour is blue'
self.comment_data = {
'content': self.default_content,
}

def test_55_add_comment_without_authentication(self, default_hearing):
# post data to hearing ednpoint /v1/hearings/<hearingID>/comments/
response = self.client.post(self.get_hearing_detail_url(default_hearing.id, 'comments'), data=self.comment_data)
assert response.status_code == 403

def test_55_add_comment_to_hearing_empty_data(self, default_hearing):
# authenticate first
self.user_login()

# post data to hearing ednpoint /v1/hearings/<hearingID>/comments/
response = self.client.post(self.get_hearing_detail_url(default_hearing.id, 'comments'), data=None)
assert response.status_code == 400

data = self.get_data_from_response(response)
assert data is not None

def test_55_add_comment_to_hearing_invalid_data(self, default_hearing):
# authenticate first
self.user_login()

# post data to hearing ednpoint /v1/hearings/<hearingID>/comments/
invalid_data = {
'invalidKey': 'Korben Dallas multipass'
}
response = self.client.post(self.get_hearing_detail_url(default_hearing.id, 'comments'), data=invalid_data)
assert response.status_code == 400

data = self.get_data_from_response(response)
assert data is not None

def test_55_add_comment_to_hearing(self, default_hearing):
# authenticate first
self.user_login()

# post data to hearing ednpoint /v1/hearings/<hearingID>/comments/
response = self.client.post(self.get_hearing_detail_url(default_hearing.id, 'comments'), data=self.comment_data)
assert response.status_code in [200, 201]

data = self.get_data_from_response(response)
assert data['created_by'] == self.username
assert data['content'] == self.default_content
assert data['votes'] == 0
18 changes: 18 additions & 0 deletions kk/views/base.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from rest_framework import serializers


# Serializer for user field


class UserFieldSerializer(serializers.ModelSerializer):

def to_representation(self, user):
return user.username


# Serializer for created_by


class CreatedBySerializer(serializers.ModelSerializer):

created_by = UserFieldSerializer()
33 changes: 33 additions & 0 deletions kk/views/comment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from rest_framework import serializers

from kk.models import Comment
from .base import CreatedBySerializer


# Serializer for comment


class CommentSerializer(CreatedBySerializer, serializers.ModelSerializer):

class Meta:
model = Comment
fields = ['content', 'votes', 'created_by', 'created_at']


# Serializer to create comment

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should use DocStrings instead of Comments


class CommentCreateSerializer(serializers.ModelSerializer):

class Meta:
model = Comment
fields = ['content']


# Serializer for 'comments' field.


class CommentFieldSerializer(serializers.RelatedField):

def to_representation(self, comment):
return CommentSerializer(comment).data
40 changes: 38 additions & 2 deletions kk/views/hearing.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,15 @@
from rest_framework import filters
from rest_framework.decorators import detail_route
from rest_framework.response import Response
from rest_framework import permissions
from rest_framework import status

from kk.models import Hearing
from kk.models import Hearing, Comment

from .image import ImageFieldSerializer, ImageSerializer
from .introduction import IntroductionFieldSerializer, IntroductionSerializer
from .scenario import ScenarioFieldSerializer, ScenarioSerializer
from .comment import CommentFieldSerializer, CommentSerializer, CommentCreateSerializer


class HearingFilter(django_filters.FilterSet):
Expand All @@ -34,13 +37,14 @@ class HearingSerializer(serializers.ModelSerializer):
images = ImageFieldSerializer(many=True, read_only=True)
introductions = IntroductionFieldSerializer(many=True, read_only=True)
scenarios = ScenarioFieldSerializer(many=True, read_only=True)
comments = CommentFieldSerializer(many=True, read_only=True)

class Meta:
model = Hearing
fields = ['abstract', 'heading', 'content', 'id', 'borough', 'n_comments',
'labels', 'close_at', 'created_at', 'latitude', 'longitude',
'servicemap_url', 'images', 'introductions', 'scenarios', 'images',
'closed']
'closed', 'comments']


class HearingViewSet(viewsets.ReadOnlyModelViewSet):
Expand All @@ -50,6 +54,7 @@ class HearingViewSet(viewsets.ReadOnlyModelViewSet):
queryset = Hearing.objects.all()
serializer_class = HearingSerializer
filter_backends = (filters.DjangoFilterBackend, filters.OrderingFilter)
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
#ordering_fields = ('created_at',)
#ordering = ('-created_at',)
#filter_class = HearingFilter
Expand Down Expand Up @@ -99,6 +104,37 @@ def scenarios(self, request, pk=None):
serializer = ScenarioSerializer(scenarios, many=True)
return Response(serializer.data)

def create_comment(self, hearing, request):
# FIXME no idea how to validate empty data or missing keys in data via CommentCreateSerializer
if len(request.data) == 0 or 'content' not in request.data:
return Response({'detail': 'Missing content'}, status=status.HTTP_400_BAD_REQUEST)

serializer = CommentCreateSerializer(data=request.data)
if serializer.is_valid():
comment = Comment.objects.create(
content=serializer.data['content'],
created_by=request.user,
)
return Response(CommentSerializer(comment).data)
else:
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

@detail_route(methods=['get', 'post'])
def comments(self, request, pk=None):
hearing = self.get_object()

if request.method == 'POST':
return self.create_comment(hearing, request)

comments = hearing.comments.all()
page = self.paginate_queryset(comments)
if page is not None:
serializer = CommentSerializer(page, many=True)
return self.get_paginated_response(serializer.data)

serializer = CommentSerializer(comments, many=True)
return Response(serializer.data)

# temporary for query debug purpose
def _list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
Expand Down