#24 simple sns: 좋아요 api

This commit is contained in:
haerong22
2022-11-22 02:12:34 +09:00
parent a8efd26a78
commit fc328f92b8
6 changed files with 144 additions and 1 deletions

View File

@@ -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();
}
}

View File

@@ -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."),
;

View File

@@ -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;
}
}

View File

@@ -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);
}

View File

@@ -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));
}
}

View File

@@ -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());
}
}