Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(like) : 좋아요 기능 개발 #37

Merged
merged 7 commits into from
Jan 7, 2024
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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
42 changes: 42 additions & 0 deletions src/main/java/com/sickgyun/server/like/domain/Like.java
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -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<Like, Long> {
boolean existsByQnAAndUser(QnA qnA, User user);

Optional<Like> findByQnAAndUser(QnA qnA, User user);

void deleteByQnA(QnA qnA);

default Like getLike(QnA qnA, User user) {
return findByQnAAndUser(qnA, user)
.orElseThrow(LikeNotFoundException::new);
}
}
Original file line number Diff line number Diff line change
@@ -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입니다.");
}
}
Original file line number Diff line number Diff line change
@@ -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, "좋아요를 찾을 수 없습니다.");
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand All @@ -37,5 +38,6 @@ public void deleteQnA(Long qnAId) {
QnA qnA = qnAReader.read(qnAId);
qnADeleter.delete(qnA);
commentDeleter.deleteByQnA(qnA);
likeDeleter.deleteByQnA(qnA);
}
}