diff --git a/demo/src/main/java/com/example/demo/dto/ImageDto.java b/demo/src/main/java/com/example/demo/dto/ImageDto.java new file mode 100644 index 0000000..e0bdd39 --- /dev/null +++ b/demo/src/main/java/com/example/demo/dto/ImageDto.java @@ -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; + } + + +} diff --git a/demo/src/main/java/com/example/demo/dto/RecipeDto.java b/demo/src/main/java/com/example/demo/dto/RecipeDto.java index 22feb25..8b0244a 100644 --- a/demo/src/main/java/com/example/demo/dto/RecipeDto.java +++ b/demo/src/main/java/com/example/demo/dto/RecipeDto.java @@ -13,6 +13,8 @@ public class RecipeDto { private UserDto userDto; private String status; private List ingredients; + private List steps; + private List 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 ingredients) { + Integer servings, UserDto userDto, String status, List ingredients, List steps, List 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 getSteps() { + return steps; + } + + public void setSteps(List steps) { + this.steps = steps; + } + + + public List getImages() { + return images; + } + + public void setImages(List images) { + this.images = images; + } + public UserDto getUserDto() { return userDto; } diff --git a/demo/src/main/java/com/example/demo/dto/StepDto.java b/demo/src/main/java/com/example/demo/dto/StepDto.java index 71949d5..dac9030 100644 --- a/demo/src/main/java/com/example/demo/dto/StepDto.java +++ b/demo/src/main/java/com/example/demo/dto/StepDto.java @@ -1,5 +1,29 @@ -package com.example.demo.dto; - -public class StepDto { - -} +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; + } +} \ No newline at end of file diff --git a/demo/src/main/java/com/example/demo/entity/Image.java b/demo/src/main/java/com/example/demo/entity/Image.java index ea6be16..3ae18f7 100644 --- a/demo/src/main/java/com/example/demo/entity/Image.java +++ b/demo/src/main/java/com/example/demo/entity/Image.java @@ -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; } diff --git a/demo/src/main/java/com/example/demo/entity/Recipe.java b/demo/src/main/java/com/example/demo/entity/Recipe.java index c4ee101..decc67f 100644 --- a/demo/src/main/java/com/example/demo/entity/Recipe.java +++ b/demo/src/main/java/com/example/demo/entity/Recipe.java @@ -39,6 +39,14 @@ public class Recipe { // Recipe ingredients relationship @OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) private Set recipeIngredients = new HashSet<>(); + + // Recipe Steps relationship + @OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) + private Set steps = new HashSet<>(); + + // Recipe Images relationship + @OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) + private Set images = new HashSet<>(); // Default constructor @@ -123,4 +131,20 @@ public class Recipe { public Set getRecipeIngredients() { return recipeIngredients; } public void setRecipeIngredients(Set recipeIngredients) { this.recipeIngredients = recipeIngredients; } + public Set getSteps() { + return steps; + } + + public void setSteps(Set steps) { + this.steps = steps; + } + + public Set getImages() { + return images; + } + + public void setImages(Set images) { + this.images = images; + } + } \ No newline at end of file diff --git a/demo/src/main/java/com/example/demo/entity/Step.java b/demo/src/main/java/com/example/demo/entity/Step.java index 3264682..da6c90e 100644 --- a/demo/src/main/java/com/example/demo/entity/Step.java +++ b/demo/src/main/java/com/example/demo/entity/Step.java @@ -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; } diff --git a/demo/src/main/java/com/example/demo/service/Impl/RecipeServiceImpl.java b/demo/src/main/java/com/example/demo/service/Impl/RecipeServiceImpl.java index 0b93223..5c6cfc0 100644 --- a/demo/src/main/java/com/example/demo/service/Impl/RecipeServiceImpl.java +++ b/demo/src/main/java/com/example/demo/service/Impl/RecipeServiceImpl.java @@ -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 stepDtos = recipe.getSteps().stream() + .map(ri -> new StepDto( + ri.getStepNumber(), + ri.getInstruction() + )) + .toList(); + + List 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 @@ -142,6 +181,12 @@ private UserRepo userRepository; List updatedIngredients = recipeDto.getIngredients(); List ingredientsToRemove = new ArrayList<>(); + + List updatedSteps = recipeDto.getSteps(); + List stepsToRemove = new ArrayList<>(); + + List updatedImages = recipeDto.getImages(); + List imagesToRemove = new ArrayList<>(); for (RecipeIngredient ri : existingRecipe.getRecipeIngredients()) { @@ -201,8 +246,65 @@ private UserRepo userRepository; existingRecipe.getRecipeIngredients().add(newRI); } } - + 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); }