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

[#63] 좋아요 생성/취소 기능 및 해당 게시물에 대한 좋아요 개수 기능 추가 #87

Merged
merged 10 commits into from
Jan 27, 2023
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.prgrms.prolog.domain.like.api;

import java.net.URI;

import javax.validation.Valid;

import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.util.UriComponentsBuilder;

import com.prgrms.prolog.domain.like.dto.LikeDto;
import com.prgrms.prolog.domain.like.dto.LikeDto.likeRequest;
import com.prgrms.prolog.domain.like.service.LikeServiceImpl;
import com.prgrms.prolog.global.jwt.JwtAuthentication;

import lombok.RequiredArgsConstructor;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/like")
public class LikeController {

private final LikeServiceImpl likeService;

@PostMapping(value = "/{postId}")
public ResponseEntity<Long> insert(
@PathVariable Long postId,
@AuthenticationPrincipal JwtAuthentication user
) {
LikeDto.likeRequest request = new likeRequest(user.id(), postId);
Long likeId = likeService.save(request);
URI location = UriComponentsBuilder.fromUriString("/api/v1/like/" + likeId).build().toUri();
return ResponseEntity.created(location).build();
}

@DeleteMapping
public ResponseEntity<Void> delete(@RequestBody @Valid likeRequest likeRequest) {
likeService.cancel(likeRequest);
return ResponseEntity.noContent().build();
}
}
10 changes: 10 additions & 0 deletions src/main/java/com/prgrms/prolog/domain/like/dto/LikeDto.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.prgrms.prolog.domain.like.dto;

import javax.validation.constraints.NotNull;

public class LikeDto {

public record likeRequest(@NotNull Long userId,
@NotNull Long postId) {
}
}
44 changes: 44 additions & 0 deletions src/main/java/com/prgrms/prolog/domain/like/model/Like.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.prgrms.prolog.domain.like.model;

import static javax.persistence.FetchType.*;
import static javax.persistence.GenerationType.*;
import static lombok.AccessLevel.*;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

import com.prgrms.prolog.domain.post.model.Post;
import com.prgrms.prolog.domain.user.model.User;

import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Table(name = "likes")
@Entity
@Getter
@NoArgsConstructor(access = PROTECTED)
public class Like {

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

@ManyToOne(fetch = LAZY)
@JoinColumn(name = "user_id")
private User user;

@ManyToOne(fetch = LAZY)
@JoinColumn(name = "post_id")
private Post post;

@Builder
public Like(User user, Post post) {
this.user = user;
this.post = post;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.prgrms.prolog.domain.like.repository;

import java.util.Optional;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import com.prgrms.prolog.domain.like.model.Like;
import com.prgrms.prolog.domain.post.model.Post;
import com.prgrms.prolog.domain.user.model.User;

@Repository
public interface LikeRepository extends JpaRepository<Like, Long> {
Optional<Like> findByUserAndPost(User user, Post post);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.prgrms.prolog.domain.like.service;

import com.prgrms.prolog.domain.like.dto.LikeDto;

public interface LikeService {
Long save(LikeDto.likeRequest likeRequest);

void cancel(LikeDto.likeRequest likeRequest);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package com.prgrms.prolog.domain.like.service;

import javax.persistence.EntityNotFoundException;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.prgrms.prolog.domain.like.dto.LikeDto.likeRequest;
import com.prgrms.prolog.domain.like.model.Like;
import com.prgrms.prolog.domain.like.repository.LikeRepository;
import com.prgrms.prolog.domain.post.model.Post;
import com.prgrms.prolog.domain.post.repository.PostRepository;
import com.prgrms.prolog.domain.user.model.User;
import com.prgrms.prolog.domain.user.repository.UserRepository;

import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
@Transactional
@Service
public class LikeServiceImpl implements LikeService {

private final LikeRepository likeRepository;
private final UserRepository userRepository;
private final PostRepository postRepository;

@Override
public Long save(likeRequest likeRequest) {

User user = getFindUserBy(likeRequest.userId());
Post post = getFindPostBy(likeRequest.postId());

//TODO 이미 좋아요 되어있으면 에러 반환 -> 409 Conflict 오류로 변환
if (likeRepository.findByUserAndPost(user, post).isPresent()) {
throw new EntityNotFoundException("exception.like.alreadyExist");
}

Like like = likeRepository.save(saveLike(user, post));

postRepository.addLikeCount(post.getId());
return like.getId();
}

@Override
public void cancel(likeRequest likeRequest) {

User user = getFindUserBy(likeRequest.userId());
Post post = getFindPostBy(likeRequest.postId());

Like like = likeRepository.findByUserAndPost(user, post)
.orElseThrow(() -> new EntityNotFoundException("exception.like.notExist"));

likeRepository.delete(like);
postRepository.subLikeCount(post.getId());
}

private Like saveLike(User user, Post post) {
return Like.builder()
.user(user)
.post(post)
.build();
}

private User getFindUserBy(Long userId) {
return userRepository.findById(userId)
.orElseThrow(() -> new IllegalArgumentException("exception.user.notExists"));
}

private Post getFindPostBy(Long postId) {
return postRepository.findById(postId)
.orElseThrow(() -> new IllegalArgumentException("exception.post.notExists"));
}
}
10 changes: 6 additions & 4 deletions src/main/java/com/prgrms/prolog/domain/post/model/Post.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.util.Objects;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
Expand All @@ -17,6 +18,7 @@
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;

import org.hibernate.annotations.ColumnDefault;
import org.springframework.util.Assert;

import com.prgrms.prolog.domain.comment.model.Comment;
Expand All @@ -39,10 +41,6 @@ public class Post extends BaseEntity {
private static final int TITLE_MAX_SIZE = 50;
private static final int CONTENT_MAX_SIZE = 65535;

private static final String USER_INFO_NEED_MESSAGE = "게시글은 작성자 정보가 필요합니다.";
private static final String NOT_NULL_DATA_MESSAGE = "빈 값일 수 없는 데이터입니다.";
private static final String OVER_LENGTH_MESSAGE = "입력할 수 있는 범위를 초과하였습니다.";

@Id
@GeneratedValue(strategy = IDENTITY)
private Long id;
Expand All @@ -68,6 +66,10 @@ public class Post extends BaseEntity {
@JoinColumn(name = "series_id")
private Series series;

@ColumnDefault("0")
@Column(name = "like_count")
private int likeCount;

@Builder
public Post(String title, String content, boolean openStatus, User user, Series series) {
this.title = validateTitle(title);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.Optional;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;
Expand All @@ -27,4 +28,12 @@ public interface PostRepository extends JpaRepository<Post, Long> {
WHERE p.id = :postId
""")
Optional<Post> joinUserFindById(@Param(value = "postId") Long postId);

@Modifying
@Query("UPDATE Post p SET p.likeCount = p.likeCount + 1 WHERE p.id = :postId")
int addLikeCount(@Param(value = "postId") Long postId);

@Modifying
@Query("UPDATE Post p SET p.likeCount = p.likeCount - 1 WHERE p.id = :postId")
int subLikeCount(@Param(value = "postId") Long postId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@

public interface PostService {
Long save(PostRequest.CreateRequest request, Long userId);

PostResponse findById(Long postId);

Page<PostResponse> findAll(Pageable pageable);

PostResponse update(PostRequest.UpdateRequest update, Long userId, Long postId);

void delete(Long id);
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ public class PostServiceImpl implements PostService {
private final PostTagRepository postTagRepository;
private final UserTagRepository userTagRepository;


@Override
@Transactional
public Long save(CreateRequest request, Long userId) {
Expand All @@ -66,10 +65,10 @@ private void registerSeries(CreateRequest request, Post post, User owner) {
Series series = seriesRepository
.findByIdAndTitle(owner.getId(), seriesTitle)
.orElseGet(() -> seriesRepository.save(
Series.builder()
.title(seriesTitle)
.user(owner)
.build()
Series.builder()
.title(seriesTitle)
.user(owner)
.build()
)
);
post.setSeries(series);
Expand All @@ -78,7 +77,7 @@ private void registerSeries(CreateRequest request, Post post, User owner) {
@Override
public PostResponse findById(Long postId) {
Post post = postRepository.joinCommentFindById(postId)
.orElseThrow(() -> new IllegalArgumentException(POST_NOT_EXIST_MESSAGE));
.orElseThrow(() -> new IllegalArgumentException("exception.post.notExists"));
Set<PostTag> findPostTags = postTagRepository.joinRootTagFindByPostId(postId);
post.addPostTagsFrom(findPostTags);
return PostResponse.toPostResponse(post);
Expand All @@ -94,7 +93,7 @@ public Page<PostResponse> findAll(Pageable pageable) {
@Transactional
public PostResponse update(UpdateRequest update, Long userId, Long postId) {
Post findPost = postRepository.joinUserFindById(postId)
.orElseThrow(() -> new IllegalArgumentException(POST_NOT_EXIST_MESSAGE));
.orElseThrow(() -> new IllegalArgumentException("exception.post.notExists"));

if (!findPost.getUser().checkSameUserId(userId)) {
throw new IllegalArgumentException("exception.post.not.owner");
Expand Down
22 changes: 19 additions & 3 deletions src/main/java/com/prgrms/prolog/domain/user/dto/UserDto.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

public class UserDto {

@Builder
public record UserProfile(
Long id,
String email,
Expand All @@ -15,6 +14,17 @@ public record UserProfile(
String prologName,
String profileImgUrl
) {
@Builder
public UserProfile(Long id, String email, String nickName, String introduce, String prologName,
String profileImgUrl) {
this.id = id;
this.email = email;
this.nickName = nickName;
this.introduce = introduce;
this.prologName = prologName;
this.profileImgUrl = profileImgUrl;
}

public static UserProfile toUserProfile(User user) {
return new UserProfile(
user.getId(),
Expand All @@ -27,15 +37,21 @@ public static UserProfile toUserProfile(User user) {
}
}

@Builder
public record UserInfo(
String email,
String nickName,
String provider,
String oauthId,
String profileImgUrl
) {

@Builder
public UserInfo(String email, String nickName, String provider, String oauthId, String profileImgUrl) {
this.email = email;
this.nickName = nickName;
this.provider = provider;
this.oauthId = oauthId;
this.profileImgUrl = profileImgUrl;
}
}

public record IdResponse(Long id) {
Expand Down
12 changes: 12 additions & 0 deletions src/main/resources/db/migration/V2.2__add_like_table.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
DROP TABLE IF EXISTS likes;

CREATE TABLE likes
(
id bigint NOT NULL PRIMARY KEY AUTO_INCREMENT,
user_id bigint NOT NULL,
post_id bigint NOT NULL,
FOREIGN KEY fk_likes_user_id (user_id) REFERENCES users (id),
FOREIGN KEY fk_likes_post_id (post_id) REFERENCES post (id)
);

ALTER TABLE post ADD like_count INT DEFAULT 0;
Loading