#24 simple sns: 좋아요 api
This commit is contained in:
@@ -54,4 +54,11 @@ public class PostController {
|
||||
public Response<Page<PostResponse>> my(Pageable pageable, Authentication authentication) {
|
||||
return Response.success(postService.my(authentication.getName(), pageable).map(PostResponse::fromPost));
|
||||
}
|
||||
|
||||
@PostMapping("/{postId}/likes")
|
||||
public Response<Void> like(@PathVariable Integer postId, Authentication authentication) {
|
||||
postService.like(postId, authentication.getName());
|
||||
return Response.success();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,7 +14,8 @@ public enum ErrorCode {
|
||||
INVALID_TOKEN(HttpStatus.UNAUTHORIZED, "Token is invalid."),
|
||||
POST_NOT_FOUND(HttpStatus.NOT_FOUND, "Post not founded."),
|
||||
INVALID_PERMISSION(HttpStatus.UNAUTHORIZED, "Permission is invalid."),
|
||||
INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "Internal server error.")
|
||||
INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "Internal server error."),
|
||||
ALREADY_LIKED(HttpStatus.CONFLICT, "User already liked the post."),
|
||||
|
||||
;
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.example.sns.model.entity;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.hibernate.annotations.SQLDelete;
|
||||
import org.hibernate.annotations.Where;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.sql.Timestamp;
|
||||
import java.time.Instant;
|
||||
|
||||
@Entity
|
||||
@Table(name = "likes")
|
||||
@Getter
|
||||
@Setter
|
||||
@SQLDelete(sql = "UPDATE likes SET deleted_at = NOW() where id=?")
|
||||
@Where(clause = "deleted_at IS NULL")
|
||||
public class LikeEntity {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Integer id;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "user_id")
|
||||
private UserEntity user;
|
||||
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "post_id")
|
||||
private PostEntity post;
|
||||
|
||||
private Timestamp registeredAt;
|
||||
private Timestamp updatedAt;
|
||||
|
||||
@Column(name = "deleted_at")
|
||||
private Timestamp deletedAt;
|
||||
|
||||
@PrePersist
|
||||
void registeredAt() {
|
||||
this.registeredAt = Timestamp.from(Instant.now());
|
||||
}
|
||||
|
||||
@PreUpdate
|
||||
void updatedAt() {
|
||||
this.updatedAt = Timestamp.from(Instant.now());
|
||||
}
|
||||
|
||||
public static LikeEntity of(UserEntity userEntity, PostEntity postEntity) {
|
||||
LikeEntity entity = new LikeEntity();
|
||||
entity.setUser(userEntity);
|
||||
entity.setPost(postEntity);
|
||||
return entity;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.example.sns.repository;
|
||||
|
||||
import com.example.sns.model.entity.LikeEntity;
|
||||
import com.example.sns.model.entity.PostEntity;
|
||||
import com.example.sns.model.entity.UserEntity;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Repository
|
||||
public interface LikeEntityRepository extends JpaRepository<LikeEntity, Integer> {
|
||||
|
||||
Optional<LikeEntity> findByUserAndPost(UserEntity user, PostEntity post);
|
||||
}
|
||||
@@ -2,8 +2,10 @@ package com.example.sns.service;
|
||||
|
||||
import com.example.sns.exception.SnsApplicationException;
|
||||
import com.example.sns.model.Post;
|
||||
import com.example.sns.model.entity.LikeEntity;
|
||||
import com.example.sns.model.entity.PostEntity;
|
||||
import com.example.sns.model.entity.UserEntity;
|
||||
import com.example.sns.repository.LikeEntityRepository;
|
||||
import com.example.sns.repository.PostEntityRepository;
|
||||
import com.example.sns.repository.UserEntityRepository;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -20,6 +22,7 @@ public class PostService {
|
||||
|
||||
private final PostEntityRepository postEntityRepository;
|
||||
private final UserEntityRepository userEntityRepository;
|
||||
private final LikeEntityRepository likeEntityRepository;
|
||||
|
||||
@Transactional
|
||||
public void create(String title, String body, String username) {
|
||||
@@ -107,4 +110,35 @@ public class PostService {
|
||||
);
|
||||
return postEntityRepository.findAllByUser(userEntity, pageable).map(Post::fromEntity);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void like(Integer postId, String username) {
|
||||
PostEntity postEntity = postEntityRepository.findById(postId)
|
||||
.orElseThrow(
|
||||
() -> new SnsApplicationException(
|
||||
POST_NOT_FOUND,
|
||||
String.format("%s not founded", postId)
|
||||
)
|
||||
);
|
||||
|
||||
UserEntity userEntity = userEntityRepository.findByUsername(username)
|
||||
.orElseThrow(
|
||||
() -> new SnsApplicationException(
|
||||
USER_NOT_FOUND,
|
||||
String.format("%s not founded", username)
|
||||
)
|
||||
);
|
||||
|
||||
// check liked
|
||||
likeEntityRepository.findByUserAndPost(userEntity, postEntity)
|
||||
.ifPresent(it -> {
|
||||
throw new SnsApplicationException(
|
||||
ALREADY_LIKED,
|
||||
String.format("username %s already like post %d", username, postId)
|
||||
);
|
||||
});
|
||||
|
||||
// save like
|
||||
likeEntityRepository.save(LikeEntity.of(userEntity, postEntity));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,4 +226,36 @@ public class PostControllerTest {
|
||||
).andDo(print())
|
||||
.andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser
|
||||
void 좋아요기능() throws Exception {
|
||||
|
||||
mockMvc.perform(post("/api/v1/posts/1/likes")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
).andDo(print())
|
||||
.andExpect(status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithAnonymousUser
|
||||
void 좋아요버튼클릭시_로그인하지_않은경우() throws Exception {
|
||||
|
||||
mockMvc.perform(post("/api/v1/posts/1/likes")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
).andDo(print())
|
||||
.andExpect(status().isUnauthorized());
|
||||
}
|
||||
|
||||
@Test
|
||||
@WithMockUser
|
||||
void 좋아요버튼클릭시_게시글이_없는경우() throws Exception {
|
||||
|
||||
doThrow(new SnsApplicationException(ErrorCode.POST_NOT_FOUND)).when(postService).like(any(), any());
|
||||
|
||||
mockMvc.perform(post("/api/v1/posts/1/likes")
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
).andDo(print())
|
||||
.andExpect(status().isNotFound());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user