Add Duck booking API method

This commit is contained in:
Gergely Polonkai 2015-01-22 16:22:57 +01:00 committed by Gergely Polonkai
parent 15ad940445
commit 7facc7a1cf
4 changed files with 247 additions and 3 deletions

View File

@ -1,9 +1,21 @@
from django.test import TestCase, Client from django.test import TestCase, Client
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.conf import settings
import json
from booking.ducklevel import level_to_up_minutes
from booking.models import Species, Location, Duck, Competence, DuckCompetence from booking.models import Species, Location, Duck, Competence, DuckCompetence
def get_response_encoding(response):
encoding = settings.DEFAULT_CHARSET
if response.has_header('content-encoding'):
encoding = response['content-encoding']
return encoding
class ReverseTest(TestCase): class ReverseTest(TestCase):
def setUp(self): def setUp(self):
self.client = Client() self.client = Client()
@ -42,3 +54,142 @@ class ApiTest(TestCase):
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertEqual(len(response.context['comp_list']), 1) self.assertEqual(len(response.context['comp_list']), 1)
class DuckBookingTest(TestCase):
username = 'admin'
password = 'password'
def setUp(self):
good_minutes = level_to_up_minutes(settings.COMP_WARN_LEVEL + 1)
bad_minutes = level_to_up_minutes(settings.COMP_WARN_LEVEL)
self.duck_id = 1
self.comp_id = 1
self.admin = User.objects.create_user(
username = self.username,
password = self.password)
self.admin.save()
spec = Species(name = 'duck')
spec.save()
loc = Location(name = 'temp')
loc.save()
self.comp_bad = Competence(
pk = self.comp_id,
name = 'test1',
added_by = self.admin)
self.comp_id += 1
self.comp_bad.save()
self.comp_good = Competence(
pk = self.comp_id,
name = 'test2',
added_by = self.admin)
self.comp_id += 1
self.comp_good.save()
self.duck = Duck(
pk = self.duck_id,
species = spec,
location = loc,
donated_by = self.admin)
self.duck_id += 1
self.duck.save()
dcomp = DuckCompetence(
duck = self.duck,
comp = self.comp_bad,
up_minutes = bad_minutes,
down_minutes = 0)
dcomp.save()
dcomp = DuckCompetence(
duck = self.duck,
comp = self.comp_good,
up_minutes = good_minutes,
down_minutes = 0)
dcomp.save()
self.client = Client()
def send_booking_json(self, json_data):
return self.client.post(
'/api/duck/book/',
json.dumps(json_data),
HTTP_X_REQUESTED_WITH = 'XMLHttpRequest',
content_type = 'application/json')
def test_book_nonlogged(self):
self.client.logout()
response = self.send_booking_json({
"duck_id": self.duck.pk,
"comp_id": self.comp_good.pk
})
self.assertEqual(response.status_code, 401)
def test_book_nonexist(self):
self.client.login(username = self.username, password = self.password)
# Try to book a non-existing Duck
response = self.send_booking_json({
"duck_id": self.duck.pk + 1,
"comp_id": self.comp_good.pk
})
self.assertEqual(response.status_code, 404)
# Try to book an existing Duck for a non-existing competence
response = self.send_booking_json({
"duck_id": self.duck.pk,
"comp_id": 3
})
self.assertEqual(response.status_code, 404)
def test_book_warn(self):
test_data = {
"duck_id": self.duck.pk,
"comp_id": self.comp_bad.pk
}
self.client.login(username = self.username, password = self.password)
response = self.send_booking_json(test_data)
self.assertEqual(response.status_code, 200)
j = json.loads(response.content.decode(get_response_encoding(response)))
self.assertIn('success', j)
self.assertEquals(j['success'], 1)
test_data['force'] = 1
response = self.send_booking_json(test_data)
self.assertEqual(response.status_code, 200)
j = json.loads(response.content.decode(get_response_encoding(response)))
self.assertIn('success', j)
self.assertEquals(j['success'], 2)
def test_book_good(self):
test_data = {
"duck_id": self.duck.pk,
"comp_id": self.comp_good.pk
}
self.client.login(username = self.username, password = self.password)
# Book the duck
response = self.send_booking_json(test_data)
self.assertEqual(response.status_code, 200)
j = json.loads(response.content.decode(get_response_encoding(response)))
self.assertIn('success', j)
self.assertEqual(j['success'], 2)
# Try to book again, it should fail
response = self.send_booking_json(test_data)
self.assertEqual(response.status_code, 200)
j = json.loads(response.content.decode(get_response_encoding(response)))
self.assertIn('success', j)
self.assertEqual(j['success'], 0)

View File

@ -6,6 +6,19 @@ from . import views
urlpatterns = patterns( urlpatterns = patterns(
'', '',
url(r'^reverse.js$', cache_page(3600)(urls_js), name = 'js_reverse'), url(
url(r'^duck/(?P<duck_id>\d+)/competence.json$', views.DuckCompListView.as_view(), name = 'complist'), r'^reverse.js$',
cache_page(3600)(urls_js),
name = 'js_reverse'
),
url(
r'^duck/book/$',
views.duck_book,
name = 'book'
),
url(
r'^duck/(?P<duck_id>\d+)/competence.json$',
views.DuckCompListView.as_view(),
name = 'complist'
),
) )

View File

@ -1,7 +1,12 @@
from django.http import JsonResponse, HttpResponse
from django.shortcuts import render, get_object_or_404 from django.shortcuts import render, get_object_or_404
from django.views import generic from django.views import generic
from django.conf import settings
from django.views.decorators.http import require_POST
from booking.models import Duck import json
from booking.models import Duck, Booking, Competence
class DuckCompListView(generic.ListView): class DuckCompListView(generic.ListView):
template_name = 'api/duck_comp_list.json' template_name = 'api/duck_comp_list.json'
@ -12,3 +17,77 @@ class DuckCompListView(generic.ListView):
duck = get_object_or_404(Duck, pk = duck_id) duck = get_object_or_404(Duck, pk = duck_id)
return duck.duckcompetence_set.all() return duck.duckcompetence_set.all()
@require_POST
def duck_book(request):
"""Book a duck to the logged in user.
Return value:
HttpResponse with status_code = 400 if response.jsondata misses
duck_id or comp_id
HttpResponse with status_code = 401 if the user is not authenticated
HttpResponse with status_code = 404 if the duck or comp is not found
response.jsondata.success = 0 if the duck is already booked
response.jsondata.success = 1 if the duck's competence is too low
(use request.jsondata.force = True
to force)
response.jsondata.success = 2 if the booking was successful"""
user = request.user
# Check if user is authenticated; if not, return HTTP 401
if not user.is_authenticated():
res = HttpResponse()
res.status_code = 401
return res
# Decode the request body
encoding = settings.DEFAULT_CHARSET if request.encoding == None else request.encoding
json_content = request.body.decode(encoding)
j = json.loads(json_content)
# If there is no duck_id or no comp_id in the request, return HTTP 400
if 'duck_id' not in j or 'comp_id' not in j:
res = HttpResponse()
res.status_code = 400
return res
duck_id = j['duck_id']
comp_id = j['comp_id']
# Find the duck and the competence; if any of them non-existant,
# return HTTP 404
duck = get_object_or_404(Duck, pk = duck_id)
comp = get_object_or_404(Competence, pk = comp_id)
# If the duck is already booked, return 0 as the result
if duck.booked_by() != None:
return JsonResponse({'success': 0})
# Result 0 means a problem
result = 0
comp_level = 0
# Check if the duck has the requested competence
dcomp_list = duck.duckcompetence_set.filter(comp = comp)
if len(dcomp_list) < 1:
comp_level = 0
else:
comp_level = dcomp_list[0].level()
# If the competence level is too low, set result to 1
if comp_level <= settings.COMP_WARN_LEVEL:
result = 1
# If the duck has high enough competence or the booking is forced,
# return success (2)
if result != 1 or 'force' in j:
result = 2
booking = Booking(duck = duck, user = user, comp_req = comp)
booking.save()
return JsonResponse({'success': result})

View File

@ -87,4 +87,5 @@ USE_TZ = True
STATIC_URL = '/static/' STATIC_URL = '/static/'
MAX_DUCK_LEVEL = 5 MAX_DUCK_LEVEL = 5
COMP_WARN_LEVEL = 2
MIN_FUZZY_SIMILARITY = 75 MIN_FUZZY_SIMILARITY = 75