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.core.urlresolvers import reverse
|
||||
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
|
||||
|
||||
def get_response_encoding(response):
|
||||
encoding = settings.DEFAULT_CHARSET
|
||||
|
||||
if response.has_header('content-encoding'):
|
||||
encoding = response['content-encoding']
|
||||
|
||||
return encoding
|
||||
|
||||
class ReverseTest(TestCase):
|
||||
def setUp(self):
|
||||
self.client = Client()
|
||||
@ -42,3 +54,142 @@ class ApiTest(TestCase):
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
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(
|
||||
'',
|
||||
url(r'^reverse.js$', cache_page(3600)(urls_js), name = 'js_reverse'),
|
||||
url(r'^duck/(?P<duck_id>\d+)/competence.json$', views.DuckCompListView.as_view(), name = 'complist'),
|
||||
url(
|
||||
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.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):
|
||||
template_name = 'api/duck_comp_list.json'
|
||||
@ -12,3 +17,77 @@ class DuckCompListView(generic.ListView):
|
||||
duck = get_object_or_404(Duck, pk = duck_id)
|
||||
|
||||
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/'
|
||||
|
||||
MAX_DUCK_LEVEL = 5
|
||||
COMP_WARN_LEVEL = 2
|
||||
MIN_FUZZY_SIMILARITY = 75
|
||||
|
Loading…
Reference in New Issue
Block a user