Add Duck booking API method
This commit is contained in:
parent
15ad940445
commit
7facc7a1cf
151
api/tests.py
151
api/tests.py
@ -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)
|
||||||
|
17
api/urls.py
17
api/urls.py
@ -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'
|
||||||
|
),
|
||||||
)
|
)
|
||||||
|
81
api/views.py
81
api/views.py
@ -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})
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user