from recipes.models import Information, Review, RawIngredient, Unit from profiles.models import Pantry from rest_framework import generics, status, permissions from rest_framework.response import Response from .serializers import ( RecipeInformationSerializer, ReviewSerializer, RecipeDetailSerializer, RecipeIngredientsSerializer, RawIngredientSerializer, UnitSerializer ) from .models import Ingredient from django.http import JsonResponse class IsAuthenticatedOrReadOnly(permissions.BasePermission): def has_permission(self, request, view): if request.method == 'GET' or request.user.is_authenticated: return True return False class RecipeListView(generics.GenericAPIView): serializer_class = RecipeInformationSerializer def get(self, request): recipes = Information.objects.all()[:30] recipes_serializer = self.serializer_class( recipes, context={'request': request}, many=True) return Response(recipes_serializer.data) class OwnedIngredientView(generics.GenericAPIView): serializer_class = RecipeIngredientsSerializer def get(self, request, recipe_id): user = request.user if not user.is_authenticated: return Response([]) owned_raw_ingredient_ids = Pantry.objects.filter( user=user).values_list('raw_ingredient_id', flat=True) owned_ingredients = Ingredient.objects.filter( raw_ingredient__in=owned_raw_ingredient_ids, recipe_id=recipe_id).distinct() serializer = RecipeIngredientsSerializer(owned_ingredients, many=True) return Response(serializer.data) class NotOwnedIngredientViews(generics.GenericAPIView): serializer_class = RecipeIngredientsSerializer def get(self, request, recipe_id): user = request.user if not user.is_authenticated: all_ingredients = Ingredient.objects.filter(recipe_id=recipe_id) serializer = RecipeIngredientsSerializer( all_ingredients, many=True) return Response(serializer.data) owned_raw_ingredient_ids = Pantry.objects.filter( user=user).values_list('raw_ingredient_id', flat=True) not_owned_ingredients = Ingredient.objects.filter( recipe_id=recipe_id).exclude(raw_ingredient__in=owned_raw_ingredient_ids) serializer = RecipeIngredientsSerializer( not_owned_ingredients, many=True) return Response(serializer.data) class RecipeDetailView(generics.GenericAPIView): serializer_class = RecipeDetailSerializer permission_classes = [permissions.AllowAny] def get(self, request, recipe_id): recipes = Information.objects.get(pk=recipe_id) recipes_serializer = self.serializer_class( recipes, context={'request': request}) return Response(recipes_serializer.data) class SearchRecipeView(generics.GenericAPIView): def get(self, request): keyword = request.GET.get('keyword') if not keyword or not keyword.strip(): return Response({'message': 'Kata kunci yang Anda masukkan tidak valid'}, status=status.HTTP_400_BAD_REQUEST) recipes = Information.objects.filter(title__icontains=keyword) if not recipes: return Response({'message': 'Resep tidak ditemukan'}, status=status.HTTP_404_NOT_FOUND) recipes_list = RecipeInformationSerializer( recipes, context={'request': request}, many=True).data sorted_recipes = sorted( recipes_list, key=lambda x: x['completeness_percentage'], reverse=True) return Response(sorted_recipes, status=status.HTTP_200_OK) class ReviewView(generics.GenericAPIView): permission_classes = [IsAuthenticatedOrReadOnly] serializer_class = ReviewSerializer def get(self, request, recipe_id, review_id=None): if review_id is not None: try: review = Review.objects.get( recipe_id=recipe_id, pk=review_id, user=request.user) except Review.DoesNotExist: return Response({"message": "Ulasan tidak ditemukan"}, status=status.HTTP_404_NOT_FOUND) review_serializer = self.serializer_class(review) return Response(review_serializer.data) else: reviews = Review.objects.filter(recipe_id=recipe_id) if not reviews: return Response({"message": "Tidak ada ulasan"}, status=status.HTTP_404_NOT_FOUND) review_serializer = self.serializer_class(reviews, many=True) return Response(review_serializer.data) def post(self, request, recipe_id): try: recipe = Information.objects.get(pk=recipe_id) except Information.DoesNotExist: return JsonResponse({'message': 'Resep tidak ditemukan'}, status=status.HTTP_404_NOT_FOUND) review_serializer = self.serializer_class(data=request.data) if Review.objects.filter(user=request.user, recipe=recipe).exists(): return Response({'message': 'Anda sudah memberikan ulasan'}, status=status.HTTP_400_BAD_REQUEST) if review_serializer.is_valid(): saved_review = review_serializer.save( user=request.user, recipe=recipe) return Response(self.serializer_class(saved_review).data, status=status.HTTP_201_CREATED) return Response(review_serializer.errors, status=status.HTTP_400_BAD_REQUEST) def put(self, request, recipe_id, review_id): review = Review.objects.get( pk=review_id, user=request.user, recipe_id=recipe_id) if not review: return Response({"message": "Ulasan tidak ditemukan"}, status=status.HTTP_404_NOT_FOUND) review_serializer = self.serializer_class( instance=review, data=request.data) if review_serializer.is_valid(): review_serializer.save() return Response(review_serializer.data) else: return Response(review_serializer.errors, status=status.HTTP_400_BAD_REQUEST) def delete(self, request, recipe_id, review_id): try: review = Review.objects.get( pk=review_id, user=request.user) review.delete() return Response({'message': 'Berhasil menghapus ulasan'}, status=status.HTTP_200_OK) except Review.DoesNotExist: return Response({'message': 'Ulasan tidak ditemukan'}, status=status.HTTP_404_NOT_FOUND) class RawIngredientView(generics.GenericAPIView): serializer_class = RawIngredientSerializer def get(self, request): if request.GET.get('name'): raw_materials = RawIngredient.objects.filter( name__icontains=request.GET.get('name')) else: raw_materials = RawIngredient.objects.all() serializer = self.get_serializer(raw_materials, many=True) return Response(serializer.data) class UnitView(generics.GenericAPIView): def get(self, request): raw_ingredient_id = request.GET.get('raw_ingredient_id') units = Unit.objects.filter( ingredient__raw_ingredient_id=raw_ingredient_id).distinct() units_list = UnitSerializer(units, many=True).data return Response(units_list, status=status.HTTP_200_OK)