diff --git a/.gitignore b/.gitignore index 7e085c9..c6e934a 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ build/ !gradle/wrapper/gradle-wrapper.jar !**/src/main/**/build/ !**/src/test/**/build/ -!**/src/main/generated/ +/src/main/generated/ ### STS ### .apt_generated diff --git a/src/main/java/com/sickgyun/server/like/domain/Like.java b/src/main/java/com/sickgyun/server/like/domain/Like.java new file mode 100644 index 0000000..a7b3695 --- /dev/null +++ b/src/main/java/com/sickgyun/server/like/domain/Like.java @@ -0,0 +1,42 @@ +package com.sickgyun.server.like.domain; + +import com.sickgyun.server.qna.QnA; +import com.sickgyun.server.user.domain.User; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import lombok.AccessLevel; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(name = "like_tbl") +public class Like { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "like_id") + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "user_id") + private User user; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "qna_id") + private QnA qnA; + + public Like(User user, QnA qnA) { + this.user = user; + this.qnA = qnA; + } +} diff --git a/src/main/java/com/sickgyun/server/like/domain/repository/LikeRepository.java b/src/main/java/com/sickgyun/server/like/domain/repository/LikeRepository.java new file mode 100644 index 0000000..bac0f23 --- /dev/null +++ b/src/main/java/com/sickgyun/server/like/domain/repository/LikeRepository.java @@ -0,0 +1,23 @@ +package com.sickgyun.server.like.domain.repository; + +import java.util.Optional; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.sickgyun.server.like.domain.Like; +import com.sickgyun.server.like.exception.LikeNotFoundException; +import com.sickgyun.server.qna.QnA; +import com.sickgyun.server.user.domain.User; + +public interface LikeRepository extends JpaRepository { + boolean existsByQnAAndUser(QnA qnA, User user); + + Optional findByQnAAndUser(QnA qnA, User user); + + void deleteByQnA(QnA qnA); + + default Like getLike(QnA qnA, User user) { + return findByQnAAndUser(qnA, user) + .orElseThrow(LikeNotFoundException::new); + } +} diff --git a/src/main/java/com/sickgyun/server/like/exception/AlreadyLikeException.java b/src/main/java/com/sickgyun/server/like/exception/AlreadyLikeException.java new file mode 100644 index 0000000..f346d26 --- /dev/null +++ b/src/main/java/com/sickgyun/server/like/exception/AlreadyLikeException.java @@ -0,0 +1,12 @@ +package com.sickgyun.server.like.exception; + +import org.springframework.http.HttpStatus; + +import com.sickgyun.server.common.exception.SickgyunException; + +public class AlreadyLikeException extends SickgyunException { + + public AlreadyLikeException() { + super(HttpStatus.BAD_REQUEST, "이미 좋아요한 QnA입니다."); + } +} diff --git a/src/main/java/com/sickgyun/server/like/exception/LikeNotFoundException.java b/src/main/java/com/sickgyun/server/like/exception/LikeNotFoundException.java new file mode 100644 index 0000000..64f9236 --- /dev/null +++ b/src/main/java/com/sickgyun/server/like/exception/LikeNotFoundException.java @@ -0,0 +1,12 @@ +package com.sickgyun.server.like.exception; + +import org.springframework.http.HttpStatus; + +import com.sickgyun.server.common.exception.SickgyunException; + +public class LikeNotFoundException extends SickgyunException { + + public LikeNotFoundException() { + super(HttpStatus.NOT_FOUND, "좋아요를 찾을 수 없습니다."); + } +} diff --git a/src/main/java/com/sickgyun/server/like/presentation/LikeController.java b/src/main/java/com/sickgyun/server/like/presentation/LikeController.java new file mode 100644 index 0000000..9798e10 --- /dev/null +++ b/src/main/java/com/sickgyun/server/like/presentation/LikeController.java @@ -0,0 +1,47 @@ +package com.sickgyun.server.like.presentation; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +import com.sickgyun.server.like.service.CommandLikeService; +import com.sickgyun.server.like.service.QueryLikeService; +import com.sickgyun.server.user.domain.User; +import com.sickgyun.server.user.service.UserTempService; + +import lombok.RequiredArgsConstructor; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/likes") +public class LikeController { + + private final CommandLikeService commandLikeService; + private final QueryLikeService queryLikeService; + private final UserTempService userTempService; + + @ResponseStatus(HttpStatus.CREATED) + @PostMapping("/{qna-id}") + public void createLike(@PathVariable(name = "qna-id") Long qnAId) { + User user = userTempService.getUserId1(); + commandLikeService.create(qnAId, user); + } + + @ResponseStatus(HttpStatus.NO_CONTENT) + @DeleteMapping("/{qna-id}") + public void deleteLike(@PathVariable(name = "qna-id") Long qnAId) { + User user = userTempService.getUserId1(); + commandLikeService.delete(qnAId, user); + } + + @GetMapping("/{qna-id}") + public boolean checkLiked(@PathVariable(name = "qna-id") Long qnAId) { + User user = userTempService.getUserId1(); + return queryLikeService.checkLike(qnAId, user); + } +} diff --git a/src/main/java/com/sickgyun/server/like/service/CommandLikeService.java b/src/main/java/com/sickgyun/server/like/service/CommandLikeService.java new file mode 100644 index 0000000..eb09b8c --- /dev/null +++ b/src/main/java/com/sickgyun/server/like/service/CommandLikeService.java @@ -0,0 +1,39 @@ +package com.sickgyun.server.like.service; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.sickgyun.server.like.domain.Like; +import com.sickgyun.server.like.service.implememtation.LikeCreator; +import com.sickgyun.server.like.service.implememtation.LikeDeleter; +import com.sickgyun.server.like.service.implememtation.LikeReader; +import com.sickgyun.server.like.service.implememtation.LikeValidator; +import com.sickgyun.server.qna.QnA; +import com.sickgyun.server.qna.service.implementation.QnAReader; +import com.sickgyun.server.user.domain.User; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +@Transactional +public class CommandLikeService { + + private final LikeCreator likeCreator; + private final LikeReader likeReader; + private final LikeDeleter likeDeleter; + private final LikeValidator likeValidator; + private final QnAReader qnAReader; + + public void create(Long qnAId, User user) { + QnA qnA = qnAReader.read(qnAId); + likeValidator.shouldNotExistLike(qnA, user); + likeCreator.create(new Like(user, qnA)); + } + + public void delete(Long qnAId, User user) { + QnA qnA = qnAReader.read(qnAId); + Like like = likeReader.read(qnA, user); + likeDeleter.delete(like); + } +} diff --git a/src/main/java/com/sickgyun/server/like/service/QueryLikeService.java b/src/main/java/com/sickgyun/server/like/service/QueryLikeService.java new file mode 100644 index 0000000..7f565e7 --- /dev/null +++ b/src/main/java/com/sickgyun/server/like/service/QueryLikeService.java @@ -0,0 +1,25 @@ +package com.sickgyun.server.like.service; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.sickgyun.server.like.service.implememtation.LikeValidator; +import com.sickgyun.server.qna.QnA; +import com.sickgyun.server.qna.service.implementation.QnAReader; +import com.sickgyun.server.user.domain.User; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class QueryLikeService { + + private final QnAReader qnAReader; + private final LikeValidator likeValidator; + + public boolean checkLike(Long qnAId, User user) { + QnA qnA = qnAReader.read(qnAId); + return likeValidator.checkLiked(qnA, user); + } +} diff --git a/src/main/java/com/sickgyun/server/like/service/implememtation/LikeCreator.java b/src/main/java/com/sickgyun/server/like/service/implememtation/LikeCreator.java new file mode 100644 index 0000000..3dba449 --- /dev/null +++ b/src/main/java/com/sickgyun/server/like/service/implememtation/LikeCreator.java @@ -0,0 +1,19 @@ +package com.sickgyun.server.like.service.implememtation; + +import org.springframework.stereotype.Service; + +import com.sickgyun.server.like.domain.Like; +import com.sickgyun.server.like.domain.repository.LikeRepository; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class LikeCreator { + + private final LikeRepository likeRepository; + + public void create(Like like) { + likeRepository.save(like); + } +} diff --git a/src/main/java/com/sickgyun/server/like/service/implememtation/LikeDeleter.java b/src/main/java/com/sickgyun/server/like/service/implememtation/LikeDeleter.java new file mode 100644 index 0000000..e224b72 --- /dev/null +++ b/src/main/java/com/sickgyun/server/like/service/implememtation/LikeDeleter.java @@ -0,0 +1,24 @@ +package com.sickgyun.server.like.service.implememtation; + +import org.springframework.stereotype.Service; + +import com.sickgyun.server.like.domain.Like; +import com.sickgyun.server.like.domain.repository.LikeRepository; +import com.sickgyun.server.qna.QnA; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class LikeDeleter { + + private final LikeRepository likeRepository; + + public void delete(Like like) { + likeRepository.delete(like); + } + + public void deleteByQnA(QnA qnA) { + likeRepository.deleteByQnA(qnA); + } +} diff --git a/src/main/java/com/sickgyun/server/like/service/implememtation/LikeReader.java b/src/main/java/com/sickgyun/server/like/service/implememtation/LikeReader.java new file mode 100644 index 0000000..1d1f95c --- /dev/null +++ b/src/main/java/com/sickgyun/server/like/service/implememtation/LikeReader.java @@ -0,0 +1,21 @@ +package com.sickgyun.server.like.service.implememtation; + +import org.springframework.stereotype.Service; + +import com.sickgyun.server.like.domain.Like; +import com.sickgyun.server.like.domain.repository.LikeRepository; +import com.sickgyun.server.qna.QnA; +import com.sickgyun.server.user.domain.User; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class LikeReader { + + private final LikeRepository likeRepository; + + public Like read(QnA qnA, User user) { + return likeRepository.getLike(qnA, user); + } +} diff --git a/src/main/java/com/sickgyun/server/like/service/implememtation/LikeValidator.java b/src/main/java/com/sickgyun/server/like/service/implememtation/LikeValidator.java new file mode 100644 index 0000000..daa429c --- /dev/null +++ b/src/main/java/com/sickgyun/server/like/service/implememtation/LikeValidator.java @@ -0,0 +1,29 @@ +package com.sickgyun.server.like.service.implememtation; + +import org.springframework.stereotype.Service; + +import com.sickgyun.server.like.domain.repository.LikeRepository; +import com.sickgyun.server.like.exception.AlreadyLikeException; +import com.sickgyun.server.qna.QnA; +import com.sickgyun.server.user.domain.User; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class LikeValidator { + + private final LikeRepository likeRepository; + + public void shouldNotExistLike(QnA qnA, User user) { + boolean isExist = likeRepository.existsByQnAAndUser(qnA, user); + + if (isExist) { + throw new AlreadyLikeException(); + } + } + + public boolean checkLiked(QnA qnA, User user) { + return likeRepository.existsByQnAAndUser(qnA, user); + } +} diff --git a/src/main/java/com/sickgyun/server/qna/service/CommandQnAService.java b/src/main/java/com/sickgyun/server/qna/service/CommandQnAService.java index 32069f1..c5aa636 100644 --- a/src/main/java/com/sickgyun/server/qna/service/CommandQnAService.java +++ b/src/main/java/com/sickgyun/server/qna/service/CommandQnAService.java @@ -3,8 +3,8 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; - import com.sickgyun.server.comment.service.implementation.CommentDeleter; +import com.sickgyun.server.like.service.implememtation.LikeDeleter; import com.sickgyun.server.qna.QnA; import com.sickgyun.server.qna.service.implementation.QnACreator; import com.sickgyun.server.qna.service.implementation.QnADeleter; @@ -23,6 +23,7 @@ public class CommandQnAService { private final QnAReader qnAReader; private final QnADeleter qnADeleter; private final CommentDeleter commentDeleter; + private final LikeDeleter likeDeleter; public void createQnA(QnA qnA) { qnACreator.create(qnA); @@ -37,5 +38,6 @@ public void deleteQnA(Long qnAId) { QnA qnA = qnAReader.read(qnAId); qnADeleter.delete(qnA); commentDeleter.deleteByQnA(qnA); + likeDeleter.deleteByQnA(qnA); } }