Complete all major API endpoints for prototype

This commit is contained in:
Tanner Collin 2017-06-18 00:11:49 +00:00
parent 170878441e
commit 3823c887b6
6 changed files with 372 additions and 72 deletions

View File

@ -1,3 +1,11 @@
from django.contrib import admin
from .models import UserInfo, Client, Provider, WorkType, Manage, Price, Shift
# Register your models here.
admin.site.register(UserInfo)
admin.site.register(Client)
admin.site.register(Provider)
admin.site.register(WorkType)
admin.site.register(Manage)
admin.site.register(Price)
admin.site.register(Shift)

View File

@ -6,39 +6,59 @@ from django.core.validators import RegexValidator
class UserInfo(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
phone_regex = RegexValidator(regex=r'^\+?1?\d{9,15}$', message="Phone number must be entered in the format: '+999999999'. Up to 15 digits allowed.")
phone_number = models.CharField(validators=[phone_regex], max_length=16, blank=True)
USER_TYPES = (('C', 'Client'), ('P', 'Provider'))
user_type = models.CharField(max_length=1, choices=USER_TYPES, blank=True)
phone_number = models.CharField(validators=[phone_regex], max_length=16)
def __str__(self):
return 'UserInfo: ' + self.user.username
class Client(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
business_number = models.CharField(max_length=16, blank=True)
business_number = models.CharField(max_length=16)
def __str__(self):
return 'Client: ' + self.user.username
class Provider(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
sin = models.CharField(max_length=16, blank=True)
sin = models.CharField(max_length=16)
class Work(models.Model):
client = models.ForeignKey(Client, on_delete=models.CASCADE)
color = models.CharField(max_length=16, blank=True)
label = models.CharField(max_length=100, blank=True)
def __str__(self):
return 'Provider: ' + self.user.username
class WorkType(models.Model):
client = models.ForeignKey(Client, related_name='work_types', on_delete=models.CASCADE)
color = models.CharField(max_length=16)
label = models.CharField(max_length=100)
deleted = models.BooleanField(default=False)
def __str__(self):
return 'WorkType: ' + self.label + ' of ' + self.client.user.username
class Manage(models.Model):
client = models.ForeignKey(Client, on_delete=models.CASCADE)
provider = models.ForeignKey(Provider, on_delete=models.CASCADE)
client = models.ForeignKey(Client, related_name='employees', on_delete=models.CASCADE)
provider = models.ForeignKey(Provider, related_name='employers', on_delete=models.CASCADE)
note = models.CharField(max_length=500, blank=True)
approved = models.NullBooleanField(blank=True)
deleted = models.BooleanField(default=False)
def __str__(self):
return self.client.user.username + ' manages ' + self.provider.user.username
class Price(models.Model):
client = models.ForeignKey(Client, on_delete=models.CASCADE)
provider = models.ForeignKey(Provider, on_delete=models.CASCADE)
work = models.ForeignKey(Work, on_delete=models.CASCADE)
management = models.ForeignKey(Manage, related_name='prices', on_delete=models.CASCADE)
work_type = models.ForeignKey(WorkType, on_delete=models.CASCADE)
amount = models.DecimalField(max_digits=8, decimal_places=2)
deleted = models.BooleanField(default=False)
class Shift(models.Model):
client = models.ForeignKey(Client, on_delete=models.CASCADE)
provider = models.ForeignKey(Provider, on_delete=models.CASCADE)
work = models.ForeignKey(Work, on_delete=models.CASCADE)
price = models.ForeignKey(Price, on_delete=models.CASCADE)
set_price = models.DecimalField(max_digits=8, decimal_places=2, null=True)
set_date = models.DateField()
set_start = models.DateTimeField()
set_end = models.DateTimeField()
amount = models.DecimalField(max_digits=8, decimal_places=2)
description = models.CharField(max_length=100, blank=True)
actual_start = models.DateTimeField(null=True)
actual_end = models.DateTimeField(null=True)
amount = models.DecimalField(max_digits=8, decimal_places=2, null=True)
description = models.CharField(max_length=100, null=True)
chart = models.TextField(max_length=1000, null=True)
deleted = models.BooleanField(default=False)

View File

@ -1,20 +1,3 @@
from pprint import pprint
from rest_framework import permissions
from caremyway.api.models import Client, Provider
class UserTypePermission(permissions.BasePermission):
"""
Disallow creation of client or provider if one already exists
"""
message = "User is already either a client or a provider."
def has_permission(self, request, view):
user = request.data.get('user', None)
if request.method != 'POST' or user is None:
return True
elif not Client.objects.filter(user=user).exists() \
and not Provider.objects.filter(user=user).exists():
return True
else:
return False

View File

@ -1,32 +1,255 @@
from datetime import datetime, timedelta, timezone
from decimal import Decimal
from django.contrib.auth.models import User, Group
from django.shortcuts import get_object_or_404
from rest_framework import serializers
from caremyway.api.models import UserInfo, Client, Provider
from caremyway.api.models import UserInfo, Client, Provider, WorkType, Manage, Price, Shift
class UserInfoSerializer(serializers.ModelSerializer):
class Meta:
model = UserInfo
fields = ('user', 'user_type', 'phone_number')
fields = ('phone_number',)
class ChosenUserInfoSerializer(UserInfoSerializer):
class Meta(UserInfoSerializer.Meta):
read_only_fields = ('user_type',)
def create(self, validated_data):
validated_data['user'] = self.context['request'].user
return serializers.ModelSerializer.create(self, validated_data)
class WorkTypeSerializer(serializers.ModelSerializer):
class Meta:
model = WorkType
fields = ('id', 'color', 'label', 'deleted')
read_only_fields =('deleted',)
def create(self, validated_data):
validated_data['client'] = self.context['request'].user.client
return serializers.ModelSerializer.create(self, validated_data)
class PriceSerializer(serializers.ModelSerializer):
get_employee_id = serializers.IntegerField(write_only=True)
get_work_type_id = serializers.IntegerField(write_only=True)
work_type = WorkTypeSerializer(read_only=True)
class Meta:
model = Price
fields = ('id', 'get_employee_id', 'get_work_type_id', 'work_type', 'amount', 'deleted')
read_only_fields =('deleted',)
depth = 1
def create(self, validated_data):
user = self.context['request'].user
if not Client.objects.filter(user=user).exists():
raise serializers.ValidationError("User is not a client.")
client = user.client
manage_objs = Manage.objects.filter(client=client).filter(deleted=False)
employee_id = validated_data.pop('get_employee_id')
employee = get_object_or_404(manage_objs, id=employee_id)
worktype_objs = WorkType.objects.filter(client=client).filter(deleted=False)
work_type_id = validated_data.pop('get_work_type_id')
work_type = get_object_or_404(worktype_objs, id=work_type_id)
if not employee.approved:
raise serializers.ValidationError("Employee hasn't approved employment yet.")
if Price.objects.filter(management=employee) \
.filter(work_type=work_type) \
.filter(deleted=False).exists():
raise serializers.ValidationError("Price for this work already defined.")
validated_data['management'] = employee
validated_data['work_type'] = work_type
return serializers.ModelSerializer.create(self, validated_data)
class EmployeeUserSerializer(serializers.ModelSerializer):
userinfo = UserInfoSerializer(read_only=True)
class Meta:
model = User
fields = ('is_active', 'first_name', 'last_name', 'email', 'userinfo')
depth = 1
class EmployeeSerializer(serializers.ModelSerializer):
provider_email = serializers.EmailField(write_only=True)
provider = serializers.SerializerMethodField()
prices = PriceSerializer(many=True, read_only=True)
class Meta:
model = Manage
fields = ('id', 'provider', 'provider_email', 'note', 'approved', 'prices', 'deleted')
read_only_fields = ('approved', 'deleted')
def get_provider(self, obj):
if obj.approved == True:
user = User.objects.get(provider=obj.provider)
return EmployeeUserSerializer(user).data
else:
return obj.provider.user.email
def create(self, validated_data):
user = self.context['request'].user
if not Client.objects.filter(user=user).exists():
raise serializers.ValidationError("User is not a client.")
client = user.client
provider_email = validated_data.pop('provider_email')
provider = get_object_or_404(Provider, user__email=provider_email)
if Manage.objects.filter(client=client) \
.filter(provider=provider) \
.filter(deleted=False).exists():
raise serializers.ValidationError("Employee already added.")
validated_data['client'] = client
validated_data['provider'] = provider
return serializers.ModelSerializer.create(self, validated_data)
class ClientSerializer(serializers.ModelSerializer):
work_types = WorkTypeSerializer(many=True, read_only=True)
employees = EmployeeSerializer(many=True, read_only=True)
class Meta:
model = Client
fields = ('user', 'business_number')
fields = ('business_number', 'work_types', 'employees')
def create(self, validated_data):
user = self.context['request'].user
if Provider.objects.filter(user=user).exists():
raise serializers.ValidationError("User is already a Provider.")
validated_data['user'] = user
return serializers.ModelSerializer.create(self, validated_data)
class EmployerUserSerializer(serializers.ModelSerializer):
userinfo = UserInfoSerializer(read_only=True)
class Meta:
model = User
fields = ('is_active', 'first_name', 'last_name', 'email', 'userinfo')
depth = 1
class EmployerSerializer(serializers.ModelSerializer):
client = serializers.SerializerMethodField()
prices = PriceSerializer(many=True, read_only=True)
class Meta:
model = Manage
fields = ('id', 'client', 'note', 'approved', 'prices')
read_only_fields = ('note',)
def get_client(self, obj):
if obj.approved == True:
user = User.objects.get(client=obj.client)
return EmployerUserSerializer(user).data
else:
return obj.client.user.first_name + ' ' + obj.client.user.last_name
class ProviderSerializer(serializers.ModelSerializer):
employers = EmployerSerializer(many=True, read_only=True)
class Meta:
model = Provider
fields = ('user', 'sin')
fields = ('sin', 'employers')
def create(self, validated_data):
user = self.context['request'].user
if Client.objects.filter(user=user).exists():
raise serializers.ValidationError("User is already a Client.")
validated_data['user'] = user
return serializers.ModelSerializer.create(self, validated_data)
class UserSerializer(serializers.ModelSerializer):
userinfo = UserInfoSerializer(read_only=True, allow_null=True)
client = ClientSerializer(allow_null=True)
provider = ProviderSerializer(allow_null=True)
userinfo = UserInfoSerializer(read_only=True)
client = ClientSerializer(read_only=True)
provider = ProviderSerializer(read_only=True)
class Meta:
model = User
fields = ('username', 'is_active', 'first_name', 'last_name', 'email', 'userinfo', 'client', 'provider')
depth = 1
class CShiftSerializer(serializers.ModelSerializer):
get_price_id = serializers.IntegerField(write_only=True)
class Meta:
model = Shift
fields = ('id', 'chart', 'get_price_id', 'price', 'set_price', 'set_date', 'set_start', 'set_end', 'actual_start', 'actual_end', 'amount', 'description', 'deleted')
read_only_fields = ('chart', 'price', 'set_price', 'set_date', 'actual_start', 'actual_end', 'amount', 'deleted')
def create(self, validated_data):
user = self.context['request'].user
if not Client.objects.filter(user=user).exists():
raise serializers.ValidationError("User is not a client.")
client = user.client
price_objs = Price.objects.filter(management__client=client).filter(deleted=False)
price_id = validated_data.pop('get_price_id')
price = get_object_or_404(price_objs, id=price_id)
if price.management.deleted:
raise serializers.ValidationError("Employment relationship was deleted.")
if price.work_type.deleted:
raise serializers.ValidationError("Type of work was deleted.")
if not price.management.approved:
raise serializers.ValidationError("Employee hasn't approved employment yet.")
now = datetime.now(timezone.utc)
set_start = validated_data['set_start']
set_end = validated_data['set_end']
if set_start > set_end:
raise serializers.ValidationError("Shift ends before it starts.")
if set_start > set_end - timedelta(hours=1):
raise serializers.ValidationError("Shift is less than one hour long.")
if set_start < now or set_end < now:
raise serializers.ValidationError("Shift is in the past.")
# TODO: Make sure provider isn't double-booked?????
validated_data['set_date'] = set_start.date()
validated_data['price'] = price
return serializers.ModelSerializer.create(self, validated_data)
class PShiftSerializer(serializers.ModelSerializer):
action = serializers.ChoiceField(write_only=True, choices=['checkin', 'checkout'])
class Meta:
model = Shift
fields = ('id', 'action', 'chart', 'price', 'set_price', 'set_date', 'set_start', 'set_end', 'actual_start', 'actual_end', 'amount', 'description', 'deleted')
read_only_fields = ('id', 'price', 'set_price', 'set_date', 'set_start', 'set_end', 'actual_start', 'actual_end', 'amount', 'description', 'deleted')
def update(self, instance, validated_data):
action = validated_data['action']
chart = validated_data['chart']
if action == 'checkin':
if instance.deleted:
raise serializers.ValidationError("Shift was deleted.")
if instance.actual_start:
raise serializers.ValidationError("Already checked in.")
if chart:
raise serializers.ValidationError("Can only provide chart on checkout.")
instance.actual_start = datetime.now(timezone.utc)
instance.set_price = instance.price.amount
elif action == 'checkout':
if not instance.actual_start:
raise serializers.ValidationError("Need to check in first.")
if instance.actual_end:
raise serializers.ValidationError("Already checked out.")
if not chart:
raise serializers.ValidationError("No chart info provided.")
instance.actual_end = datetime.now(timezone.utc)
shift_length = instance.actual_end - instance.actual_start
instance.amount = Decimal(shift_length.total_seconds()) / 3600 * instance.set_price
instance.chart = chart
instance.save()
return instance

View File

@ -1,12 +1,11 @@
from django.shortcuts import render
from django.contrib.auth.models import User, Group
from caremyway.api.models import UserInfo, Client, Provider
from caremyway.api.models import UserInfo, Client, Provider, WorkType, Manage, Price, Shift
from rest_framework import viewsets, permissions, status
from rest_framework.decorators import api_view
from rest_framework.response import Response
from caremyway.api.serializers import UserSerializer, UserInfoSerializer, ClientSerializer, ProviderSerializer
from caremyway.api.permissions import UserTypePermission
from rest_framework.views import APIView
from caremyway.api.serializers import UserSerializer, UserInfoSerializer, ClientSerializer, ProviderSerializer, WorkTypeSerializer, EmployeeSerializer, EmployerSerializer, PriceSerializer, CShiftSerializer, PShiftSerializer
class UserViewSet(viewsets.ModelViewSet):
lookup_field = 'username'
@ -16,52 +15,111 @@ class UserViewSet(viewsets.ModelViewSet):
http_method_names = ['get', 'head', 'put', 'options']
def get_queryset(self):
user = self.request.user
if user.is_staff:
return User.objects.all().order_by('-date_joined')
else:
return User.objects.filter(username=user)
return User.objects.filter(username=self.request.user)
class UserInfoViewSet(viewsets.ModelViewSet):
lookup_field = "user__username"
serializer_class = UserInfoSerializer
# Disallow DELETE
http_method_names = ['get', 'post', 'head', 'put', 'options']
def get_queryset(self):
user = self.request.user
if user.is_staff:
return UserInfo.objects.all().order_by('-user__date_joined')
else:
return UserInfo.objects.filter(user__username=user)
return UserInfo.objects.filter(user__username=self.request.user)
class ClientViewSet(viewsets.ModelViewSet):
lookup_field = "user__username"
serializer_class = ClientSerializer
# Disallow DELETE
http_method_names = ['get', 'post', 'head', 'put', 'options']
permission_classes = (UserTypePermission,)
def get_queryset(self):
user = self.request.user
if user.is_staff:
return Client.objects.all().order_by('-user__date_joined')
else:
return Client.objects.filter(user__username=user)
return Client.objects.filter(user__username=self.request.user)
class ProviderViewSet(viewsets.ModelViewSet):
lookup_field = "user__username"
serializer_class = ProviderSerializer
# Disallow DELETE
http_method_names = ['get', 'post', 'head', 'put', 'options']
permission_classes = (UserTypePermission,)
def get_queryset(self):
user = self.request.user
if user.is_staff:
return Provider.objects.all().order_by('-user__date_joined')
else:
return Provider.objects.filter(user__username=user)
return Provider.objects.filter(user__username=self.request.user)
class WorkTypeViewSet(viewsets.ModelViewSet):
serializer_class = WorkTypeSerializer
def get_queryset(self):
return WorkType.objects.filter(client__user__username=self.request.user)
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
instance.deleted = True
instance.save()
return Response(status=status.HTTP_204_NO_CONTENT)
class EmployeeViewSet(viewsets.ModelViewSet):
serializer_class = EmployeeSerializer
def get_queryset(self):
return Manage.objects.filter(client__user__username=self.request.user)
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
instance.deleted = True
instance.save()
return Response(status=status.HTTP_204_NO_CONTENT)
class EmployerViewSet(viewsets.ModelViewSet):
serializer_class = EmployerSerializer
# Disallow creation and deletions of relationships
http_method_names = ['get', 'head', 'put', 'options']
def get_queryset(self):
return Manage.objects.filter(provider__user__username=self.request.user)
class PriceViewSet(viewsets.ModelViewSet):
serializer_class = PriceSerializer
def get_queryset(self):
return Price.objects.filter(management__client__user__username=self.request.user)
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
instance.deleted = True
instance.save()
return Response(status=status.HTTP_204_NO_CONTENT)
class CShiftViewSet(viewsets.ModelViewSet):
serializer_class = CShiftSerializer
def get_queryset(self):
return Shift.objects.filter(price__management__client__user__username=self.request.user) \
.filter(deleted=False) \
.order_by('-set_start')
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
if instance.actual_start:
return Response("Shift already started.", status=status.HTTP_400_BAD_REQUEST)
instance.deleted = True
instance.save()
return Response(status=status.HTTP_204_NO_CONTENT)
class PShiftViewSet(viewsets.ModelViewSet):
serializer_class = PShiftSerializer
# Disallow creation and deletions of relationships
http_method_names = ['get', 'head', 'put', 'options']
def get_queryset(self):
return Shift.objects.filter(price__management__provider__user__username=self.request.user) \
.filter(deleted=False) \
.order_by('-set_start')
@api_view()
def null_view(request):

View File

@ -14,6 +14,7 @@ Including another URLconf
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url, include
from django.contrib import admin
from rest_framework import routers
from caremyway.api import views
@ -22,11 +23,18 @@ router.register(r'user', views.UserViewSet, 'user')
router.register(r'userinfo', views.UserInfoViewSet, 'userinfo')
router.register(r'client', views.ClientViewSet, 'client')
router.register(r'provider', views.ProviderViewSet, 'provider')
router.register(r'worktype', views.WorkTypeViewSet, 'worktype')
router.register(r'employee', views.EmployeeViewSet, 'employee')
router.register(r'employer', views.EmployerViewSet, 'employer')
router.register(r'price', views.PriceViewSet, 'price')
router.register(r'cshift', views.CShiftViewSet, 'cshift')
router.register(r'pshift', views.PShiftViewSet, 'pshift')
# Wire up our API using automatic URL routing.
# Additionally, we include login URLs for the browsable API.
urlpatterns = [
url(r'^', include(router.urls)),
url(r'^admin/', include(admin.site.urls)),
url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')),
url(r'^rest-auth/registration/account-email-verification-sent/', views.null_view, name='account_email_verification_sent'),
url(r'^rest-auth/registration/account-confirm-email/', views.null_view, name='account_confirm_email'),