Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,12 @@ public ApiResponse<PageResponseDto<ProductRegisterHistoryDto>> getRegisterHistor
return ApiResponse.onSuccess(productService.getRegisterHistory(user, pageable));
}

@Operation(summary = "제품 좋아요 추가/취소", description = "좋아요를 누르면 추가, 다시 누르면 취소됩니다.")
@PostMapping("/{productId}/like")
public ApiResponse<ProductLikeResponseDTO> addOrUpdateLike(
@CurrentUser User user,
@Parameter(description = "제품 ID") @PathVariable Long productId
) {
return ApiResponse.onSuccess(productService.addOrUpdateLike(user.getId(), productId));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.DecodEat.domain.products.dto.request.ProductRegisterRequestDto;
import com.DecodEat.domain.products.dto.response.*;
import com.DecodEat.domain.products.entity.Product;
import com.DecodEat.domain.products.entity.ProductInfoImage;
import com.DecodEat.domain.products.entity.ProductNutrition;
import com.DecodEat.domain.products.entity.RawMaterial.RawMaterialCategory;
import org.springframework.data.domain.Slice;
Expand Down Expand Up @@ -121,4 +122,13 @@ public static ProductResponseDTO.ProductListResultDTO toProductListResultDTO(Sli
.nextCursorId(nextCursorId)
.build();
}

public static ProductLikeResponseDTO toProductLikeDTO(Long productId, boolean isLiked) {

return ProductLikeResponseDTO.builder()
.productId(productId)
.isLiked(isLiked)
.build();

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.DecodEat.domain.products.dto.response;

import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Schema(description = "제품 좋아요 응답 정보")
public class ProductLikeResponseDTO {

@Schema(description = "제품 ID", example = "1")
private Long productId;

@Schema(description = "좋아요 여부", example = "true")
private boolean isLiked;

}
34 changes: 34 additions & 0 deletions src/main/java/com/DecodEat/domain/products/entity/ProductLike.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.DecodEat.domain.products.entity;


import com.DecodEat.domain.users.entity.User;
import com.DecodEat.global.common.BaseEntity;
import jakarta.persistence.*;
import lombok.*;

@Entity
@Getter
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Table(
name = "product_like",
uniqueConstraints = {
@UniqueConstraint(columnNames = {"user_id", "product_id"})
}
)// 한 유저는 하나의 제품에 대해 한번의 좋아요만 하도록 유니크 제약조건 설정
public class ProductLike extends BaseEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", nullable = false)
private User user;

@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "product_id", nullable = false)
private Product product;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.DecodEat.domain.products.repository;

import com.DecodEat.domain.products.entity.Product;
import com.DecodEat.domain.products.entity.ProductLike;
import com.DecodEat.domain.users.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;

public interface ProductLikeRepository extends JpaRepository<ProductLike, Long> {

Optional<ProductLike> findByUserAndProduct(User user, Product product);

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,13 @@
import com.DecodEat.domain.products.dto.request.AnalysisRequestDto;
import com.DecodEat.domain.products.dto.request.ProductRegisterRequestDto;
import com.DecodEat.domain.products.dto.response.*;
import com.DecodEat.domain.products.entity.DecodeStatus;
import com.DecodEat.domain.products.entity.Product;
import com.DecodEat.domain.products.entity.ProductInfoImage;
import com.DecodEat.domain.products.entity.ProductNutrition;
import com.DecodEat.domain.products.entity.ProductRawMaterial;
import com.DecodEat.domain.products.entity.*;
import com.DecodEat.domain.products.entity.RawMaterial.RawMaterial;
import com.DecodEat.domain.products.entity.RawMaterial.RawMaterialCategory;
import com.DecodEat.domain.products.repository.ProductImageRepository;
import com.DecodEat.domain.products.repository.ProductNutritionRepository;
import com.DecodEat.domain.products.repository.ProductRawMaterialRepository;
import com.DecodEat.domain.products.repository.ProductRepository;
import com.DecodEat.domain.products.repository.RawMaterialRepository;
import com.DecodEat.domain.products.repository.ProductSpecification;
import com.DecodEat.domain.products.repository.*;
import com.DecodEat.domain.users.entity.Behavior;
import com.DecodEat.domain.users.entity.User;
import com.DecodEat.domain.users.repository.UserRepository;
import com.DecodEat.domain.users.service.UserBehaviorService;
import com.DecodEat.global.aws.s3.AmazonS3Manager;
import com.DecodEat.global.dto.PageResponseDto;
Expand All @@ -37,6 +29,7 @@
import javax.swing.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;

Expand All @@ -55,9 +48,9 @@ public class ProductService {
private final AmazonS3Manager amazonS3Manager;
private final PythonAnalysisClient pythonAnalysisClient;
private final UserBehaviorService userBehaviorService;


private static final int PAGE_SIZE = 12;
private final UserRepository userRepository;
private final ProductLikeRepository productLikeRepository;

public ProductDetailDto getDetail(Long id, User user) {
Product product = productRepository.findById(id).orElseThrow(() -> new GeneralException(PRODUCT_NOT_EXISTED));
Expand Down Expand Up @@ -325,4 +318,36 @@ private Double parseDouble(String value) {
return null;
}
}

@Transactional
public ProductLikeResponseDTO addOrUpdateLike(Long userId, Long productId) {

// 1. 유저 확인
User user = userRepository.findById(userId)
.orElseThrow(() -> new GeneralException(USER_NOT_EXISTED));

// 2. 제품 확인
Product product = productRepository.findById(productId)
.orElseThrow(() -> new GeneralException(PRODUCT_NOT_EXISTED));

// 3. 기존 좋아요 여부 확인
Optional<ProductLike> existingLike = productLikeRepository.findByUserAndProduct(user, product);

boolean isLiked;

if (existingLike.isPresent()) {
// 이미 눌렀으면 → 좋아요 취소
productLikeRepository.delete(existingLike.get());
isLiked = false;
} else {
// 처음 누르면 → 좋아요 추가
ProductLike productLike = ProductLike.builder()
.user(user)
.product(product)
.build();
productLikeRepository.save(productLike);
isLiked = true;
}
return ProductConverter.toProductLikeDTO(productId, isLiked);
}
}
Loading