diff --git a/authserver/README.md b/authserver/README.md index d29054b..41c29ef 100644 --- a/authserver/README.md +++ b/authserver/README.md @@ -54,6 +54,13 @@ In subsequent requests, the token key should be included in the `Authorization` Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b ``` +Example authenticated request: + +``` +curl -H "Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b" http://tools-auth.protospace.ca/user/ +``` + + ### For anonymous users #### GET `/tooldata/` @@ -128,10 +135,11 @@ Example response: ``` [ { - "username": "admin", + "username": "tanner.collin", "profile": { - "url": "http://tools-auth.protospace.ca/profile/1/", - "user": "admin", + "url": "http://tools-auth.protospace.ca/profile/2/", + "user": "tanner.collin", + "card": "00000A4123", "authorized_tools": [ "table-saw", "jointer" @@ -173,3 +181,33 @@ Get a list of all profiles. Get a specific profile, or modify an existing one. Here you can authorize users on tools or make them another lockout admin. + +#### PUT `/update-cards/` + +Send a dictionary of username=card_number pairs to update any profiles already in the system. Users not already registered will be ignored. + +Responds with the number of profiles updated. + +Operation is idempotent. + +Example PUT data: + +``` +{ + "tanner.collin": "00000A4123", + "matthew.mulrooney": "00000B8567", + "not-a-member": "539830843A" +} +``` + +Example response: + +``` +{"updated":2} +``` + +Example request: + +``` +curl -X PUT -H "Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b" -d tanner.collin=00000A4123 -d matthew.mulrooney=00000B8567 http://tools-auth.protospace.ca/update-cards/ +``` diff --git a/authserver/authserver/api/admin.py b/authserver/authserver/api/admin.py index 9d094a6..a39f206 100644 --- a/authserver/authserver/api/admin.py +++ b/authserver/authserver/api/admin.py @@ -5,3 +5,4 @@ from . import models admin.site.register(models.Category) admin.site.register(models.Tool) admin.site.register(models.Profile) +admin.site.register(models.Card) diff --git a/authserver/authserver/api/models.py b/authserver/authserver/api/models.py index 2f077a0..b6ca4ab 100644 --- a/authserver/authserver/api/models.py +++ b/authserver/authserver/api/models.py @@ -29,3 +29,10 @@ class Profile(models.Model): def __str__(self): return self.user.username + +class Card(models.Model): + profile = models.OneToOneField(Profile, on_delete=models.CASCADE, editable=False) + number = models.CharField(max_length=10) + + def __str__(self): + return self.number diff --git a/authserver/authserver/api/serializers.py b/authserver/authserver/api/serializers.py index f00e1a6..57e1aff 100644 --- a/authserver/authserver/api/serializers.py +++ b/authserver/authserver/api/serializers.py @@ -32,6 +32,11 @@ class ToolDataSerializer(serializers.HyperlinkedModelSerializer): class ProfileSerializer(serializers.HyperlinkedModelSerializer): user = serializers.StringRelatedField() + card = serializers.SlugRelatedField( + allow_null=True, + slug_field='number', + queryset=models.Card.objects.all() + ) authorized_tools = serializers.SlugRelatedField( many=True, slug_field='slug', diff --git a/authserver/authserver/api/views.py b/authserver/authserver/api/views.py index 4cf99a9..7cac84b 100644 --- a/authserver/authserver/api/views.py +++ b/authserver/authserver/api/views.py @@ -1,10 +1,11 @@ import requests +import json from django.contrib.auth.models import User from rest_framework import mixins, permissions, status, viewsets from rest_framework.authtoken.models import Token -from rest_framework.decorators import api_view +from rest_framework.decorators import api_view, permission_classes from rest_framework.response import Response from . import models, serializers @@ -74,3 +75,26 @@ def login(request): token, _ = Token.objects.get_or_create(user=user) return Response({'token': token.key}, status=status.HTTP_200_OK) + +@api_view(["PUT"]) +@permission_classes((IsLockoutAdmin,)) +def update_cards(request): + data = request.data + updated_count = 0 + + if not data: + return Response({'error': 'Please provide card data in the form username=cardnumber'}, + status=status.HTTP_400_BAD_REQUEST) + + for username, card_number in data.items(): + try: + profile = models.Profile.objects.get(user__username=username) + card, _ = models.Card.objects.update_or_create( + profile=profile, + defaults={'number': card_number} + ) + if card: updated_count += 1 + except: + continue + + return Response({'updated': updated_count}, status=status.HTTP_200_OK) diff --git a/authserver/authserver/urls.py b/authserver/authserver/urls.py index 57ad2ab..fd72586 100644 --- a/authserver/authserver/urls.py +++ b/authserver/authserver/urls.py @@ -33,7 +33,8 @@ urlpatterns = [ url(r'^', include(router.urls)), url(r'^admin/', admin.site.urls), url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework')), - url(r'^login/', views.login) + url(r'^login/', views.login), + url(r'^update-cards/', views.update_cards) ] if settings.DEBUG is True: