From d0123850884da3a5b0fa722c47fa65e5df013444 Mon Sep 17 00:00:00 2001 From: vabene1111 Date: Tue, 16 Jun 2020 20:32:41 +0200 Subject: [PATCH] WIP api stuff --- cookbook/helper/permission_helper.py | 22 ++++++- cookbook/serializer.py | 94 ++++++++++++++++++++++++++-- cookbook/urls.py | 1 + cookbook/views/api.py | 21 +++++-- 4 files changed, 128 insertions(+), 10 deletions(-) diff --git a/cookbook/helper/permission_helper.py b/cookbook/helper/permission_helper.py index 466747a5..1972fac9 100644 --- a/cookbook/helper/permission_helper.py +++ b/cookbook/helper/permission_helper.py @@ -8,6 +8,7 @@ from django.db.models import Q from django.utils.translation import gettext as _ from django.http import HttpResponseRedirect from django.urls import reverse_lazy, reverse +from rest_framework import permissions from cookbook.models import ShareLink @@ -73,8 +74,27 @@ class OwnerRequiredMixin(object): def share_link_valid(recipe, share): - print(share, recipe) + """ + Verifies if a share uuid is valid for a given recipe + """ try: return True if ShareLink.objects.filter(recipe=recipe, uuid=share).exists() else False except ValidationError: return False + + +class DRFOwnerPermissions(permissions.BasePermission): + """ + Custom permission class for django rest framework views + verifies user has ownership over object + (either user or created_by or user is request user) + """ + + def has_object_permission(self, request, view, obj): + if not request.user.is_authenticated: + return False + if owner := getattr(obj, 'created_by', None): + return owner == request.user + if owner := getattr(obj, 'user', None): + return owner == request.user + return False diff --git a/cookbook/serializer.py b/cookbook/serializer.py index 4a7a1b78..e9522001 100644 --- a/cookbook/serializer.py +++ b/cookbook/serializer.py @@ -1,7 +1,7 @@ from django.contrib.auth.models import User from rest_framework import serializers -from cookbook.models import MealPlan, MealType, Recipe, ViewLog +from cookbook.models import MealPlan, MealType, Recipe, ViewLog, UserPreference, Storage, Sync, SyncLog, Keyword, Ingredient, Unit, RecipeIngredient, Comment, RecipeImport, RecipeBook, RecipeBookEntry, ShareLink, CookLog from cookbook.templatetags.custom_tags import markdown @@ -11,6 +11,90 @@ class UserNameSerializer(serializers.ModelSerializer): fields = ('id', 'username', 'first_name', 'last_name') +class UserPreferenceSerializer(serializers.ModelSerializer): + class Meta: + model = UserPreference + fields = '__all__' + + +class StorageSerializer(serializers.ModelSerializer): + class Meta: + model = Storage + fields = '__all__' + + +class SyncSerializer(serializers.ModelSerializer): + class Meta: + model = Sync + fields = '__all__' + + +class SyncLogSerializer(serializers.ModelSerializer): + class Meta: + model = SyncLog + fields = '__all__' + + +class KeywordSerializer(serializers.ModelSerializer): + class Meta: + model = Keyword + fields = '__all__' + + +class RecipeSerializer(serializers.ModelSerializer): + class Meta: + model = Recipe + fields = '__all__' + + +class UnitSerializer(serializers.ModelSerializer): + class Meta: + model = Unit + fields = '__all__' + + +class IngredientSerializer(serializers.ModelSerializer): + class Meta: + model = Ingredient + fields = '__all__' + + +class RecipeIngredientSerializer(serializers.ModelSerializer): + class Meta: + model = RecipeIngredient + fields = '__all__' + + +class CommentSerializer(serializers.ModelSerializer): + class Meta: + model = Comment + fields = '__all__' + + +class RecipeImportSerializer(serializers.ModelSerializer): + class Meta: + model = RecipeImport + fields = '__all__' + + +class RecipeBookSerializer(serializers.ModelSerializer): + class Meta: + model = RecipeBook + fields = '__all__' + + +class RecipeBookEntrySerializer(serializers.ModelSerializer): + class Meta: + model = RecipeBookEntry + fields = '__all__' + + +class MealTypeSerializer(serializers.ModelSerializer): + class Meta: + model = MealType + fields = '__all__' + + class MealPlanSerializer(serializers.ModelSerializer): recipe_name = serializers.ReadOnlyField(source='recipe.name') meal_type_name = serializers.ReadOnlyField(source='meal_type.name') @@ -24,15 +108,15 @@ class MealPlanSerializer(serializers.ModelSerializer): fields = ('id', 'title', 'recipe', 'note', 'note_markdown', 'date', 'meal_type', 'created_by', 'shared', 'recipe_name', 'meal_type_name') -class MealTypeSerializer(serializers.ModelSerializer): +class ShareLinkSerializer(serializers.ModelSerializer): class Meta: - model = MealType + model = ShareLink fields = '__all__' -class RecipeSerializer(serializers.ModelSerializer): +class CookLogSerializer(serializers.ModelSerializer): class Meta: - model = Recipe + model = CookLog fields = '__all__' diff --git a/cookbook/urls.py b/cookbook/urls.py index f6abea5d..d7f10939 100644 --- a/cookbook/urls.py +++ b/cookbook/urls.py @@ -9,6 +9,7 @@ from cookbook.views import api, import_export from cookbook.helper import dal router = routers.DefaultRouter() +#router.register(r'user-preference', api.UserPreferenceViewSet) router.register(r'recipe', api.RecipeViewSet) router.register(r'meal-plan', api.MealPlanViewSet) router.register(r'meal-type', api.MealTypeViewSet) diff --git a/cookbook/views/api.py b/cookbook/views/api.py index 067e58fd..12aa2942 100644 --- a/cookbook/views/api.py +++ b/cookbook/views/api.py @@ -13,12 +13,13 @@ from django.utils.translation import gettext as _ from icalendar import Calendar, Event from rest_framework import viewsets, permissions from rest_framework.exceptions import APIException +from rest_framework.mixins import RetrieveModelMixin, UpdateModelMixin -from cookbook.helper.permission_helper import group_required -from cookbook.models import Recipe, Sync, Storage, CookLog, MealPlan, MealType, ViewLog +from cookbook.helper.permission_helper import group_required, DRFOwnerPermissions +from cookbook.models import Recipe, Sync, Storage, CookLog, MealPlan, MealType, ViewLog, UserPreference from cookbook.provider.dropbox import Dropbox from cookbook.provider.nextcloud import Nextcloud -from cookbook.serializer import MealPlanSerializer, MealTypeSerializer, RecipeSerializer, ViewLogSerializer, UserNameSerializer +from cookbook.serializer import MealPlanSerializer, MealTypeSerializer, RecipeSerializer, ViewLogSerializer, UserNameSerializer, UserPreferenceSerializer class UserNameViewSet(viewsets.ModelViewSet): @@ -30,7 +31,7 @@ class UserNameViewSet(viewsets.ModelViewSet): queryset = User.objects.all() serializer_class = UserNameSerializer permission_classes = [permissions.IsAuthenticated] - http_method_names = ['get', ] + http_method_names = ['get'] def get_queryset(self): queryset = User.objects.all() @@ -44,6 +45,18 @@ class UserNameViewSet(viewsets.ModelViewSet): return queryset +class UserPreferenceViewSet(RetrieveModelMixin, UpdateModelMixin, viewsets.GenericViewSet): + """ + Update user preference settings + """ + queryset = UserPreference.objects.all() + serializer_class = UserPreferenceSerializer + permission_classes = [DRFOwnerPermissions, ] + # TODO disable create view + def get_queryset(self): + return UserPreference.objects.filter(user=self.request.user).all() + + class MealPlanViewSet(viewsets.ModelViewSet): """ list: