images and steps added to recipe

This commit is contained in:
durn
2026-03-03 05:45:39 -07:00
parent e2fb9c1034
commit fcb00b32a7
7 changed files with 243 additions and 30 deletions
@@ -0,0 +1,26 @@
package com.example.demo.dto;
public class ImageDto {
String imageUrl;
public ImageDto() {
super();
}
public ImageDto(String imageUrl) {
super();
this.imageUrl = imageUrl;
}
public String getImageUrl() {
return imageUrl;
}
public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}
}
@@ -13,6 +13,8 @@ public class RecipeDto {
private UserDto userDto;
private String status;
private List<RecipeIngredientDto> ingredients;
private List<StepDto> steps;
private List<ImageDto> images;
@@ -22,7 +24,7 @@ public class RecipeDto {
}
public RecipeDto(String title, String description, Integer prepTimeMinutes, Integer cookTimeMinutes,
Integer servings, UserDto userDto, String status, List<RecipeIngredientDto> ingredients) {
Integer servings, UserDto userDto, String status, List<RecipeIngredientDto> ingredients, List<StepDto> steps, List<ImageDto> images) {
super();
this.title = title;
this.description = description;
@@ -32,6 +34,8 @@ public class RecipeDto {
this.userDto = userDto;
this.status = status;
this.ingredients = ingredients;
this.steps = steps;
this.images = images;
}
// getters and setters
@@ -79,6 +83,23 @@ public class RecipeDto {
this.ingredients = ingredients;
}
public List<StepDto> getSteps() {
return steps;
}
public void setSteps(List<StepDto> steps) {
this.steps = steps;
}
public List<ImageDto> getImages() {
return images;
}
public void setImages(List<ImageDto> images) {
this.images = images;
}
public UserDto getUserDto() {
return userDto;
}
@@ -1,5 +1,29 @@
package com.example.demo.dto;
public class StepDto {
private Integer stepNumber;
private String instruction;
public StepDto() {}
public StepDto(Integer stepNumber, String instruction) {
this.stepNumber = stepNumber;
this.instruction = instruction;
}
public Integer getStepNumber() {
return stepNumber;
}
public void setStepNumber(Integer stepNumber) {
this.stepNumber = stepNumber;
}
public String getInstruction() {
return instruction;
}
public void setInstruction(String instruction) {
this.instruction = instruction;
}
}
@@ -1,6 +1,8 @@
package com.example.demo.entity;
import jakarta.persistence.*;
import lombok.EqualsAndHashCode;
import java.time.LocalDateTime;
@Entity
@@ -11,8 +13,10 @@ public class Image {
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "recipe_id", nullable = false)
private Integer recipeId;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "recipe_id", nullable = false)
@EqualsAndHashCode.Include
private Recipe recipe;
@Column(name = "image_url", nullable = false)
private String imageUrl;
@@ -22,8 +26,8 @@ public class Image {
public Image() {}
public Image(Integer recipeId, String imageUrl) {
this.recipeId = recipeId;
public Image(Recipe recipe, String imageUrl) {
this.recipe = recipe;
this.imageUrl = imageUrl;
this.createdAt = LocalDateTime.now();
}
@@ -32,10 +36,15 @@ public class Image {
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
public Integer getRecipeId() { return recipeId; }
public void setRecipeId(Integer recipeId) { this.recipeId = recipeId; }
public Recipe getRecipe() {
return recipe;
}
public String getImageUrl() { return imageUrl; }
public void setRecipe(Recipe recipe) {
this.recipe = recipe;
}
public String getImageUrl() { return imageUrl; }
public void setImageUrl(String imageUrl) { this.imageUrl = imageUrl; }
public LocalDateTime getCreatedAt() { return createdAt; }
@@ -40,6 +40,14 @@ public class Recipe {
@OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
private Set<RecipeIngredient> recipeIngredients = new HashSet<>();
// Recipe Steps relationship
@OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
private Set<Step> steps = new HashSet<>();
// Recipe Images relationship
@OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
private Set<Image> images = new HashSet<>();
// Default constructor
public Recipe() {}
@@ -123,4 +131,20 @@ public class Recipe {
public Set<RecipeIngredient> getRecipeIngredients() { return recipeIngredients; }
public void setRecipeIngredients(Set<RecipeIngredient> recipeIngredients) { this.recipeIngredients = recipeIngredients; }
public Set<Step> getSteps() {
return steps;
}
public void setSteps(Set<Step> steps) {
this.steps = steps;
}
public Set<Image> getImages() {
return images;
}
public void setImages(Set<Image> images) {
this.images = images;
}
}
@@ -1,6 +1,7 @@
package com.example.demo.entity;
import jakarta.persistence.*;
import lombok.EqualsAndHashCode;
@Entity
@Table(name = "steps")
@@ -10,20 +11,21 @@ public class Step {
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "recipe_id", nullable = false)
private Integer recipeId;
@Column(name = "step_number", nullable = false)
private Integer stepNumber;
@Column(name = "instruction", nullable = false, columnDefinition = "TEXT")
private String instruction;
// No-arg constructor required by JPA
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "recipe_id", nullable = false)
@EqualsAndHashCode.Include
private Recipe recipe;
public Step() {}
public Step(Integer recipeId, Integer stepNumber, String instruction) {
this.recipeId = recipeId;
public Step(Recipe recipe, Integer stepNumber, String instruction) {
this.recipe = recipe;
this.stepNumber = stepNumber;
this.instruction = instruction;
}
@@ -32,10 +34,15 @@ public class Step {
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
public Integer getRecipeId() { return recipeId; }
public void setRecipeId(Integer recipeId) { this.recipeId = recipeId; }
public Recipe getRecipe() {
return recipe;
}
public Integer getStepNumber() { return stepNumber; }
public void setRecipe(Recipe recipe) {
this.recipe = recipe;
}
public Integer getStepNumber() { return stepNumber; }
public void setStepNumber(Integer stepNumber) { this.stepNumber = stepNumber; }
public String getInstruction() { return instruction; }
@@ -7,15 +7,21 @@ import org.springframework.stereotype.Service;
import com.example.demo.dto.RecipeDto;
import com.example.demo.dto.UserDto;
import com.example.demo.dto.StepDto;
import com.example.demo.dto.ImageDto;
import com.example.demo.dto.RecipeIngredientDto;
import com.example.demo.entity.Image;
import com.example.demo.entity.Ingredient;
import com.example.demo.entity.Recipe;
import com.example.demo.entity.RecipeIngredient;
import com.example.demo.entity.Step;
import com.example.demo.entity.User;
import com.example.demo.exception.NotFoundException;
import com.example.demo.repository.ImageRepo;
import com.example.demo.repository.IngredientRepo;
import com.example.demo.repository.RecipeIngredientRepo;
import com.example.demo.repository.RecipeRepo;
import com.example.demo.repository.StepRepo;
import com.example.demo.repository.UserRepo;
import com.example.demo.service.RecipeService;
@@ -29,13 +35,17 @@ private RecipeRepo recipeRepository;
private IngredientRepo ingredientRepository;
private RecipeIngredientRepo recipeIngredientRepository;
private UserRepo userRepository;
private StepRepo stepRepository;
private ImageRepo imageRepository;
public RecipeServiceImpl(RecipeRepo recipeRepository, IngredientRepo ingredientRepository, RecipeIngredientRepo recipeIngredientRepository, UserRepo userRepository) {
public RecipeServiceImpl(RecipeRepo recipeRepository, IngredientRepo ingredientRepository, RecipeIngredientRepo recipeIngredientRepository, UserRepo userRepository, StepRepo stepRepository, ImageRepo imageRepository) {
super();
this.recipeRepository = recipeRepository;
this.ingredientRepository = ingredientRepository;
this.recipeIngredientRepository = recipeIngredientRepository;
this.userRepository = userRepository;
this.stepRepository = stepRepository;
this.imageRepository = imageRepository;
}
public RecipeDto convertToDto(Recipe recipe) {
@@ -48,7 +58,21 @@ private UserRepo userRepository;
))
.toList();
List<StepDto> stepDtos = recipe.getSteps().stream()
.map(ri -> new StepDto(
ri.getStepNumber(),
ri.getInstruction()
))
.toList();
List<ImageDto> imageDtos = recipe.getImages().stream()
.map(ri -> new ImageDto(
ri.getImageUrl()
))
.toList();
UserDto userDto = new UserDto(recipe.getUser().getId());
return new RecipeDto(
recipe.getTitle(),
recipe.getDescription(),
@@ -57,7 +81,9 @@ private UserRepo userRepository;
recipe.getServings(),
userDto,
recipe.getStatus(),
ingredientDtos
ingredientDtos,
stepDtos,
imageDtos
);
}
@@ -70,7 +96,7 @@ private UserRepo userRepository;
Recipe recipe = new Recipe(
dto.getTitle(),
dto.getDescription(),
dto.getPrepTimeMinutes(),+
dto.getPrepTimeMinutes(),
dto.getCookTimeMinutes(),
dto.getServings(),
user,
@@ -99,11 +125,24 @@ private UserRepo userRepository;
recipe.getRecipeIngredients().add(ri);
}
recipeRepository.save(recipe);
return dto;
if (dto.getSteps() != null) {
for (StepDto stepDto : dto.getSteps()) {
Step step = new Step(recipe, stepDto.getStepNumber(), stepDto.getInstruction());
recipe.getSteps().add(step);
}
}
if (dto.getImages() != null) {
for (ImageDto imageDto : dto.getImages()) {
Image image = new Image(recipe, imageDto.getImageUrl());
recipe.getImages().add(image);
}
}
Recipe saved = recipeRepository.save(recipe);
return convertToDto(saved);
}
@Override
@@ -143,6 +182,12 @@ private UserRepo userRepository;
List<RecipeIngredientDto> updatedIngredients = recipeDto.getIngredients();
List<RecipeIngredient> ingredientsToRemove = new ArrayList<>();
List<StepDto> updatedSteps = recipeDto.getSteps();
List<Step> stepsToRemove = new ArrayList<>();
List<ImageDto> updatedImages = recipeDto.getImages();
List<Image> imagesToRemove = new ArrayList<>();
for (RecipeIngredient ri : existingRecipe.getRecipeIngredients()) {
boolean existsInUpdatedList = false;
@@ -202,7 +247,64 @@ private UserRepo userRepository;
}
}
if(updatedSteps != null) {
// find steps that weren't included
for (Step step : existingRecipe.getSteps()) {
boolean existsInUpdatedList = updatedSteps.stream()
.anyMatch(dto -> dto.getStepNumber().equals(step.getStepNumber()));
if (!existsInUpdatedList) stepsToRemove.add(step);
}
// delete those steps
existingRecipe.getSteps().removeAll(stepsToRemove);
// go through updated steps
for (StepDto stepDto : updatedSteps) {
// find matching step by step number
Step existingStep = existingRecipe.getSteps().stream()
.filter(s -> s.getStepNumber().equals(stepDto.getStepNumber()))
.findFirst()
.orElse(null);
// if there's a match update the instruction string
if (existingStep != null) {
existingStep.setInstruction(stepDto.getInstruction());
}
// if no match then make a whole new step
else {
Step newStep = new Step(existingRecipe, stepDto.getStepNumber(), stepDto.getInstruction());
existingRecipe.getSteps().add(newStep);
}
}
}
//same process as above just with images instead
if (updatedImages != null) {
for (Image image : existingRecipe.getImages()) {
boolean existsInUpdatedList = updatedImages.stream()
.anyMatch(dto -> dto.getImageUrl().equals(image.getImageUrl()));
if (!existsInUpdatedList) imagesToRemove.add(image);
}
existingRecipe.getImages().removeAll(imagesToRemove);
for (ImageDto imageDto : updatedImages) {
Image existingImage = existingRecipe.getImages().stream()
.filter(img -> img.getImageUrl().equals(imageDto.getImageUrl()))
.findFirst()
.orElse(null);
if (existingImage != null) {
existingImage.setImageUrl(imageDto.getImageUrl());
}
else {
Image newImage = new Image(existingRecipe, imageDto.getImageUrl());
existingRecipe.getImages().add(newImage);
}
}
}
recipeRepository.save(existingRecipe);
return convertToDto(existingRecipe);
}