Browse Source

Big refactor of views.

feature/python-error-tracking
Drew Larson 8 years ago
parent
commit
b6d2f5e88c
  1. 83
      bikeshop_project/registration/tests/test_utils.py
  2. 37
      bikeshop_project/registration/utils.py
  3. 32
      bikeshop_project/registration/views.py

83
bikeshop_project/registration/tests/test_utils.py

@ -0,0 +1,83 @@
from datetime import timedelta
from django.test import TestCase
from django.utils import timezone
from model_mommy import mommy
from core.models import Visit
from registration.models import Member
from registration.utils import signin_member, AlreadySignedInError, member_signed_in, get_signed_in_members
class GetSignedInMembersTests(TestCase):
def setUp(self):
self.now = timezone.now()
self.member1 = mommy.make(model=Member)
self.member2 = mommy.make(model=Member)
self.member3 = mommy.make(model=Member)
three_hours_ago = self.now - timedelta(hours=3)
five_hours_ago = self.now - timedelta(hours=5)
self.visit1 = Visit.objects.create(member=self.member1, purpose=Visit.DONATE, created_at=self.now)
self.visit2 = Visit.objects.create(member=self.member2, purpose=Visit.DONATE, created_at=three_hours_ago)
self.visit3 = Visit.objects.create(member=self.member3, purpose=Visit.DONATE, created_at=five_hours_ago)
def test_get_signed_in_members(self):
"""
Only members signed-in in the window are returned
"""
result1 = get_signed_in_members(end=self.now) # default window=4
self.assertEqual(len(result1), 2)
result2 = get_signed_in_members(window=2, end=self.now)
self.assertEqual(len(result2), 1)
result3 = get_signed_in_members(window=5, end=self.now)
self.assertEqual(len(result3), 3)
class SigninMember(TestCase):
def test_not_signed_in(self):
"""
A member who hasn't signed-in in 4 hours is signed-in.
"""
member = mommy.make(Member)
purpose = Visit.FIX
visit = signin_member(member, purpose)
self.assertIsInstance(visit, Visit)
def test_signed_in(self):
"""
A member who has signed-in in 4 hours is not signed-in.
"""
member = mommy.make(Member)
purpose = Visit.FIX
signin_member(member, purpose)
with self.assertRaises(AlreadySignedInError):
signin_member(member, purpose)
class CheckMemberSignedIn(TestCase):
def test_member_not_signed_in(self):
"""
Returns false when member is not signed-in
"""
not_signed_member = mommy.make(model=Member)
result = member_signed_in(not_signed_member)
self.assertFalse(result)
def test_member_signed_in(self):
"""
Returns true when member is signed-in
"""
member = mommy.make(model=Member)
Visit.objects.create(member=member, purpose=Visit.DONATE)
result = member_signed_in(member)
self.assertTrue(result)

37
bikeshop_project/registration/utils.py

@ -0,0 +1,37 @@
from datetime import datetime, timedelta
from typing import Optional
from django.db.models import QuerySet
from django.utils import timezone
from core.models import Visit
from registration.models import Member
class AlreadySignedInError(ValueError):
pass
def signin_member(member: Member, purpose: str) -> Visit:
"""
Signs in a member, creating a new `Visit`
:param member: the member to be signed in
:param purpose: The reason for visit. E.g. Fix a bike or volunteer
:return: a new `Visit`
:raise: `AlreadySignedInError` or `ValidationError`
"""
if not member_signed_in(member):
return Visit.objects.create(member=member, purpose=purpose)
raise AlreadySignedInError
def member_signed_in(member: Member, window: int = 4) -> bool:
return get_signed_in_members(window=window).filter(id__in=[member.id]).exists()
def get_signed_in_members(window: int = 4, end: Optional[datetime] = None) -> QuerySet:
new_end = end if end else timezone.now()
start = new_end - timedelta(hours=window)
visits = Visit.objects.filter(created_at__lte=new_end, created_at__gte=start)
return visits

32
bikeshop_project/registration/views.py

@ -1,27 +1,23 @@
import json import json
import logging
from datetime import timedelta
from django.contrib.auth.decorators import login_required from django.contrib.auth.decorators import login_required
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.http import HttpResponse, HttpResponseRedirect, JsonResponse from django.http import HttpResponse, HttpResponseRedirect, JsonResponse
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from django.template.response import TemplateResponse from django.template.response import TemplateResponse
from django.utils import timezone
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from django.views.generic import TemplateView, View from django.views.generic import TemplateView, View
from haystack.query import SearchQuerySet
from rest_framework import serializers
from rest_framework.renderers import JSONRenderer from rest_framework.renderers import JSONRenderer
from rest_framework.serializers import ModelSerializer from rest_framework.serializers import ModelSerializer
from core.models import Visit from core.models import Visit
from haystack.query import SearchQuerySet from registration.utils import signin_member, get_signed_in_members
from .forms import MemberForm from .forms import MemberForm
from .models import Member from .models import Member
logger = logging.getLogger('bikeshop')
@method_decorator(login_required, name='dispatch') @method_decorator(login_required, name='dispatch')
class MemberFormView(View): class MemberFormView(View):
@ -69,17 +65,23 @@ class MemberSearchView(View):
class MemberSerializer(ModelSerializer): class MemberSerializer(ModelSerializer):
first_name = serializers.CharField(allow_blank=True, required=False)
last_name = serializers.CharField(allow_blank=True, required=False)
class Meta: class Meta:
model = Member model = Member
fields = ('full_name', 'email', 'id') fields = ('first_name', 'last_name', 'email', 'id')
class VisitSerializer(ModelSerializer): class VisitSerializer(ModelSerializer):
member = MemberSerializer() member = MemberSerializer()
class Meta: class Meta:
model = Visit model = Visit
fields = ('created_at', 'purpose', 'member') fields = ('created_at', 'purpose', 'member')
depth = 1 depth = 1
class MemberSignIn(View): class MemberSignIn(View):
@method_decorator(csrf_exempt) @method_decorator(csrf_exempt)
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
@ -87,21 +89,17 @@ class MemberSignIn(View):
def post(self, request): def post(self, request):
member = get_object_or_404(Member, id=request.POST.get('id')) member = get_object_or_404(Member, id=request.POST.get('id'))
Visit.objects.create(member=member, purpose=request.POST.get('purpose')) visit = signin_member(member, request.POST.get('purpose'))
data = json.dumps(dict(results=dict(id=member.id))) data = json.dumps(dict(results=dict(id=member.id, created_at=visit.created_at.isoformat())))
return JsonResponse(data=data, safe=False, status=201) return JsonResponse(data=data, safe=False, status=201)
def get(self, request): def get(self, request):
start = timezone.now() visits = get_signed_in_members().prefetch_related()
end = start + timedelta(hours=4)
visits = Visit.objects.filter(created_at__lte=end,
created_at__gte=start).prefetch_related()
serializer = VisitSerializer(visits, many=True) serializer = VisitSerializer(visits, many=True)
json = JSONRenderer().render(serializer.data) results_json = JSONRenderer().render(serializer.data)
return JsonResponse(data=json.decode(), safe=False, status=200) return JsonResponse(data=results_json.decode(), safe=False, status=200)
@method_decorator(login_required, name='dispatch') @method_decorator(login_required, name='dispatch')

Loading…
Cancel
Save