Skip to content

Commit

Permalink
Merge pull request #101 from andela-kanyanwu/staging
Browse files Browse the repository at this point in the history
Staging
  • Loading branch information
kosyfrances committed May 20, 2016
2 parents 1d69342 + fe94078 commit 337a9b6
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 34 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ django_foodbot/staticfiles/
.env.yml

.coverage.*
plans
2 changes: 1 addition & 1 deletion django_foodbot/api/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def __unicode__(self):
class Rating(models.Model):

created_at = models.DateTimeField(auto_now_add=True)
user_id = models.CharField(max_length=20)
user_id = models.CharField(max_length=20, blank=False, null=False)
menu = models.ForeignKey(Menu, related_name='rating')
rate = models.IntegerField(blank=False, null=False)
comment = models.TextField(default='no comment')
Expand Down
2 changes: 1 addition & 1 deletion django_foodbot/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ class RatingSerializer(serializers.ModelSerializer):

class Meta:
model = Rating
fields = ('id', 'created_at', 'user_id', 'menu', 'rate', 'comment')
fields = ('id', 'created_at', 'user_id', 'rate', 'comment', 'menu')
111 changes: 97 additions & 14 deletions django_foodbot/api/tests/test_api.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,117 @@
from rest_framework.test import APIClient
import json
import mock
from datetime import datetime

from django.utils import timezone
from django.core.urlresolvers import reverse_lazy
from rest_framework.test import APITestCase

from rest_framework import status
from rest_framework.test import APIClient, APITestCase

from api.models import Menu, Rating


class FoodBotApiTestCase(APITestCase):
"""Class defined to test foodbot api."""

'''Class defined to test foodbot api.'''
def setUp(self):
self.client = APIClient()
self.menu = Menu.objects.create(day='monday', food='rice',
meal='lunch', option=1, week=1)
self.Rating = Rating.objects.create(created_at='2015-11-04 06:42:20.5587',
user_id='U0BT88BS', menu=self.menu,
rate=3, comment='wonderful')
old_testtime = datetime(2016, 4, 20, 11, 11, 16, 398810)

self.menu = Menu.objects.create(day='monday', food='rice', meal='lunch',
option=1, week=1)
with mock.patch('django.utils.timezone.now') as mock_now:
mock_now.return_value = old_testtime
self.rating = Rating.objects.create(created_at=old_testtime,
user_id='U0BT88BS', menu=self.menu,
rate=3, comment='good')


class TestMenu(FoodBotApiTestCase):
"""Test for menu endpoint."""

def test_get_menu_list_when_menu_exist(self):
url = reverse_lazy('menulist')
response = self.client.get(url)
expected_content = {'id': 1, 'day': 'monday', 'food': 'rice',
'meal': 'lunch', 'option': 1, 'week': 1}

def test_get_menu_list(self):
self.assertTrue(status.is_success(response.status_code))
self.assertDictEqual(json.loads(response.content)['results'][0],
expected_content)

def test_get_menu_list_when_no_menu_exist(self):
Menu.objects.all().delete()
url = reverse_lazy('menulist')
response = self.client.get(url)
self.assertEqual(response.status_code, 200)

def test_get_rating_list(self):
self.assertTrue(status.is_success(response.status_code))
self.assertEqual(json.loads(response.content)['results'], [])


class TestRating(FoodBotApiTestCase):
"""Test for rating endpoint."""

def test_get_all_rating_list_when_rating_exist(self):
url = reverse_lazy('ratinglist')
response = self.client.get(url)
self.assertEqual(response.status_code, 200)
expected_content = {'id': 4, 'created_at': '2016-04-20T10:11:16.398810Z',
'user_id': 'U0BT88BS', 'rate': 3, 'comment': 'good',
'menu': {'week': 1, 'option': 1, 'food': 'rice',
'id': 4, 'meal': 'lunch', 'day': 'monday'}
}

def test_get_weekly_ratings(self):
self.assertTrue(status.is_success(response.status_code))
self.assertDictEqual(json.loads(response.content)['results'][0],
expected_content)

def test_no_weekly_ratings_is_returned_when_there_is_none_for_the_week(self):
url = reverse_lazy('weeklyratinglist')
response = self.client.get(url)
self.assertEqual(response.status_code, 200)

self.assertTrue(status.is_success(response.status_code))
self.assertEqual(json.loads(response.content)['results'], [])

def test_weekly_ratings_is_returned_when_it_exist_for_the_week(self):
# Create a new rating for current week using mock time
current_testtime = timezone.now()
with mock.patch('django.utils.timezone.now') as mock_now:
mock_now.return_value = current_testtime
Rating.objects.create(created_at=current_testtime, user_id='U0BT88BS',
menu=self.menu, rate=3)

url = reverse_lazy('weeklyratinglist')
response = self.client.get(url)
testtime = current_testtime.strftime("%Y-%m-%dT%H:%M:%S.%fZ")

expected_content = {'comment': 'no comment', 'user_id': 'U0BT88BS',
'created_at': testtime, 'rate': 3, 'id': 10,
'menu': {'week': 1, 'option': 1, 'food': 'rice',
'id': 8, 'meal': 'lunch', 'day': 'monday'}
}

self.assertTrue(status.is_success(response.status_code))
self.assertDictEqual(json.loads(response.content)['results'][0],
expected_content)

def test_get_all_rating_list_when_no_rating_exist(self):
Rating.objects.all().delete()
url = reverse_lazy('ratinglist')
response = self.client.get(url)

self.assertTrue(status.is_success(response.status_code))
self.assertEqual(json.loads(response.content)['results'], [])

def test_post_ratings(self):
url = reverse_lazy('addrating', kwargs={'id': 7})
data = {'user_id': '1', 'rate': 5}
response = self.client.post(url, data)

self.assertTrue(status.is_success(response.status_code))

def test_post_rating_with_invalid_meal_id(self):
url = reverse_lazy('addrating', kwargs={'id': 50})
data = {'user_id': '1', 'rate': 5}
response = self.client.post(url, data)

self.assertTrue(status.is_client_error(response.status_code))
4 changes: 3 additions & 1 deletion django_foodbot/api/urls.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
'''API urls defined for views.'''
"""API urls defined for views."""

from django.conf.urls import url

Expand All @@ -12,6 +12,8 @@
url(r'^rating/all/$', views.RatingList.as_view(), name='ratinglist'),
url(r'^rating/week/$', views.WeeklyRatings.as_view(),
name='weeklyratinglist'),
url(r'^rating/(?P<id>[0-9]+)/create/$', views.PostRatings.as_view(),
name='addrating'),
]


Expand Down
31 changes: 19 additions & 12 deletions django_foodbot/api/views.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
from datetime import datetime
from datetime import timedelta
from datetime import datetime, timedelta

from django.shortcuts import get_object_or_404

from rest_framework import filters
from rest_framework.generics import ListAPIView
from rest_framework.generics import ListAPIView, CreateAPIView

from api.models import Menu, Rating
from api.serializers import RatingSerializer, MenuSerializer
from api.setpage import LimitOffsetpage


class MenuList(ListAPIView):
"""List all the Menu items."""

"""
List all the Menu items.
"""
model = Menu
serializer_class = MenuSerializer
pagination_class = LimitOffsetpage
Expand All @@ -31,9 +30,8 @@ def get_queryset(self):


class RatingList(ListAPIView):
"""
List all ratings and comments
"""
"""List all ratings and comments."""

model = Rating
serializer_class = RatingSerializer
pagination_class = LimitOffsetpage
Expand All @@ -51,9 +49,8 @@ def get_queryset(self):


class WeeklyRatings(ListAPIView):
"""
List all ratings and comments for the week
"""
"""List all ratings and comments for the week."""

model = Rating
serializer_class = RatingSerializer
pagination_class = LimitOffsetpage
Expand All @@ -67,3 +64,13 @@ def get_queryset(self):
queryset = Rating.objects.filter(created_at__range=[startdate, enddate])

return queryset


class PostRatings(CreateAPIView):
"""Post ratings and comments."""

serializer_class = RatingSerializer

def perform_create(self, serializer):
menu = get_object_or_404(Menu, pk=self.kwargs.get('id'))
serializer.save(menu=menu)
23 changes: 19 additions & 4 deletions plugins/food_bot_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def process_message(data):

class Helper:
"""
Contains helper functions for validation and and sending the right context
Contains helper functions for validation and sending the right context.
"""
@staticmethod
def get_day_of_week():
Expand Down Expand Up @@ -155,6 +155,18 @@ def check_rating(rating_val):
else:
return True

@staticmethod
def check_multiple_rating(user_id, meal):
sql = CustomSQL()
variables = (user_id, meal,)

query = 'SELECT count(rating.id) FROM rating INNER JOIN menu_table ON menu_table.id = menu_id WHERE rating.user_id = (%s) AND menu_table.meal = (%s) AND rating.created_at::date = now()::date'
result = sql.query(query, variables)
if int(result[0][0]) > 0:
return True
else:
return False

@staticmethod
def get_rate_template_context(buff, user_id):
"""
Expand All @@ -175,16 +187,19 @@ def get_rate_template_context(buff, user_id):
check_option = Helper.check_option_selected(option, day, week,
meal)

if Helper.check_meal_selected(meal) is False:
if not Helper.check_meal_selected(meal):
return {'template': 'invalid_meal', 'context': {}}

if check_option['bool'] is False:
if not check_option['bool']:
return {'template': 'invalid_option',
'context': {'option_count': check_option['option']}}

if Helper.check_rating(rating) is False:
if not Helper.check_rating(rating):
return {'template': 'invalid_rating', 'context': {}}

if Helper.check_multiple_rating(user_id, meal):
return {'template': 'multiple_rating', 'context': {}}

variables = (meal, day, week, option,)
sql = CustomSQL()
query_string = 'SELECT id FROM menu_table WHERE meal = (%s) AND day = (%s) AND week = (%s) AND option = (%s)'
Expand Down
1 change: 1 addition & 0 deletions templates/multiple_rating.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
```You can only rate once``` :frowning:
2 changes: 1 addition & 1 deletion templates/rating_response.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
```Thanks for rating``` :smile:
```Thanks for rating``` :smile:
21 changes: 21 additions & 0 deletions tests/rate_menu_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,14 @@ def test_check_rating(self):
self.assertFalse(Helper.check_rating('w'))
self.assertFalse(Helper.check_rating('asdf'))

@patch.object(CustomSQL, 'query', return_value=[(0,)])
def test_check_multiple_rating_returns_false_if_count_is_zero(self, *args):
self.assertFalse(Helper.check_multiple_rating(self.user_id, 'breakfast'))

@patch.object(CustomSQL, 'query', return_value=[(3L,)])
def test_check_multiple_rating_returns_true_if_count_greater_than_zero(self, *args):
self.assertTrue(Helper.check_multiple_rating(self.user_id, 'breakfast'))

@patch.object(Helper, 'get_day_of_week', return_value='saturday')
@patch.object(Helper, 'get_week_number', return_value=2)
def test_user_gets_weekend_rate_error_on_weekend(self, *args):
Expand Down Expand Up @@ -97,6 +105,7 @@ def test_invalid_rating_returns_correct_error_template(self, *args):
@patch.object(CustomSQL, 'command', return_value='command object')
@patch.object(Helper, 'get_day_of_week', return_value='monday')
@patch.object(Helper, 'get_week_number', return_value='1')
@patch.object(Helper, 'check_multiple_rating', return_value=0)
def test_valid_rate_returns_correct_template(self, *args):
buff = ['rate', 'breakfast', '2', '5']

Expand All @@ -106,3 +115,15 @@ def test_valid_rate_returns_correct_template(self, *args):
'context': {}})
CustomSQL.query.assert_called_with(
'SELECT id FROM menu_table WHERE meal = (%s) AND day = (%s) AND week = (%s) AND option = (%s)', ('breakfast', 'monday', '1', '2'))

@patch.object(CustomSQL, 'query', return_value=[(3L,)])
@patch.object(CustomSQL, 'command', return_value='command object')
@patch.object(Helper, 'get_day_of_week', return_value='monday')
@patch.object(Helper, 'get_week_number', return_value='1')
@patch.object(Helper, 'check_multiple_rating', return_value=1)
def test_multiple_check_template_rendered_if_rate_count_is_greater_than_zero(self, *args):
buff = ['rate', 'breakfast', '2', '5']

rate_context = Helper.get_rate_template_context(buff, self.user_id)
self.assertEqual(rate_context, {'template': 'multiple_rating',
'context': {}})

0 comments on commit 337a9b6

Please sign in to comment.