tag recipe relationship made

This commit is contained in:
durn
2026-03-03 21:44:04 -07:00
parent fcb00b32a7
commit d03cbaf9a3
8 changed files with 147 additions and 9 deletions
@@ -10,8 +10,7 @@ public class SecurityConfig {
@Bean @Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http http.csrf(csrf -> csrf.disable())
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(auth -> auth .authorizeHttpRequests(auth -> auth
.anyRequest().permitAll() .anyRequest().permitAll()
); );
@@ -23,4 +23,4 @@ public class ImageDto {
} }
} }
@@ -15,6 +15,7 @@ public class RecipeDto {
private List<RecipeIngredientDto> ingredients; private List<RecipeIngredientDto> ingredients;
private List<StepDto> steps; private List<StepDto> steps;
private List<ImageDto> images; private List<ImageDto> images;
private List<TagDto> tags;
@@ -24,7 +25,7 @@ public class RecipeDto {
} }
public RecipeDto(String title, String description, Integer prepTimeMinutes, Integer cookTimeMinutes, public RecipeDto(String title, String description, Integer prepTimeMinutes, Integer cookTimeMinutes,
Integer servings, UserDto userDto, String status, List<RecipeIngredientDto> ingredients, List<StepDto> steps, List<ImageDto> images) { Integer servings, UserDto userDto, String status, List<RecipeIngredientDto> ingredients, List<StepDto> steps, List<ImageDto> images, List<TagDto> tags) {
super(); super();
this.title = title; this.title = title;
this.description = description; this.description = description;
@@ -36,6 +37,7 @@ public class RecipeDto {
this.ingredients = ingredients; this.ingredients = ingredients;
this.steps = steps; this.steps = steps;
this.images = images; this.images = images;
this.tags = tags;
} }
// getters and setters // getters and setters
@@ -99,6 +101,15 @@ public class RecipeDto {
public void setImages(List<ImageDto> images) { public void setImages(List<ImageDto> images) {
this.images = images; this.images = images;
} }
public List<TagDto> getTags() {
return tags;
}
public void setTags(List<TagDto> tags) {
this.tags = tags;
}
public UserDto getUserDto() { public UserDto getUserDto() {
return userDto; return userDto;
@@ -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;
}
}
@@ -47,6 +47,13 @@ public class Recipe {
// Recipe Images relationship // Recipe Images relationship
@OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) @OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
private Set<Image> images = new HashSet<>(); private Set<Image> 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<Tag> tags = new HashSet<>();
// Default constructor // Default constructor
@@ -147,4 +154,14 @@ public class Recipe {
this.images = images; this.images = images;
} }
public Set<Tag> getTags() {
return tags;
}
public void setTags(Set<Tag> tags) {
this.tags = tags;
}
} }
@@ -1,5 +1,8 @@
package com.example.demo.entity; package com.example.demo.entity;
import java.util.HashSet;
import java.util.Set;
import jakarta.persistence.*; import jakarta.persistence.*;
@Entity @Entity
@@ -12,6 +15,10 @@ public class Tag {
@Column(nullable = false, unique = true) @Column(nullable = false, unique = true)
private String name; private String name;
// Recipe is the manager for this relationship
@ManyToMany(fetch = FetchType.LAZY, mappedBy = "tags")
private Set<Recipe> recipes = new HashSet<>();
// Required by JPA // Required by JPA
public Tag() {} public Tag() {}
@@ -36,4 +43,14 @@ public class Tag {
public void setName(String name) { public void setName(String name) {
this.name = name; this.name = name;
} }
public Set<Recipe> getRecipes() {
return recipes;
}
public void setRecipes(Set<Recipe> recipes) {
this.recipes = recipes;
}
} }
@@ -2,12 +2,11 @@ package com.example.demo.repository;
import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaRepository;
import com.example.demo.entity.Ingredient;
import com.example.demo.entity.Tag; import com.example.demo.entity.Tag;
import java.util.Optional; import java.util.Optional;
public interface TagRepo extends JpaRepository<Tag, Integer> { public interface TagRepo extends JpaRepository<Tag, Integer> {
Optional<Tag> findByName(String name);
} }
@@ -8,6 +8,7 @@ import org.springframework.stereotype.Service;
import com.example.demo.dto.RecipeDto; import com.example.demo.dto.RecipeDto;
import com.example.demo.dto.UserDto; import com.example.demo.dto.UserDto;
import com.example.demo.dto.StepDto; import com.example.demo.dto.StepDto;
import com.example.demo.dto.TagDto;
import com.example.demo.dto.ImageDto; import com.example.demo.dto.ImageDto;
import com.example.demo.dto.RecipeIngredientDto; import com.example.demo.dto.RecipeIngredientDto;
import com.example.demo.entity.Image; 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.Recipe;
import com.example.demo.entity.RecipeIngredient; import com.example.demo.entity.RecipeIngredient;
import com.example.demo.entity.Step; import com.example.demo.entity.Step;
import com.example.demo.entity.Tag;
import com.example.demo.entity.User; import com.example.demo.entity.User;
import com.example.demo.exception.NotFoundException; import com.example.demo.exception.NotFoundException;
import com.example.demo.repository.ImageRepo; 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.RecipeIngredientRepo;
import com.example.demo.repository.RecipeRepo; import com.example.demo.repository.RecipeRepo;
import com.example.demo.repository.StepRepo; import com.example.demo.repository.StepRepo;
import com.example.demo.repository.TagRepo;
import com.example.demo.repository.UserRepo; import com.example.demo.repository.UserRepo;
import com.example.demo.service.RecipeService; import com.example.demo.service.RecipeService;
@@ -37,8 +40,9 @@ private RecipeIngredientRepo recipeIngredientRepository;
private UserRepo userRepository; private UserRepo userRepository;
private StepRepo stepRepository; private StepRepo stepRepository;
private ImageRepo imageRepository; 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(); super();
this.recipeRepository = recipeRepository; this.recipeRepository = recipeRepository;
this.ingredientRepository = ingredientRepository; this.ingredientRepository = ingredientRepository;
@@ -46,6 +50,7 @@ private ImageRepo imageRepository;
this.userRepository = userRepository; this.userRepository = userRepository;
this.stepRepository = stepRepository; this.stepRepository = stepRepository;
this.imageRepository = imageRepository; this.imageRepository = imageRepository;
this.tagRepository = tagRepository;
} }
public RecipeDto convertToDto(Recipe recipe) { public RecipeDto convertToDto(Recipe recipe) {
@@ -71,6 +76,12 @@ private ImageRepo imageRepository;
)) ))
.toList(); .toList();
List<TagDto> tagDtos = recipe.getTags().stream()
.map(ri -> new TagDto(
ri.getName()
))
.toList();
UserDto userDto = new UserDto(recipe.getUser().getId()); UserDto userDto = new UserDto(recipe.getUser().getId());
return new RecipeDto( return new RecipeDto(
@@ -83,7 +94,8 @@ private ImageRepo imageRepository;
recipe.getStatus(), recipe.getStatus(),
ingredientDtos, ingredientDtos,
stepDtos, 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); Recipe saved = recipeRepository.save(recipe);
return convertToDto(saved); return convertToDto(saved);
@@ -187,6 +220,9 @@ private ImageRepo imageRepository;
List<ImageDto> updatedImages = recipeDto.getImages(); List<ImageDto> updatedImages = recipeDto.getImages();
List<Image> imagesToRemove = new ArrayList<>(); List<Image> imagesToRemove = new ArrayList<>();
List<TagDto> updatedTags = recipeDto.getTags();
List<Tag> tagsToRemove = new ArrayList<>();
for (RecipeIngredient ri : existingRecipe.getRecipeIngredients()) { 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); recipeRepository.save(existingRecipe);
return convertToDto(existingRecipe); return convertToDto(existingRecipe);
} }