From 8455ff3f7b6f1bcb59d262a93a34ac669c665bd4 Mon Sep 17 00:00:00 2001 From: klmp200 Date: Fri, 19 Aug 2016 12:37:30 +0200 Subject: [PATCH 1/4] Turned the api readonly and fixed permissions on it --- api/views/__init__.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/api/views/__init__.py b/api/views/__init__.py index 97682e80..86a33cc6 100644 --- a/api/views/__init__.py +++ b/api/views/__init__.py @@ -2,10 +2,20 @@ from rest_framework.response import Response from rest_framework import viewsets from django.core.exceptions import PermissionDenied from rest_framework.decorators import detail_route +from django.db.models.query import QuerySet from core.views import can_view, can_edit -class RightManagedModelViewSet(viewsets.ModelViewSet): +def check_if(obj, user, test): + if (isinstance(obj, QuerySet)): + for o in obj: + if (test(o, user) is False): + return False + return True + else: + return test(obj, user) + +class RightManagedModelViewSet(viewsets.ReadOnlyModelViewSet): @detail_route() def id(self, request, pk=None): @@ -22,9 +32,7 @@ class RightManagedModelViewSet(viewsets.ModelViewSet): obj = self.queryset user = self.request.user try: - if (request.method == 'GET' and can_view(obj, user)): - return res - elif (request.method != 'GET' and can_edit(obj, user)): + if (check_if(obj, user, can_view)): return res except: pass # To prevent bug with Anonymous user raise PermissionDenied From cc619daf45319dc372ef7b45e14dcdd4f286e086 Mon Sep 17 00:00:00 2001 From: klmp200 Date: Fri, 19 Aug 2016 14:40:20 +0200 Subject: [PATCH 2/4] Renaming and commenting in api --- api/views/__init__.py | 11 ++++++++--- api/views/api.py | 16 ++++++++-------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/api/views/__init__.py b/api/views/__init__.py index 86a33cc6..c4dfb7b2 100644 --- a/api/views/__init__.py +++ b/api/views/__init__.py @@ -7,6 +7,10 @@ from django.db.models.query import QuerySet from core.views import can_view, can_edit def check_if(obj, user, test): + """ + Detect if it's a single object or a queryset + aply a given test on individual object and return global permission + """ if (isinstance(obj, QuerySet)): for o in obj: if (test(o, user) is False): @@ -15,8 +19,7 @@ def check_if(obj, user, test): else: return test(obj, user) -class RightManagedModelViewSet(viewsets.ReadOnlyModelViewSet): - +class ManageModelMixin: @detail_route() def id(self, request, pk=None): """ @@ -26,8 +29,10 @@ class RightManagedModelViewSet(viewsets.ReadOnlyModelViewSet): serializer = self.get_serializer(self.queryset) return Response(serializer.data) +class RightReadOnlyModelViewSet(ManageModelMixin, viewsets.ReadOnlyModelViewSet): + def dispatch(self, request, *arg, **kwargs): - res = super(RightManagedModelViewSet, + res = super(RightReadOnlyModelViewSet, self).dispatch(request, *arg, **kwargs) obj = self.queryset user = self.request.user diff --git a/api/views/api.py b/api/views/api.py index 6a0aa594..cecc5f4d 100644 --- a/api/views/api.py +++ b/api/views/api.py @@ -14,7 +14,7 @@ from club.models import Club from launderette.models import Launderette, Machine, Token from api.views import serializers -from api.views import RightManagedModelViewSet +from api.views import RightReadOnlyModelViewSet @api_view(['GET']) def RenderMarkdown(request): @@ -25,7 +25,7 @@ def RenderMarkdown(request): return Response(markdown(request.GET['text'])) -class CounterViewSet(RightManagedModelViewSet): +class CounterViewSet(RightReadOnlyModelViewSet): """ Manage Counters (api/v1/counter/) """ @@ -43,7 +43,7 @@ class CounterViewSet(RightManagedModelViewSet): return Response(serializer.data) -class UserViewSet(RightManagedModelViewSet): +class UserViewSet(RightReadOnlyModelViewSet): """ Manage Users (api/v1/user/) Only show active users @@ -63,7 +63,7 @@ class UserViewSet(RightManagedModelViewSet): return Response(serializer.data) -class ClubViewSet(RightManagedModelViewSet): +class ClubViewSet(RightReadOnlyModelViewSet): """ Manage Clubs (api/v1/club/) """ @@ -71,7 +71,7 @@ class ClubViewSet(RightManagedModelViewSet): serializer_class = serializers.ClubRead queryset = Club.objects.all() -class GroupViewSet(RightManagedModelViewSet): +class GroupViewSet(RightReadOnlyModelViewSet): """ Manage Groups (api/v1/group/) """ @@ -79,7 +79,7 @@ class GroupViewSet(RightManagedModelViewSet): serializer_class = serializers.GroupRead queryset = RealGroup.objects.all() -class LaunderettePlaceViewSet(RightManagedModelViewSet): +class LaunderettePlaceViewSet(RightReadOnlyModelViewSet): """ Manage Launderette (api/v1/launderette/place/) """ @@ -87,7 +87,7 @@ class LaunderettePlaceViewSet(RightManagedModelViewSet): serializer_class = serializers.LaunderettePlaceRead queryset = Launderette.objects.all() -class LaunderetteMachineViewSet(RightManagedModelViewSet): +class LaunderetteMachineViewSet(RightReadOnlyModelViewSet): """ Manage Washing Machines (api/v1/launderette/machine/) """ @@ -95,7 +95,7 @@ class LaunderetteMachineViewSet(RightManagedModelViewSet): serializer_class = serializers.LaunderetteMachineRead queryset = Machine.objects.all() -class LaunderetteTokenViewSet(RightManagedModelViewSet): +class LaunderetteTokenViewSet(RightReadOnlyModelViewSet): """ Manage Launderette's tokens (api/v1/launderette/token/) """ From 6c107ed3d4bebdb593f1e5b342f3a5259c4b5f64 Mon Sep 17 00:00:00 2001 From: klmp200 Date: Fri, 19 Aug 2016 16:13:40 +0200 Subject: [PATCH 3/4] Splited api across sevral files, deactivated readonly --- api/views/__init__.py | 14 +++-- api/views/api.py | 126 --------------------------------------- api/views/club.py | 21 +++++++ api/views/counter.py | 37 ++++++++++++ api/views/group.py | 20 +++++++ api/views/launderette.py | 95 +++++++++++++++++++++++++++++ api/views/serializers.py | 66 -------------------- api/views/user.py | 37 ++++++++++++ 8 files changed, 220 insertions(+), 196 deletions(-) create mode 100644 api/views/club.py create mode 100644 api/views/counter.py create mode 100644 api/views/group.py create mode 100644 api/views/launderette.py delete mode 100644 api/views/serializers.py create mode 100644 api/views/user.py diff --git a/api/views/__init__.py b/api/views/__init__.py index c4dfb7b2..52da6d66 100644 --- a/api/views/__init__.py +++ b/api/views/__init__.py @@ -29,19 +29,25 @@ class ManageModelMixin: serializer = self.get_serializer(self.queryset) return Response(serializer.data) -class RightReadOnlyModelViewSet(ManageModelMixin, viewsets.ReadOnlyModelViewSet): +class RightModelViewSet(ManageModelMixin, viewsets.ModelViewSet): def dispatch(self, request, *arg, **kwargs): - res = super(RightReadOnlyModelViewSet, + res = super(RightModelViewSet, self).dispatch(request, *arg, **kwargs) obj = self.queryset user = self.request.user try: - if (check_if(obj, user, can_view)): + if (request.method == 'GET' and check_if(obj, user, can_view)): + return res + if (request.method != 'GET' and check_if(obj, user, can_edit)): return res except: pass # To prevent bug with Anonymous user raise PermissionDenied from .api import * -from .serializers import * \ No newline at end of file +from .counter import * +from .user import * +from .club import * +from .group import * +from .launderette import * \ No newline at end of file diff --git a/api/views/api.py b/api/views/api.py index cecc5f4d..6e7933be 100644 --- a/api/views/api.py +++ b/api/views/api.py @@ -1,20 +1,8 @@ -import datetime - -from django.shortcuts import get_object_or_404 from rest_framework.response import Response from rest_framework.decorators import api_view -from rest_framework import viewsets -from rest_framework.decorators import detail_route -from rest_framework.decorators import list_route from core.templatetags.renderer import markdown -from counter.models import Counter -from core.models import User, RealGroup -from club.models import Club -from launderette.models import Launderette, Machine, Token -from api.views import serializers -from api.views import RightReadOnlyModelViewSet @api_view(['GET']) def RenderMarkdown(request): @@ -24,117 +12,3 @@ def RenderMarkdown(request): if request.method == 'GET': return Response(markdown(request.GET['text'])) - -class CounterViewSet(RightReadOnlyModelViewSet): - """ - Manage Counters (api/v1/counter/) - """ - - serializer_class = serializers.CounterRead - queryset = Counter.objects.all() - - @list_route() - def bar(self, request): - """ - Return all bars (api/v1/counter/bar/) - """ - self.queryset = self.queryset.filter(type="BAR") - serializer = self.get_serializer(self.queryset, many=True) - return Response(serializer.data) - - -class UserViewSet(RightReadOnlyModelViewSet): - """ - Manage Users (api/v1/user/) - Only show active users - """ - - serializer_class = serializers.UserRead - queryset = User.objects.filter(is_active=True) - - @list_route() - def birthday(self, request): - """ - Return all users born today (api/v1/user/birstdays) - """ - date = datetime.datetime.today() - self.queryset = self.queryset.filter(date_of_birth=date) - serializer = self.get_serializer(self.queryset, many=True) - return Response(serializer.data) - - -class ClubViewSet(RightReadOnlyModelViewSet): - """ - Manage Clubs (api/v1/club/) - """ - - serializer_class = serializers.ClubRead - queryset = Club.objects.all() - -class GroupViewSet(RightReadOnlyModelViewSet): - """ - Manage Groups (api/v1/group/) - """ - - serializer_class = serializers.GroupRead - queryset = RealGroup.objects.all() - -class LaunderettePlaceViewSet(RightReadOnlyModelViewSet): - """ - Manage Launderette (api/v1/launderette/place/) - """ - - serializer_class = serializers.LaunderettePlaceRead - queryset = Launderette.objects.all() - -class LaunderetteMachineViewSet(RightReadOnlyModelViewSet): - """ - Manage Washing Machines (api/v1/launderette/machine/) - """ - - serializer_class = serializers.LaunderetteMachineRead - queryset = Machine.objects.all() - -class LaunderetteTokenViewSet(RightReadOnlyModelViewSet): - """ - Manage Launderette's tokens (api/v1/launderette/token/) - """ - - serializer_class = serializers.LaunderetteTokenRead - queryset = Token.objects.all() - - @list_route() - def washing(self, request): - """ - Return all washing tokens (api/v1/launderette/token/washing) - """ - self.queryset = self.queryset.filter(type='WASHING') - serializer = self.get_serializer(self.queryset, many=True) - return Response(serializer.data) - - @list_route() - def drying(self, request): - """ - Return all drying tokens (api/v1/launderette/token/drying) - """ - self.queryset = self.queryset.filter(type='DRYING') - serializer = self.get_serializer(self.queryset, many=True) - return Response(serializer.data) - - @list_route() - def avaliable(self, request): - """ - Return all avaliable tokens (api/v1/launderette/token/avaliable) - """ - self.queryset = self.queryset.filter(borrow_date__isnull=True, user__isnull=True) - serializer = self.get_serializer(self.queryset, many=True) - return Response(serializer.data) - - @list_route() - def unavaliable(self, request): - """ - Return all unavaliable tokens (api/v1/launderette/token/unavaliable) - """ - self.queryset = self.queryset.filter(borrow_date__isnull=False, user__isnull=False) - serializer = self.get_serializer(self.queryset, many=True) - return Response(serializer.data) diff --git a/api/views/club.py b/api/views/club.py new file mode 100644 index 00000000..72ea1e32 --- /dev/null +++ b/api/views/club.py @@ -0,0 +1,21 @@ +from rest_framework import serializers + +from club.models import Club + +from api.views import RightModelViewSet + + +class ClubSerializer(serializers.ModelSerializer): + + class Meta: + model = Club + fields = ('id', 'name', 'unix_name', 'address', 'members') + + +class ClubViewSet(RightModelViewSet): + """ + Manage Clubs (api/v1/club/) + """ + + serializer_class = ClubSerializer + queryset = Club.objects.all() diff --git a/api/views/counter.py b/api/views/counter.py new file mode 100644 index 00000000..6c34029a --- /dev/null +++ b/api/views/counter.py @@ -0,0 +1,37 @@ +from rest_framework import serializers +from rest_framework.response import Response +from rest_framework.decorators import list_route + +from counter.models import Counter + +from api.views import RightModelViewSet + + +class CounterSerializer(serializers.ModelSerializer): + + is_open = serializers.BooleanField(read_only=True) + barman_list = serializers.ListField( + child=serializers.IntegerField() + ) + + class Meta: + model = Counter + fields = ('id', 'name', 'type', 'is_open', 'barman_list') + + +class CounterViewSet(RightModelViewSet): + """ + Manage Counters (api/v1/counter/) + """ + + serializer_class = CounterSerializer + queryset = Counter.objects.all() + + @list_route() + def bar(self, request): + """ + Return all bars (api/v1/counter/bar/) + """ + self.queryset = self.queryset.filter(type="BAR") + serializer = self.get_serializer(self.queryset, many=True) + return Response(serializer.data) diff --git a/api/views/group.py b/api/views/group.py new file mode 100644 index 00000000..b9ff625c --- /dev/null +++ b/api/views/group.py @@ -0,0 +1,20 @@ +from rest_framework import serializers + +from core.models import RealGroup + +from api.views import RightModelViewSet + + +class GroupSerializer(serializers.ModelSerializer): + + class Meta: + model = RealGroup + + +class GroupViewSet(RightModelViewSet): + """ + Manage Groups (api/v1/group/) + """ + + serializer_class = GroupSerializer + queryset = RealGroup.objects.all() diff --git a/api/views/launderette.py b/api/views/launderette.py new file mode 100644 index 00000000..a2423c17 --- /dev/null +++ b/api/views/launderette.py @@ -0,0 +1,95 @@ +from rest_framework import serializers +from rest_framework.response import Response +from rest_framework.decorators import list_route + +from launderette.models import Launderette, Machine, Token + +from api.views import RightModelViewSet + +class LaunderettePlaceSerializer(serializers.ModelSerializer): + + machine_list = serializers.ListField( + child=serializers.IntegerField() + ) + token_list = serializers.ListField( + child=serializers.IntegerField() + ) + + class Meta: + model = Launderette + fields = ('id', 'name', 'counter', 'machine_list', + 'token_list', 'get_absolute_url') + +class LaunderetteMachineSerializer(serializers.ModelSerializer): + + class Meta: + model = Machine + fields = ('id', 'name', 'is_working', 'launderette') + +class LaunderetteTokenSerializer(serializers.ModelSerializer): + + class Meta: + model = Token + fields = ('id', 'name', 'type', 'launderette', 'borrow_date', + 'user', 'is_avaliable') + +class LaunderettePlaceViewSet(RightModelViewSet): + """ + Manage Launderette (api/v1/launderette/place/) + """ + + serializer_class = LaunderettePlaceSerializer + queryset = Launderette.objects.all() + +class LaunderetteMachineViewSet(RightModelViewSet): + """ + Manage Washing Machines (api/v1/launderette/machine/) + """ + + serializer_class = LaunderetteMachineSerializer + queryset = Machine.objects.all() + + +class LaunderetteTokenViewSet(RightModelViewSet): + """ + Manage Launderette's tokens (api/v1/launderette/token/) + """ + + serializer_class = LaunderetteTokenSerializer + queryset = Token.objects.all() + + @list_route() + def washing(self, request): + """ + Return all washing tokens (api/v1/launderette/token/washing) + """ + self.queryset = self.queryset.filter(type='WASHING') + serializer = self.get_serializer(self.queryset, many=True) + return Response(serializer.data) + + @list_route() + def drying(self, request): + """ + Return all drying tokens (api/v1/launderette/token/drying) + """ + self.queryset = self.queryset.filter(type='DRYING') + serializer = self.get_serializer(self.queryset, many=True) + return Response(serializer.data) + + @list_route() + def avaliable(self, request): + """ + Return all avaliable tokens (api/v1/launderette/token/avaliable) + """ + self.queryset = self.queryset.filter(borrow_date__isnull=True, user__isnull=True) + serializer = self.get_serializer(self.queryset, many=True) + return Response(serializer.data) + + @list_route() + def unavaliable(self, request): + """ + Return all unavaliable tokens (api/v1/launderette/token/unavaliable) + """ + self.queryset = self.queryset.filter(borrow_date__isnull=False, user__isnull=False) + serializer = self.get_serializer(self.queryset, many=True) + return Response(serializer.data) diff --git a/api/views/serializers.py b/api/views/serializers.py deleted file mode 100644 index ccbc6fa4..00000000 --- a/api/views/serializers.py +++ /dev/null @@ -1,66 +0,0 @@ -from rest_framework import serializers -from counter.models import Counter -from core.models import User, RealGroup -from launderette.models import Launderette, Machine, Token -from club.models import Club - - -class CounterRead(serializers.ModelSerializer): - - is_open = serializers.BooleanField(read_only=True) - barman_list = serializers.ListField( - child=serializers.IntegerField() - ) - - class Meta: - model = Counter - fields = ('id', 'name', 'type', 'is_open', 'barman_list') - - -class UserRead(serializers.ModelSerializer): - - class Meta: - model = User - fields = ('id', 'first_name', 'last_name', 'email', - 'date_of_birth', 'nick_name', 'is_active', 'date_joined') - - -class ClubRead(serializers.ModelSerializer): - - class Meta: - model = Club - fields = ('id', 'name', 'unix_name', 'address', 'members') - - -class GroupRead(serializers.ModelSerializer): - - class Meta: - model = RealGroup - - -class LaunderettePlaceRead(serializers.ModelSerializer): - - machine_list = serializers.ListField( - child=serializers.IntegerField() - ) - token_list = serializers.ListField( - child=serializers.IntegerField() - ) - - class Meta: - model = Launderette - fields = ('id', 'name', 'counter', 'machine_list', - 'token_list', 'get_absolute_url') - -class LaunderetteMachineRead(serializers.ModelSerializer): - - class Meta: - model = Machine - fields = ('id', 'name', 'is_working', 'launderette') - -class LaunderetteTokenRead(serializers.ModelSerializer): - - class Meta: - model = Token - fields = ('id', 'name', 'type', 'launderette', 'borrow_date', - 'user', 'is_avaliable') diff --git a/api/views/user.py b/api/views/user.py new file mode 100644 index 00000000..f932a7f4 --- /dev/null +++ b/api/views/user.py @@ -0,0 +1,37 @@ +import datetime + +from rest_framework import serializers +from rest_framework.response import Response +from rest_framework.decorators import list_route + +from core.models import User + +from api.views import RightModelViewSet + + +class UserSerializer(serializers.ModelSerializer): + + class Meta: + model = User + fields = ('id', 'first_name', 'last_name', 'email', + 'date_of_birth', 'nick_name', 'is_active', 'date_joined') + + +class UserViewSet(RightModelViewSet): + """ + Manage Users (api/v1/user/) + Only show active users + """ + + serializer_class = UserSerializer + queryset = User.objects.filter(is_active=True) + + @list_route() + def birthday(self, request): + """ + Return all users born today (api/v1/user/birstdays) + """ + date = datetime.datetime.today() + self.queryset = self.queryset.filter(date_of_birth=date) + serializer = self.get_serializer(self.queryset, many=True) + return Response(serializer.data) From 2f7030d96472223d9680dda9ff0e2e74338f6cdf Mon Sep 17 00:00:00 2001 From: klmp200 Date: Fri, 19 Aug 2016 17:25:23 +0200 Subject: [PATCH 4/4] Fixed api's list bug --- api/views/counter.py | 6 ++++-- api/views/launderette.py | 8 +++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/api/views/counter.py b/api/views/counter.py index 6c34029a..69a98660 100644 --- a/api/views/counter.py +++ b/api/views/counter.py @@ -11,12 +11,14 @@ class CounterSerializer(serializers.ModelSerializer): is_open = serializers.BooleanField(read_only=True) barman_list = serializers.ListField( - child=serializers.IntegerField() + child=serializers.IntegerField(), + read_only=True ) class Meta: model = Counter - fields = ('id', 'name', 'type', 'is_open', 'barman_list') + fields = ('id', 'name', 'type', 'club', + 'products', 'is_open', 'barman_list') class CounterViewSet(RightModelViewSet): diff --git a/api/views/launderette.py b/api/views/launderette.py index a2423c17..c3e586c0 100644 --- a/api/views/launderette.py +++ b/api/views/launderette.py @@ -9,10 +9,12 @@ from api.views import RightModelViewSet class LaunderettePlaceSerializer(serializers.ModelSerializer): machine_list = serializers.ListField( - child=serializers.IntegerField() + child=serializers.IntegerField(), + read_only=True ) token_list = serializers.ListField( - child=serializers.IntegerField() + child=serializers.IntegerField(), + read_only=True ) class Meta: @@ -24,7 +26,7 @@ class LaunderetteMachineSerializer(serializers.ModelSerializer): class Meta: model = Machine - fields = ('id', 'name', 'is_working', 'launderette') + fields = ('id', 'name', 'type', 'is_working', 'launderette') class LaunderetteTokenSerializer(serializers.ModelSerializer):