diff --git a/refrigerator/.idea/modules/refrigerator.main.iml b/refrigerator/.idea/modules/refrigerator.main.iml index 397c268..ac8e328 100644 --- a/refrigerator/.idea/modules/refrigerator.main.iml +++ b/refrigerator/.idea/modules/refrigerator.main.iml @@ -1,9 +1,6 @@ - - - @@ -20,4 +17,5 @@ - \ No newline at end of file + + diff --git a/refrigerator/src/main/java/moja/refrigerator/aggregate/recipe/RecipeLikeDislike.java b/refrigerator/src/main/java/moja/refrigerator/aggregate/recipe/RecipeLikeDislike.java new file mode 100644 index 0000000..8fe52a5 --- /dev/null +++ b/refrigerator/src/main/java/moja/refrigerator/aggregate/recipe/RecipeLikeDislike.java @@ -0,0 +1,27 @@ +package moja.refrigerator.aggregate.recipe; + +import jakarta.persistence.*; +import lombok.Data; +import moja.refrigerator.aggregate.user.User; + +@Entity +@Table(name = "tbl_recipe_like_dislike") +@Data +public class RecipeLikeDislike { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "like_dislike_pk") + private Long id; + + @ManyToOne + @JoinColumn(name = "recipe_pk") + private Recipe recipe; + + @ManyToOne + @JoinColumn(name = "user_pk") + private User user; + + @Column(name = "like_status") + private Boolean likeStatus; +} + diff --git a/refrigerator/src/main/java/moja/refrigerator/controller/recipe/RecipeController.java b/refrigerator/src/main/java/moja/refrigerator/controller/recipe/RecipeController.java index d332f82..03ecb0a 100644 --- a/refrigerator/src/main/java/moja/refrigerator/controller/recipe/RecipeController.java +++ b/refrigerator/src/main/java/moja/refrigerator/controller/recipe/RecipeController.java @@ -2,8 +2,10 @@ import moja.refrigerator.aggregate.recipe.Recipe; import moja.refrigerator.dto.recipe.request.RecipeCreateRequest; +import moja.refrigerator.dto.recipe.request.RecipeLikeRequest; import moja.refrigerator.dto.recipe.request.RecipeUpdateRequest; import moja.refrigerator.dto.recipe.response.RecipeDetailResponse; +import moja.refrigerator.dto.recipe.response.RecipeLikeResponse; import moja.refrigerator.dto.recipe.response.RecipeRecommendResponse; import moja.refrigerator.dto.recipe.response.RecipeResponse; import moja.refrigerator.service.recipe.RecipeService; @@ -69,4 +71,12 @@ public ResponseEntity getRandomRecipe() { return ResponseEntity.notFound().build(); } } + + @PostMapping("/reaction") + public ResponseEntity toggleLikeDislike( + @RequestBody RecipeLikeRequest request + ) { + return ResponseEntity.ok(recipeService.toggleLikeDislike(request)); + } + } diff --git a/refrigerator/src/main/java/moja/refrigerator/dto/recipe/request/RecipeLikeRequest.java b/refrigerator/src/main/java/moja/refrigerator/dto/recipe/request/RecipeLikeRequest.java new file mode 100644 index 0000000..4deff9c --- /dev/null +++ b/refrigerator/src/main/java/moja/refrigerator/dto/recipe/request/RecipeLikeRequest.java @@ -0,0 +1,10 @@ +package moja.refrigerator.dto.recipe.request; + +import lombok.Data; + +@Data +public class RecipeLikeRequest { + private Long recipePk; + private Long userPk; + private Boolean likeStatus; +} diff --git a/refrigerator/src/main/java/moja/refrigerator/dto/recipe/response/RecipeLikeResponse.java b/refrigerator/src/main/java/moja/refrigerator/dto/recipe/response/RecipeLikeResponse.java new file mode 100644 index 0000000..a104acf --- /dev/null +++ b/refrigerator/src/main/java/moja/refrigerator/dto/recipe/response/RecipeLikeResponse.java @@ -0,0 +1,12 @@ +package moja.refrigerator.dto.recipe.response; + +import lombok.AllArgsConstructor; +import lombok.Data; + +@Data +@AllArgsConstructor +public class RecipeLikeResponse { + private long likesCount; + private long dislikesCount; + private Boolean userReaction; +} diff --git a/refrigerator/src/main/java/moja/refrigerator/repository/recipe/RecipeLikeDislikeRepository.java b/refrigerator/src/main/java/moja/refrigerator/repository/recipe/RecipeLikeDislikeRepository.java new file mode 100644 index 0000000..7510915 --- /dev/null +++ b/refrigerator/src/main/java/moja/refrigerator/repository/recipe/RecipeLikeDislikeRepository.java @@ -0,0 +1,14 @@ +package moja.refrigerator.repository.recipe; + +import moja.refrigerator.aggregate.recipe.Recipe; +import moja.refrigerator.aggregate.recipe.RecipeLikeDislike; +import moja.refrigerator.aggregate.user.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; +import java.util.Optional; + +@Repository +public interface RecipeLikeDislikeRepository extends JpaRepository { + Optional findByRecipeAndUser(Recipe recipe, User user); + long countByRecipeAndLikeStatus(Recipe recipe, Boolean likeStatus); +} diff --git a/refrigerator/src/main/java/moja/refrigerator/service/recipe/RecipeService.java b/refrigerator/src/main/java/moja/refrigerator/service/recipe/RecipeService.java index cb89a94..81c69a5 100644 --- a/refrigerator/src/main/java/moja/refrigerator/service/recipe/RecipeService.java +++ b/refrigerator/src/main/java/moja/refrigerator/service/recipe/RecipeService.java @@ -2,8 +2,10 @@ import moja.refrigerator.aggregate.recipe.Recipe; import moja.refrigerator.dto.recipe.request.RecipeCreateRequest; +import moja.refrigerator.dto.recipe.request.RecipeLikeRequest; import moja.refrigerator.dto.recipe.request.RecipeUpdateRequest; import moja.refrigerator.dto.recipe.response.RecipeDetailResponse; +import moja.refrigerator.dto.recipe.response.RecipeLikeResponse; import moja.refrigerator.dto.recipe.response.RecipeRecommendResponse; import moja.refrigerator.dto.recipe.response.RecipeResponse; import moja.refrigerator.repository.recipe.RecipeRepository; @@ -25,4 +27,5 @@ void updateRecipe( ); List getRecommendedRecipes(Long userPk); RecipeRecommendResponse getRandomRecipe(); + RecipeLikeResponse toggleLikeDislike(RecipeLikeRequest request); } diff --git a/refrigerator/src/main/java/moja/refrigerator/service/recipe/RecipeServiceImpl.java b/refrigerator/src/main/java/moja/refrigerator/service/recipe/RecipeServiceImpl.java index e54afe6..42030fb 100644 --- a/refrigerator/src/main/java/moja/refrigerator/service/recipe/RecipeServiceImpl.java +++ b/refrigerator/src/main/java/moja/refrigerator/service/recipe/RecipeServiceImpl.java @@ -8,11 +8,9 @@ import moja.refrigerator.aggregate.user.User; import moja.refrigerator.dto.recipe.RecipeMatchResult; import moja.refrigerator.dto.recipe.request.RecipeCreateRequest; +import moja.refrigerator.dto.recipe.request.RecipeLikeRequest; import moja.refrigerator.dto.recipe.request.RecipeUpdateRequest; -import moja.refrigerator.dto.recipe.response.RecipeDetailResponse; -import moja.refrigerator.dto.recipe.response.RecipeIngredientInfo; -import moja.refrigerator.dto.recipe.response.RecipeRecommendResponse; -import moja.refrigerator.dto.recipe.response.RecipeResponse; +import moja.refrigerator.dto.recipe.response.*; import moja.refrigerator.repository.ingredient.IngredientMyRefrigeratorRepository; import moja.refrigerator.repository.recipe.*; import moja.refrigerator.repository.user.UserRepository; @@ -43,6 +41,7 @@ public class RecipeServiceImpl implements RecipeService { private final IngredientMyRefrigeratorRepository ingredientMyRefrigeratorRepository; private final RecipeIngredientRepository recipeIngredientRepository; private final ReplacableIngredientRepository replacableIngredientRepository; + private final RecipeLikeDislikeRepository recipeLikeDislikeRepository; @Value("${cloud.aws.s3.bucket}") private String bucket; @@ -58,7 +57,8 @@ public RecipeServiceImpl( AmazonS3Client amazonS3Client, IngredientMyRefrigeratorRepository ingredientMyRefrigeratorRepository, RecipeIngredientRepository recipeIngredientRepository, - ReplacableIngredientRepository replacableIngredientRepository + ReplacableIngredientRepository replacableIngredientRepository, + RecipeLikeDislikeRepository recipeLikeDislikeRepository ) { this.recipeRepository = recipeRepository; this.userRepository = userRepository; @@ -70,8 +70,8 @@ public RecipeServiceImpl( this.ingredientMyRefrigeratorRepository = ingredientMyRefrigeratorRepository; this.recipeIngredientRepository = recipeIngredientRepository; this.replacableIngredientRepository = replacableIngredientRepository; + this.recipeLikeDislikeRepository = recipeLikeDislikeRepository; } - private boolean isImageFile(String fileName) { String extension = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase(); return List.of("jpg", "jpeg", "png", "gif").contains(extension); @@ -348,4 +348,37 @@ public RecipeRecommendResponse getRandomRecipe() { return response; } + @Override + @Transactional + public RecipeLikeResponse toggleLikeDislike(RecipeLikeRequest request) { + Recipe recipe = recipeRepository.findById(request.getRecipePk()) + .orElseThrow(() -> new IllegalArgumentException("레시피를 찾을 수 없습니다.")); + + User user = userRepository.findById(request.getUserPk()) + .orElseThrow(() -> new IllegalArgumentException("사용자를 찾을 수 없습니다.")); + + Optional existing = + recipeLikeDislikeRepository.findByRecipeAndUser(recipe, user); + + if (existing.isPresent()) { + if (existing.get().getLikeStatus() == request.getLikeStatus()) { + recipeLikeDislikeRepository.delete(existing.get()); + } else { + existing.get().setLikeStatus(request.getLikeStatus()); + } + } else { + RecipeLikeDislike newReaction = new RecipeLikeDislike(); + newReaction.setRecipe(recipe); + newReaction.setUser(user); + newReaction.setLikeStatus(request.getLikeStatus()); + recipeLikeDislikeRepository.save(newReaction); + } + + // 현재 좋아요/싫어요 수 계산 + long likes = recipeLikeDislikeRepository.countByRecipeAndLikeStatus(recipe, true); + long dislikes = recipeLikeDislikeRepository.countByRecipeAndLikeStatus(recipe, false); + + return new RecipeLikeResponse(likes, dislikes, request.getLikeStatus()); + } + } \ No newline at end of file