Skip to content

Commit

Permalink
Merge pull request #192 from uocli/pr/main/176
Browse files Browse the repository at this point in the history
Pr/main/176
  • Loading branch information
uocli authored Dec 8, 2024
2 parents ef14b33 + 07d2bab commit 6cd278f
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 4 deletions.
7 changes: 7 additions & 0 deletions backend/api/custom_models/public_recipe_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from django.contrib.auth.models import User
from django.db import models

from .favorites_model import Favorite
from ..utils.unsplash import UnsplashAPI


Expand All @@ -20,6 +21,12 @@ def __str__(self):
class PublicRecipe(models.Model):
uuid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
name = models.CharField(max_length=255)
favorite = models.OneToOneField(
Favorite,
on_delete=models.CASCADE,
related_name="public_recipe",
null=True,
)
image_url = models.URLField(max_length=500, blank=True)
description = models.TextField()
ingredients = models.ManyToManyField(Ingredient, related_name="ingredients")
Expand Down
98 changes: 97 additions & 1 deletion backend/api/custom_views/recipe_views.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import json

from django.db.models import Avg, Value, FloatField
from django.db.models.functions import Coalesce
from rest_framework import status, permissions
from rest_framework.views import APIView
from rest_framework.response import Response
from ..custom_models.public_recipe_models import PublicRecipe, Rating

from ..custom_models.favorites_model import Favorite
from ..custom_models.public_recipe_models import PublicRecipe, Rating, Ingredient
from ..serializers.recipe_serializers import RecipeSerializer


Expand Down Expand Up @@ -77,3 +81,95 @@ def post(self, request, uuid):
{"message": str(e)},
status=status.HTTP_400_BAD_REQUEST,
)


class RecipeCreateView(APIView):
permission_classes = [permissions.IsAuthenticated]

def post(self, request, pk):
user = request.user
is_shared = request.data.get("is_shared", False)

try:
favorite = Favorite.objects.get(user=user, id=pk)
except Favorite.DoesNotExist:
return Response(
{
"success": False,
"message": "Favorite recipe not found.",
},
status=status.HTTP_404_NOT_FOUND,
)

if not is_shared:
# Unshare
if hasattr(favorite, "public_recipe"):
# Delete the public recipe if it exists and is_shared is False
favorite.public_recipe.delete()
return Response(
{
"success": True,
"message": "Public recipe deleted successfully.",
},
status=status.HTTP_200_OK,
)
else:
return Response(
{
"success": False,
"message": "Public recipe does not exist for this favorite.",
},
status=status.HTTP_400_BAD_REQUEST,
)
else:
# Share
if hasattr(favorite, "public_recipe"):
return Response(
{
"success": False,
"message": "Public recipe already exists for this favorite.",
},
status=status.HTTP_400_BAD_REQUEST,
)
else:
# Create the public recipe if it does not exist
ingredients = favorite.ingredients
recipe_steps = favorite.recipe

if ingredients:
ingredients_data = json.loads(ingredients)
ingredient_names = [
ingredient["ingredient"].lower()
for ingredient in ingredients_data
]

# Create or get ingredients
ingredient_objects = []
for name in ingredient_names:
ingredient, created = Ingredient.objects.get_or_create(
name=name
)
ingredient_objects.append(ingredient)

instructions = ""
if recipe_steps:
instructions = "\n".join(json.loads(recipe_steps))

# Create the public recipe
public_recipe = PublicRecipe.objects.create(
favorite=favorite,
name=favorite.name,
description=favorite.name,
instructions=instructions,
)

# Add ingredients to the public recipe
public_recipe.ingredients.set(ingredient_objects)

return Response(
{
"success": True,
"message": "Public recipe created successfully.",
},
status=status.HTTP_201_CREATED,
)
13 changes: 11 additions & 2 deletions backend/api/serializers/favorites_serializer.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,16 @@


class FavoriteSerializer(serializers.ModelSerializer):
is_shared = serializers.SerializerMethodField()

class Meta:
model = Favorite
fields = ['id', 'user', 'name', 'ingredients', 'recipe', 'added_at']
read_only_fields = ['id', 'user', 'added_at']
fields = ['id', 'user', 'name', 'ingredients', 'recipe', 'added_at',
"is_shared",
]
read_only_fields = ['id', 'user', 'added_at',
"is_shared",
]

def get_is_shared(self, obj):
return hasattr(obj, "public_recipe")
3 changes: 2 additions & 1 deletion backend/api/urls.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from django.urls import path, include

from .custom_views.recipe_views import RecipeListView, RecipeDetailView, RecipeRateView, RecipeCreateView
from .custom_views.background_views import RandomRecipeImageView
from .custom_views.recipe_views import RecipeListView, RecipeDetailView, RecipeRateView
from .custom_views.user_profile_views import UserProfileView
from .custom_views.favorites_view import FavoriteListView, FavoriteDeleteView
from .custom_views.shopping_list_views import ShoppingListView
Expand All @@ -15,6 +15,7 @@
path("email/", include("api.custom_urls.email_request_urls"), name="email-requests"),
path('favorites/', FavoriteListView.as_view(), name='favorites-list'),
path('favorites/<int:pk>/', FavoriteDeleteView.as_view(), name='favorite-delete'),
path("favorites/share/<int:pk>/", RecipeCreateView.as_view(), name="favorite-share"),
path('shopping-list/', ShoppingListView.as_view(), name='shopping-list'),
path("favorites/<int:pk>/add-to-shopping-list/", AddToShoppingListView.as_view(), name="add-to-shopping-list"),
path("generate/", RecipeGeneratorView.as_view(), name="recipe_generate"),
Expand Down
34 changes: 34 additions & 0 deletions frontend/src/components/Favorites.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,31 @@ const Favorites = () => {
}
};

const handleTogglePublic = async (event) => {
try {
const { target } = event || {},
{ checked, dataset } = target || {},
{ id } = dataset || {};
const response = await axios.post(`/api/favorites/share/${id}/`, {
is_shared: checked,
});
// Update the state to reflect the new value
setFavorites((prevFavorites) =>
prevFavorites.map((favorite) =>
favorite.id === parseInt(id)
? { ...favorite, is_shared: checked }
: favorite,
),
);
if (sessionStorage.getItem("recipemate__recipes")) {
// Clear the session storage if the user makes a recipe public
sessionStorage.removeItem("recipemate__recipes");
}
showAlert(response.data.message, "success");
} catch (error) {
showAlert("Failed to make the recipe public.", "error");
}
};

return (
<div className="container">
Expand Down Expand Up @@ -75,6 +100,15 @@ const Favorites = () => {
>
Add Ingredients to Shopping List
</button>
<label className="toggle-label">
<input
type="checkbox"
checked={favorite.is_shared}
data-id={favorite.id}
onChange={handleTogglePublic}
/>
Make Public
</label>
</li>
))}
</ul>
Expand Down

0 comments on commit 6cd278f

Please sign in to comment.