302 lines
12 KiB
Python
302 lines
12 KiB
Python
from .models import Information
|
|
from django.contrib.auth.models import User
|
|
from rest_framework import generics, status
|
|
from rest_framework.permissions import IsAuthenticated
|
|
from rest_framework.response import Response
|
|
from django.db.models import Count, Max
|
|
|
|
from .models import Account, Pantry, History, Favorite
|
|
from .serializers import (
|
|
AccountSerializer, FavoriteSerializer, HistorySerializer, PantrySerializer, ProfilePictureSerializer
|
|
)
|
|
from recipes.models import Information, RawIngredient
|
|
from recipes.serializers import RecipeInformationSerializer, RawIngredientSerializer
|
|
|
|
from .utils import calculate_top_recipes_by_ingredients, get_hybrid_recommendation, get_recommendations_for_user
|
|
|
|
|
|
class AccountView(generics.GenericAPIView):
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
serializer_class = AccountSerializer
|
|
|
|
def get(self, request):
|
|
account = Account.objects.get(user_id=request.user.id)
|
|
serializer = self.get_serializer(account)
|
|
return Response(serializer.data)
|
|
|
|
def post(self, request):
|
|
account = User.objects.get(id=request.user.id)
|
|
account_serializer = self.get_serializer(
|
|
instance=account, data=request.data)
|
|
profile_picture_serializer = ProfilePictureSerializer(
|
|
instance=account.account, data=request.data)
|
|
|
|
if profile_picture_serializer.is_valid(raise_exception=True):
|
|
profile_picture_serializer.save()
|
|
|
|
if account_serializer.is_valid(raise_exception=True):
|
|
account_serializer.save()
|
|
|
|
return Response(account_serializer.data)
|
|
|
|
|
|
class FavoriteView(generics.GenericAPIView):
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
def get(self, request):
|
|
user = request.user
|
|
|
|
recipes = Information.objects.filter(
|
|
favorite__user=user).order_by("-favorite__created_at")
|
|
|
|
recipes_serializer = RecipeInformationSerializer(
|
|
recipes, context={'request': request}, many=True)
|
|
return Response(recipes_serializer.data)
|
|
|
|
def post(self, request, recipe_id):
|
|
user = request.user
|
|
|
|
try:
|
|
recipe = Information.objects.get(id=recipe_id)
|
|
except Information.DoesNotExist:
|
|
return Response({'message': 'Resep tidak ditemukan'}, status=status.HTTP_404_NOT_FOUND)
|
|
|
|
source = request.data.get('source', '')
|
|
|
|
favorite, created = Favorite.objects.get_or_create(
|
|
user=user, recipe=recipe, source=source)
|
|
|
|
if created:
|
|
favorite_serializer = FavoriteSerializer(
|
|
favorite, context={'request': request})
|
|
return Response(favorite_serializer.data, status=status.HTTP_201_CREATED)
|
|
else:
|
|
return Response({'message': 'Anda sudah menambahkan resep ini ke favorit'}, status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
def delete(self, request, recipe_id):
|
|
favorite = Favorite.objects.filter(
|
|
recipe_id=recipe_id, user=request.user).first()
|
|
|
|
if favorite:
|
|
favorite.delete()
|
|
return Response({'message': 'Berhasil menghapus resep dari daftar favorit'}, status=status.HTTP_200_OK)
|
|
else:
|
|
return Response({'message': 'Data tidak ditemukan'}, status=status.HTTP_404_NOT_FOUND)
|
|
|
|
|
|
class HistoryView(generics.GenericAPIView):
|
|
|
|
def get(self, request):
|
|
user = request.user
|
|
recipes = Information.objects.filter(history__user=user).annotate(
|
|
newest_created_at=Max('history__created_at')).order_by('-newest_created_at')
|
|
recipes_serializer = RecipeInformationSerializer(
|
|
recipes, context={'request': request}, many=True)
|
|
return Response(recipes_serializer.data)
|
|
|
|
def post(self, request, recipe_id):
|
|
if request.user.is_authenticated:
|
|
user = request.user
|
|
else:
|
|
user = User.objects.get(id=4)
|
|
|
|
try:
|
|
recipe = Information.objects.get(id=recipe_id)
|
|
except Information.DoesNotExist:
|
|
return Response({'message': 'Resep tidak ditemukan'}, status=status.HTTP_404_NOT_FOUND)
|
|
|
|
source = request.data.get('source', '')
|
|
|
|
history = History(
|
|
user=user, recipe=recipe, source=source)
|
|
history.save()
|
|
|
|
history_serializer = HistorySerializer(history)
|
|
return Response(history_serializer.data, status=status.HTTP_201_CREATED)
|
|
|
|
def delete(self, request, recipe_id):
|
|
history = History.objects.filter(
|
|
recipe_id=recipe_id, user=request.user).first()
|
|
|
|
if history:
|
|
history.delete()
|
|
return Response({'message': 'History berhasil dihapus'}, status=status.HTTP_200_OK)
|
|
else:
|
|
return Response({'message': 'History tidak ditemukan'}, status=status.HTTP_404_NOT_FOUND)
|
|
|
|
|
|
class PantryView(generics.GenericAPIView):
|
|
permission_classes = [IsAuthenticated]
|
|
serializer_class = PantrySerializer
|
|
|
|
def get(self, request):
|
|
pantry = Pantry.objects.filter(user=request.user)
|
|
if pantry.exists():
|
|
serializer = PantrySerializer(pantry, many=True)
|
|
return Response(serializer.data, status=status.HTTP_200_OK)
|
|
else:
|
|
return Response({"message": "Penyimpanan kosong."}, status=status.HTTP_204_NO_CONTENT)
|
|
|
|
def post(self, request):
|
|
user = request.user
|
|
|
|
raw_ingredient_id = request.data.get('id')
|
|
amount = request.data.get('amount')
|
|
unit_id = request.data.get('unit_id')
|
|
raw_ingredient_ids = request.data.get('raw_ingredient_id', [])
|
|
|
|
if (len(raw_ingredient_ids) != 0):
|
|
Pantry.objects.filter(user=user).delete()
|
|
raw_ingredients = RawIngredient.objects.filter(
|
|
pk__in=raw_ingredient_ids)
|
|
for raw_ingredient in raw_ingredients:
|
|
pantry = Pantry(user=user, raw_ingredient=raw_ingredient)
|
|
pantry.save()
|
|
|
|
user = request.user
|
|
|
|
top_recipes = calculate_top_recipes_by_ingredients(user)[:12]
|
|
top_recipe_ids = [recipe['recipe_id'] for recipe in top_recipes]
|
|
recipes = Information.objects.filter(id__in=top_recipe_ids).annotate()
|
|
recipes_list = RecipeInformationSerializer(
|
|
recipes, context={'request': request, 'top_recipes': top_recipes}, many=True).data
|
|
sorted_recipes = sorted(
|
|
recipes_list,
|
|
key=lambda x: (0.8 * next(
|
|
(item['similarity'] for item in top_recipes if item['recipe_id'] == x['id']), 0)) +
|
|
(0.2 * x['completeness_percentage']),
|
|
reverse=True
|
|
)
|
|
|
|
return Response(sorted_recipes, status=status.HTTP_200_OK)
|
|
else:
|
|
try:
|
|
pantry = Pantry.objects.get(
|
|
user=user, raw_ingredient_id=raw_ingredient_id)
|
|
pantry.amount = amount
|
|
pantry.unit_id = unit_id
|
|
pantry.save()
|
|
pantry_serializer = PantrySerializer(pantry).data
|
|
return Response(pantry_serializer, status=status.HTTP_200_OK)
|
|
except Pantry.DoesNotExist:
|
|
pantry = Pantry.objects.create(
|
|
user=user, raw_ingredient_id=raw_ingredient_id, amount=amount, unit_id=unit_id)
|
|
pantry_serializer = PantrySerializer(pantry).data
|
|
return Response(pantry_serializer, status=status.HTTP_200_OK)
|
|
|
|
def delete(self, request, pantry_id):
|
|
pantry = Pantry.objects.filter(
|
|
user=request.user, id=pantry_id)
|
|
pantry.delete()
|
|
return Response('Berhasil menghapus data', status=status.HTTP_204_NO_CONTENT)
|
|
|
|
|
|
class UpdatePasswordView(generics.GenericAPIView):
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
def post(self, request):
|
|
user = request.user
|
|
current_password = request.data.get('current_password')
|
|
new_password = request.data.get('new_password')
|
|
if user.check_password(current_password):
|
|
user.set_password(new_password)
|
|
user.save()
|
|
return Response("Password berhasil diperbarui", status=status.HTTP_200_OK)
|
|
else:
|
|
return Response("Password saat ini salah", status=status.HTTP_400_BAD_REQUEST)
|
|
|
|
|
|
class PantryRecommendationView(generics.GenericAPIView):
|
|
permission_classes = [IsAuthenticated]
|
|
|
|
def get(self, request):
|
|
user = request.user
|
|
|
|
top_recipes = calculate_top_recipes_by_ingredients(user)[:20]
|
|
top_recipe_ids = [recipe['recipe_id'] for recipe in top_recipes]
|
|
recipes = Information.objects.filter(id__in=top_recipe_ids).annotate()
|
|
recipes_list = RecipeInformationSerializer(
|
|
recipes, context={'request': request, 'top_recipes': top_recipes}, many=True).data
|
|
|
|
filtered_recipes = [
|
|
recipe for recipe in recipes_list if recipe['completeness_percentage'] > 0]
|
|
|
|
sorted_recipes = sorted(
|
|
filtered_recipes,
|
|
key=lambda x: (0.8 * next(
|
|
(item['similarity'] for item in top_recipes if item['recipe_id'] == x['id']), 0)) +
|
|
(0.2 * x['completeness_percentage']),
|
|
reverse=True
|
|
)
|
|
|
|
sorted_recipes = sorted_recipes[:12]
|
|
return Response(sorted_recipes, status=status.HTTP_200_OK)
|
|
|
|
|
|
class CFRecommendationView(generics.GenericAPIView):
|
|
permission_classes = [IsAuthenticated]
|
|
serializer_class = RecipeInformationSerializer
|
|
|
|
def get(self, request):
|
|
user_id = self.request.user.id
|
|
top_recipes = get_recommendations_for_user(user_id)[:20]
|
|
top_recipes_ids = [recipe['recipe_id']
|
|
for recipe in top_recipes]
|
|
|
|
recipes = Information.objects.filter(
|
|
id__in=top_recipes_ids)
|
|
recipes_list = RecipeInformationSerializer(
|
|
recipes, context={'request': request, 'top_recipes': top_recipes}, many=True).data
|
|
sorted_recipes = sorted(
|
|
recipes_list, key=lambda x: x['similarity'], reverse=True)
|
|
return Response(sorted_recipes, status=status.HTTP_200_OK)
|
|
|
|
|
|
class MostViewedRecommendationView(generics.GenericAPIView):
|
|
|
|
def get(self, request):
|
|
recipe_counts = History.objects.values('recipe_id').annotate(
|
|
count=Count('recipe_id')).order_by('-count')[:9]
|
|
|
|
recipe_ids = [count['recipe_id'] for count in recipe_counts]
|
|
|
|
recipes = Information.objects.filter(
|
|
id__in=recipe_ids).annotate(history_count=Count('history')).order_by('-history_count')
|
|
recipes_list = RecipeInformationSerializer(
|
|
recipes, context={'request': request}, many=True).data
|
|
return Response(recipes_list, status=status.HTTP_200_OK)
|
|
|
|
|
|
class FavoriteRecommendationView(generics.GenericAPIView):
|
|
|
|
def get(self, request):
|
|
recipe_counts = Favorite.objects.values('recipe_id').annotate(
|
|
count=Count('recipe_id')).order_by('-count')[:9]
|
|
|
|
recipe_ids = [count['recipe_id'] for count in recipe_counts]
|
|
|
|
recipes = Information.objects.filter(
|
|
id__in=recipe_ids).annotate(favorite_count=Count('favorite')).order_by('-favorite_count')
|
|
recipes_list = RecipeInformationSerializer(
|
|
recipes, context={'request': request}, many=True).data
|
|
return Response(recipes_list, status=status.HTTP_200_OK)
|
|
|
|
|
|
# Unused
|
|
class HybridRecommendationView(generics.GenericAPIView):
|
|
permission_classes = [IsAuthenticated]
|
|
serializer_class = RecipeInformationSerializer
|
|
|
|
def get(self, request):
|
|
user_id = self.request.user.id
|
|
recommended_recipe_ids = get_hybrid_recommendation(user_id)[:9]
|
|
|
|
recipes = Information.objects.filter(id__in=recommended_recipe_ids)
|
|
recipes_list = RecipeInformationSerializer(
|
|
recipes, context={'request': request}, many=True).data
|
|
sorted_recipes = sorted(
|
|
recipes_list, key=lambda x: x['completeness_percentage'], reverse=True)[:9]
|
|
|
|
return Response(sorted_recipes, status=status.HTTP_200_OK)
|