From 4cce9018f885f41d6cf715bb9ae777016bb60472 Mon Sep 17 00:00:00 2001 From: durn Date: Wed, 8 Apr 2026 13:26:22 -0600 Subject: [PATCH] added searching for recipes and users plus some cleanup --- .../demo/controller/RecipeController.java | 23 ++++++++++++-- .../demo/controller/UserController.java | 9 ++++++ .../java/com/example/demo/entity/Recipe.java | 21 ++++++++++--- .../java/com/example/demo/entity/User.java | 5 +++ .../example/demo/repository/RecipeRepo.java | 5 +++ .../com/example/demo/repository/UserRepo.java | 3 ++ .../demo/service/Impl/RecipeServiceImpl.java | 31 +++++++++++++++++++ .../demo/service/Impl/UserServiceImpl.java | 17 ++++++++++ .../example/demo/service/RecipeService.java | 2 ++ .../com/example/demo/service/UserService.java | 2 ++ 10 files changed, 111 insertions(+), 7 deletions(-) diff --git a/demo/src/main/java/com/example/demo/controller/RecipeController.java b/demo/src/main/java/com/example/demo/controller/RecipeController.java index 6e36c50..769f988 100644 --- a/demo/src/main/java/com/example/demo/controller/RecipeController.java +++ b/demo/src/main/java/com/example/demo/controller/RecipeController.java @@ -11,13 +11,17 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import com.example.demo.dto.RecipeDto; +import com.example.demo.dto.UserDto; import com.example.demo.entity.Recipe; import com.example.demo.entity.User; import com.example.demo.service.RecipeService; +import jakarta.validation.Valid; + @RestController @RequestMapping("/api/recipes") public class RecipeController { @@ -31,7 +35,7 @@ public class RecipeController { // build create recipe REST API @PostMapping - public ResponseEntity saveUser(@RequestBody Recipe recipe) { + public ResponseEntity saveRecipe(@Valid @RequestBody Recipe recipe) { RecipeDto recipeDto = recipeService.convertToDto(recipe); return new ResponseEntity(recipeService.saveRecipe(recipeDto), HttpStatus.CREATED); } @@ -48,11 +52,24 @@ public class RecipeController { public ResponseEntity getRecipeById(@PathVariable("id") Integer recipeId) { return new ResponseEntity(recipeService.getRecipeById(recipeId), HttpStatus.OK); } + + // build get recipe by name REST API + @GetMapping("/search") + public ResponseEntity> searchRecipes( + @RequestParam(required = false) String name, // by not adding a name all recipes will appear basically + @RequestParam(required = false) List tags // since users can choose no tags this isnt required + ) { + + + + List recipes = recipeService.getRecipes(name, tags); + return new ResponseEntity<>(recipes, HttpStatus.OK); + } // build update recipe REST API // http://localhost:8080/api/recipes/(id number goes here) @PutMapping("{id}") - public ResponseEntity updateUser(@PathVariable("id") Integer recipeId, @RequestBody Recipe recipe) { + public ResponseEntity updateRecipe(@PathVariable("id") Integer recipeId, @RequestBody Recipe recipe) { RecipeDto recipeDto = recipeService.convertToDto(recipe); return new ResponseEntity(recipeService.updateRecipe(recipeDto, recipeId), HttpStatus.OK); } @@ -60,7 +77,7 @@ public class RecipeController { // build delete recipe REST API // http://localhost:8080/api/recipes/(id number goes here) @DeleteMapping("{id}") - public ResponseEntity deleteUser(@PathVariable("id") Integer recipeId) { + public ResponseEntity deleteRecipe(@PathVariable("id") Integer recipeId) { recipeService.deleteRecipe(recipeId); return new ResponseEntity("Recipe deleted succesfully!", HttpStatus.OK); } diff --git a/demo/src/main/java/com/example/demo/controller/UserController.java b/demo/src/main/java/com/example/demo/controller/UserController.java index 4097702..e9ccc58 100644 --- a/demo/src/main/java/com/example/demo/controller/UserController.java +++ b/demo/src/main/java/com/example/demo/controller/UserController.java @@ -11,6 +11,7 @@ import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import com.example.demo.dto.UserDto; @@ -40,6 +41,14 @@ public class UserController { public List getAllUsers() { return userService.getAllUsers(); } + + // build get user by name REST API + @GetMapping("/search") + public ResponseEntity> getUsersByName(@RequestParam String string) { + List users = userService.getUsersByName(string); + return new ResponseEntity<>(users, HttpStatus.OK); + } + // build get user by id REST API // http://localhost:8080/api/users/(id number goes here) 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 228a83d..616ed38 100644 --- a/demo/src/main/java/com/example/demo/entity/Recipe.java +++ b/demo/src/main/java/com/example/demo/entity/Recipe.java @@ -2,6 +2,9 @@ package com.example.demo.entity; import jakarta.persistence.*; import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; import lombok.EqualsAndHashCode; import java.math.BigDecimal; @@ -22,16 +25,25 @@ public class Recipe { @Column(columnDefinition = "TEXT") private String description; - + + @NotNull(message = "Please Provide a prep time amount in mintutes") + @Positive(message = "This value cannot be negative") private Integer prepTimeMinutes; + + @NotNull(message = "Please Provide a cook time amount in mintutes") + @Positive(message = "This value cannot be negative") private Integer cookTimeMinutes; + + @NotNull(message = "Please Provide a serving amount") + @Positive(message = "This value cannot be negative") private Integer servings; - + private String status; - + private LocalDateTime createdAt; private LocalDateTime updatedAt; - + + @NotNull(message = "Recipe must be associated with a user") @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "user_id", nullable = false) @EqualsAndHashCode.Include @@ -39,6 +51,7 @@ public class Recipe { // Recipe ingredients relationship @OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) + @NotEmpty(message = "At least one ingredient is required") private Set recipeIngredients = new HashSet<>(); // Recipe Steps relationship diff --git a/demo/src/main/java/com/example/demo/entity/User.java b/demo/src/main/java/com/example/demo/entity/User.java index aef2380..e72273f 100644 --- a/demo/src/main/java/com/example/demo/entity/User.java +++ b/demo/src/main/java/com/example/demo/entity/User.java @@ -3,6 +3,8 @@ package com.example.demo.entity; import jakarta.persistence.Entity; import jakarta.persistence.FetchType; import jakarta.persistence.Table; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.JoinTable; @@ -27,14 +29,17 @@ public class User implements UserDetails { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + @NotNull private Integer id; @Column(nullable = false, unique = true) + @NotBlank(message = "Username is required") private String username; private String role; @Column(unique = true) + @NotBlank(message = "Email is required") private String email; private String hashedpassword; diff --git a/demo/src/main/java/com/example/demo/repository/RecipeRepo.java b/demo/src/main/java/com/example/demo/repository/RecipeRepo.java index e04744b..36d44c1 100644 --- a/demo/src/main/java/com/example/demo/repository/RecipeRepo.java +++ b/demo/src/main/java/com/example/demo/repository/RecipeRepo.java @@ -1,8 +1,13 @@ package com.example.demo.repository; +import java.util.List; + import org.springframework.data.jpa.repository.JpaRepository; import com.example.demo.entity.Recipe; public interface RecipeRepo extends JpaRepository { + List findByTitleContainingIgnoreCase(String name); + List findByTitleContainingIgnoreCaseAndTags_NameIn(String title, List tags); + } \ No newline at end of file diff --git a/demo/src/main/java/com/example/demo/repository/UserRepo.java b/demo/src/main/java/com/example/demo/repository/UserRepo.java index b750838..669a759 100644 --- a/demo/src/main/java/com/example/demo/repository/UserRepo.java +++ b/demo/src/main/java/com/example/demo/repository/UserRepo.java @@ -4,10 +4,13 @@ import org.springframework.data.jpa.repository.JpaRepository; import com.example.demo.entity.User; +import java.util.List; import java.util.Optional; public interface UserRepo extends JpaRepository { Optional findByUsername(String username); + List findByUsernameContainingIgnoreCase(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 fc86289..b665432 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 @@ -2,6 +2,7 @@ package com.example.demo.service.Impl; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; import org.springframework.stereotype.Service; @@ -318,4 +319,34 @@ public class RecipeServiceImpl implements RecipeService { recipeRepository.deleteById(Id); } + + @Override + @Transactional + public List getRecipes(String name, List tags) { + + List recipes; + + if(!name.isBlank()) { + recipes = recipeRepository.findByTitleContainingIgnoreCase(name); + } + + else { + recipes = recipeRepository.findAll(); + } + + if(!tags.isEmpty() && !recipes.isEmpty()) { + recipes = recipes.stream() + .filter(recipe -> recipe.getTags().stream().anyMatch(tag -> tags.contains(tag.getName()))) + .collect(Collectors.toList()); + } + + List recipeList = new ArrayList<>(); + + for (Recipe recipe : recipes) { + RecipeDto dto = convertToDto(recipe); + recipeList.add(dto); + } + + return recipeList; + } } \ No newline at end of file diff --git a/demo/src/main/java/com/example/demo/service/Impl/UserServiceImpl.java b/demo/src/main/java/com/example/demo/service/Impl/UserServiceImpl.java index 498f93e..2a2779f 100644 --- a/demo/src/main/java/com/example/demo/service/Impl/UserServiceImpl.java +++ b/demo/src/main/java/com/example/demo/service/Impl/UserServiceImpl.java @@ -108,4 +108,21 @@ public class UserServiceImpl implements UserService { } + @Override + public List getUsersByName(String name) { + List users = userRepository.findByUsernameContainingIgnoreCase(name); + + if (users.isEmpty()) { + throw new NotFoundException("User", "username containing", name); + } + + List userList = new ArrayList<>(); + + for (User user : users) { + UserDto dto = convertToDto(user); + userList.add(dto); + } + return userList; + } + } diff --git a/demo/src/main/java/com/example/demo/service/RecipeService.java b/demo/src/main/java/com/example/demo/service/RecipeService.java index b728cf8..1efcc5a 100644 --- a/demo/src/main/java/com/example/demo/service/RecipeService.java +++ b/demo/src/main/java/com/example/demo/service/RecipeService.java @@ -16,6 +16,8 @@ public interface RecipeService { List getAllRecipes(); RecipeDto getRecipeById(Integer recipeId); + + List getRecipes(String name, List tags); RecipeDto updateRecipe(RecipeDto recipedto, Integer Id); diff --git a/demo/src/main/java/com/example/demo/service/UserService.java b/demo/src/main/java/com/example/demo/service/UserService.java index 1eef88a..6038023 100644 --- a/demo/src/main/java/com/example/demo/service/UserService.java +++ b/demo/src/main/java/com/example/demo/service/UserService.java @@ -13,6 +13,8 @@ public interface UserService { List getAllUsers(); UserDto getUserById(Integer Id); + + List getUsersByName(String name); UserDto saveFavorite(Integer userId, Integer recipeId);