From d03cbaf9a37bbb11924c9095848744aefe3f2389 Mon Sep 17 00:00:00 2001 From: durn Date: Tue, 3 Mar 2026 21:44:04 -0700 Subject: [PATCH] tag recipe relationship made --- .../example/demo/config/SecurityConfig.java | 3 +- .../java/com/example/demo/dto/ImageDto.java | 2 +- .../java/com/example/demo/dto/RecipeDto.java | 13 +++- .../java/com/example/demo/dto/TagDto.java | 28 ++++++++ .../java/com/example/demo/entity/Recipe.java | 17 +++++ .../java/com/example/demo/entity/Tag.java | 17 +++++ .../com/example/demo/repository/TagRepo.java | 5 +- .../demo/service/Impl/RecipeServiceImpl.java | 71 ++++++++++++++++++- 8 files changed, 147 insertions(+), 9 deletions(-) create mode 100644 demo/src/main/java/com/example/demo/dto/TagDto.java diff --git a/demo/src/main/java/com/example/demo/config/SecurityConfig.java b/demo/src/main/java/com/example/demo/config/SecurityConfig.java index 2ab21b5..8c5850e 100644 --- a/demo/src/main/java/com/example/demo/config/SecurityConfig.java +++ b/demo/src/main/java/com/example/demo/config/SecurityConfig.java @@ -10,8 +10,7 @@ public class SecurityConfig { @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - http - .csrf(csrf -> csrf.disable()) + http.csrf(csrf -> csrf.disable()) .authorizeHttpRequests(auth -> auth .anyRequest().permitAll() ); diff --git a/demo/src/main/java/com/example/demo/dto/ImageDto.java b/demo/src/main/java/com/example/demo/dto/ImageDto.java index e0bdd39..c68ec9e 100644 --- a/demo/src/main/java/com/example/demo/dto/ImageDto.java +++ b/demo/src/main/java/com/example/demo/dto/ImageDto.java @@ -23,4 +23,4 @@ public class ImageDto { } -} +} \ No newline at end of file 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 8b0244a..30927be 100644 --- a/demo/src/main/java/com/example/demo/dto/RecipeDto.java +++ b/demo/src/main/java/com/example/demo/dto/RecipeDto.java @@ -15,6 +15,7 @@ public class RecipeDto { private List ingredients; private List steps; private List images; + private List tags; @@ -24,7 +25,7 @@ public class RecipeDto { } public RecipeDto(String title, String description, Integer prepTimeMinutes, Integer cookTimeMinutes, - Integer servings, UserDto userDto, String status, List ingredients, List steps, List images) { + Integer servings, UserDto userDto, String status, List ingredients, List steps, List images, List tags) { super(); this.title = title; this.description = description; @@ -36,6 +37,7 @@ public class RecipeDto { this.ingredients = ingredients; this.steps = steps; this.images = images; + this.tags = tags; } // getters and setters @@ -99,6 +101,15 @@ public class RecipeDto { public void setImages(List images) { this.images = images; } + + + public List getTags() { + return tags; + } + + public void setTags(List tags) { + this.tags = tags; + } public UserDto getUserDto() { return userDto; diff --git a/demo/src/main/java/com/example/demo/dto/TagDto.java b/demo/src/main/java/com/example/demo/dto/TagDto.java new file mode 100644 index 0000000..b89af97 --- /dev/null +++ b/demo/src/main/java/com/example/demo/dto/TagDto.java @@ -0,0 +1,28 @@ +package com.example.demo.dto; + +public class TagDto { + private String name; + + public TagDto() { + super(); + } + + + + public TagDto(String name) { + super(); + this.name = name; + } + + + + public String getName() { + return name; + } + + + + public void setName(String name) { + this.name = name; + } +} 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 decc67f..8e88a69 100644 --- a/demo/src/main/java/com/example/demo/entity/Recipe.java +++ b/demo/src/main/java/com/example/demo/entity/Recipe.java @@ -47,6 +47,13 @@ public class Recipe { // Recipe Images relationship @OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) private Set images = new HashSet<>(); + + // Recipe Tag relationship and also junction table + @ManyToMany(fetch = FetchType.LAZY) + @JoinTable(name = "recipe_tags", + joinColumns = {@JoinColumn(name = "recipe_id")}, + inverseJoinColumns = {@JoinColumn(name = "tag_id")}) + private Set tags = new HashSet<>(); // Default constructor @@ -147,4 +154,14 @@ public class Recipe { this.images = images; } + public Set getTags() { + return tags; + } + + public void setTags(Set tags) { + this.tags = tags; + } + + + } \ No newline at end of file diff --git a/demo/src/main/java/com/example/demo/entity/Tag.java b/demo/src/main/java/com/example/demo/entity/Tag.java index 7aa3dc0..7d899df 100644 --- a/demo/src/main/java/com/example/demo/entity/Tag.java +++ b/demo/src/main/java/com/example/demo/entity/Tag.java @@ -1,5 +1,8 @@ package com.example.demo.entity; +import java.util.HashSet; +import java.util.Set; + import jakarta.persistence.*; @Entity @@ -12,6 +15,10 @@ public class Tag { @Column(nullable = false, unique = true) private String name; + + // Recipe is the manager for this relationship + @ManyToMany(fetch = FetchType.LAZY, mappedBy = "tags") + private Set recipes = new HashSet<>(); // Required by JPA public Tag() {} @@ -36,4 +43,14 @@ public class Tag { public void setName(String name) { this.name = name; } + + public Set getRecipes() { + return recipes; + } + + public void setRecipes(Set recipes) { + this.recipes = recipes; + } + + } \ No newline at end of file diff --git a/demo/src/main/java/com/example/demo/repository/TagRepo.java b/demo/src/main/java/com/example/demo/repository/TagRepo.java index e9ad307..647482b 100644 --- a/demo/src/main/java/com/example/demo/repository/TagRepo.java +++ b/demo/src/main/java/com/example/demo/repository/TagRepo.java @@ -2,12 +2,11 @@ package com.example.demo.repository; import org.springframework.data.jpa.repository.JpaRepository; +import com.example.demo.entity.Ingredient; import com.example.demo.entity.Tag; import java.util.Optional; public interface TagRepo extends JpaRepository { - - - + Optional findByName(String name); } \ No newline at end of file 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 5c6cfc0..02dc5f3 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 @@ -8,6 +8,7 @@ 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.TagDto; import com.example.demo.dto.ImageDto; import com.example.demo.dto.RecipeIngredientDto; import com.example.demo.entity.Image; @@ -15,6 +16,7 @@ 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.Tag; import com.example.demo.entity.User; import com.example.demo.exception.NotFoundException; import com.example.demo.repository.ImageRepo; @@ -22,6 +24,7 @@ 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.TagRepo; import com.example.demo.repository.UserRepo; import com.example.demo.service.RecipeService; @@ -37,8 +40,9 @@ private RecipeIngredientRepo recipeIngredientRepository; private UserRepo userRepository; private StepRepo stepRepository; private ImageRepo imageRepository; +private TagRepo tagRepository; - public RecipeServiceImpl(RecipeRepo recipeRepository, IngredientRepo ingredientRepository, RecipeIngredientRepo recipeIngredientRepository, UserRepo userRepository, StepRepo stepRepository, ImageRepo imageRepository) { + public RecipeServiceImpl(RecipeRepo recipeRepository, IngredientRepo ingredientRepository, RecipeIngredientRepo recipeIngredientRepository, UserRepo userRepository, StepRepo stepRepository, ImageRepo imageRepository, TagRepo tagRepository) { super(); this.recipeRepository = recipeRepository; this.ingredientRepository = ingredientRepository; @@ -46,6 +50,7 @@ private ImageRepo imageRepository; this.userRepository = userRepository; this.stepRepository = stepRepository; this.imageRepository = imageRepository; + this.tagRepository = tagRepository; } public RecipeDto convertToDto(Recipe recipe) { @@ -71,6 +76,12 @@ private ImageRepo imageRepository; )) .toList(); + List tagDtos = recipe.getTags().stream() + .map(ri -> new TagDto( + ri.getName() + )) + .toList(); + UserDto userDto = new UserDto(recipe.getUser().getId()); return new RecipeDto( @@ -83,7 +94,8 @@ private ImageRepo imageRepository; recipe.getStatus(), ingredientDtos, stepDtos, - imageDtos + imageDtos, + tagDtos ); } @@ -140,6 +152,27 @@ private ImageRepo imageRepository; } } +// if (dto.getTags() != null) { +// for (TagDto tagDto : dto.getTags()) { +// Tag tag = new Tag(tagDto.getName()); +// tagRepository.save(tag); +// recipe.getTags().add(tag); +// } +// } + + for (TagDto tDto : dto.getTags()) { + + + Tag tag = tagRepository.findByName(tDto.getName()) + .orElseGet(() -> new Tag(tDto.getName())); + + + if (tag.getId() == null) { + tagRepository.save(tag); + } + recipe.getTags().add(tag); + } + Recipe saved = recipeRepository.save(recipe); return convertToDto(saved); @@ -187,6 +220,9 @@ private ImageRepo imageRepository; List updatedImages = recipeDto.getImages(); List imagesToRemove = new ArrayList<>(); + + List updatedTags = recipeDto.getTags(); + List tagsToRemove = new ArrayList<>(); for (RecipeIngredient ri : existingRecipe.getRecipeIngredients()) { @@ -305,6 +341,37 @@ private ImageRepo imageRepository; } } } + + + + //same process as above just with tags instead, except for saving the tag + // since the relationship for this one was slightly different + if (updatedTags != null) { + for (Tag tag : existingRecipe.getTags()) { + boolean existsInUpdatedList = updatedTags.stream() + .anyMatch(dto -> dto.getName().equals(tag.getName())); + if (!existsInUpdatedList) tagsToRemove.add(tag); + } + + existingRecipe.getTags().removeAll(tagsToRemove); + + for (TagDto tagDto : updatedTags) { + Tag existingTag = existingRecipe.getTags().stream() + .filter(tag -> tag.getName().equals(tagDto.getName())) + .findFirst() + .orElse(null); + + if (existingTag != null) { + existingTag.setName(tagDto.getName()); + } + else { + Tag newTag = tagRepository.findByName(tagDto.getName()) + .orElseGet(() -> tagRepository.save(new Tag(tagDto.getName()))); + + existingRecipe.getTags().add(newTag); + } + } + } recipeRepository.save(existingRecipe); return convertToDto(existingRecipe); }