Skip to content

Commit

Permalink
Feat: 책을 좋아요 했는지 확인 기능 구현 (#149)
Browse files Browse the repository at this point in the history
* #148 - feat: isbn13을 이용해 책을 좋아요 했는지 확인한다

* #148 - chore: domain 패키지와 dto 패키지의 순환참조를 해결하기 위해 redis 패키지 분리

* #148 - test: isbn13으로 좋아요 여부 확인 테스트 코드 작성
  • Loading branch information
GGHDMS authored Feb 18, 2024
1 parent a82db13 commit a08cfd8
Show file tree
Hide file tree
Showing 26 changed files with 136 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,13 @@
import cotato.bookitlist.book.dto.response.BookListResponse;
import cotato.bookitlist.book.dto.response.BookResponse;
import cotato.bookitlist.book.service.BookService;
import cotato.bookitlist.config.security.jwt.AuthDetails;
import io.swagger.v3.oas.annotations.Parameter;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

Expand Down Expand Up @@ -82,13 +80,6 @@ public ResponseEntity<Void> registerBook(
return ResponseEntity.created(location).build();
}

@GetMapping("/likes")
public ResponseEntity<BookListResponse> getLikeBooks(
@AuthenticationPrincipal AuthDetails details,
Pageable pageable
) {
return ResponseEntity.ok(bookService.getLikeBooks(details.getId(), pageable));
}
}


Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package cotato.bookitlist.book.controller;

import cotato.bookitlist.book.annotation.IsValidIsbn;
import cotato.bookitlist.book.dto.request.BookIsbn13Request;
import cotato.bookitlist.book.dto.response.BookLikeResponse;
import cotato.bookitlist.book.dto.response.BookListResponse;
import cotato.bookitlist.book.service.BookLikeService;
import cotato.bookitlist.config.security.jwt.AuthDetails;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.*;
Expand Down Expand Up @@ -45,4 +49,20 @@ public ResponseEntity<Void> deleteLike(
return ResponseEntity.noContent().build();
}

@GetMapping("/all")
public ResponseEntity<BookListResponse> getLikeBooks(
@AuthenticationPrincipal AuthDetails details,
Pageable pageable
) {
return ResponseEntity.ok(bookLikeService.getLikeBooks(details.getId(), pageable));
}

@GetMapping
public ResponseEntity<BookLikeResponse> likedBook(
@IsValidIsbn @RequestParam String isbn13,
@AuthenticationPrincipal AuthDetails details
) {
return ResponseEntity.ok(BookLikeResponse.of(bookLikeService.likedBook(details.getId(), isbn13)));
}

}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package cotato.bookitlist.book.domain.entity;
package cotato.bookitlist.book.domain;

import cotato.bookitlist.common.domain.BaseEntity;
import jakarta.persistence.*;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package cotato.bookitlist.book.domain.entity;
package cotato.bookitlist.book.domain;

import cotato.bookitlist.member.domain.Member;
import jakarta.persistence.*;
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/cotato/bookitlist/book/dto/BookApiDto.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cotato.bookitlist.book.dto;

import cotato.bookitlist.book.domain.entity.Book;

import cotato.bookitlist.book.domain.Book;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/cotato/bookitlist/book/dto/BookDto.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cotato.bookitlist.book.dto;

import cotato.bookitlist.book.domain.entity.Book;

import cotato.bookitlist.book.domain.Book;

import java.time.LocalDate;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package cotato.bookitlist.book.dto.response;

public record BookLikeResponse(
boolean liked
) {

public static BookLikeResponse of(boolean liked) {
return new BookLikeResponse(liked);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package cotato.bookitlist.book.dto.response;

import cotato.bookitlist.book.domain.entity.Book;
import cotato.bookitlist.book.domain.Book;
import cotato.bookitlist.book.dto.BookDto;
import org.springframework.data.domain.Page;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package cotato.bookitlist.book.domain.redis;
package cotato.bookitlist.book.redis;

import cotato.bookitlist.book.dto.BookApiDto;
import jakarta.persistence.Id;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package cotato.bookitlist.book.repository;

import cotato.bookitlist.book.domain.redis.BookApiCache;
import cotato.bookitlist.book.redis.BookApiCache;
import org.springframework.data.repository.CrudRepository;

public interface BookApiCacheRepository extends CrudRepository<BookApiCache, String> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package cotato.bookitlist.book.repository;

import cotato.bookitlist.book.domain.entity.BookLike;
import cotato.bookitlist.book.domain.BookLike;
import org.springframework.data.jpa.repository.JpaRepository;

import java.util.Optional;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package cotato.bookitlist.book.repository;

import cotato.bookitlist.book.domain.entity.Book;
import cotato.bookitlist.book.domain.Book;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package cotato.bookitlist.book.service;

import cotato.bookitlist.book.domain.redis.BookApiCache;
import cotato.bookitlist.book.redis.BookApiCache;
import cotato.bookitlist.book.dto.BookApiDto;
import cotato.bookitlist.book.repository.BookApiCacheRepository;
import lombok.RequiredArgsConstructor;
Expand Down
14 changes: 12 additions & 2 deletions src/main/java/cotato/bookitlist/book/service/BookLikeService.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
package cotato.bookitlist.book.service;

import cotato.bookitlist.book.domain.entity.Book;
import cotato.bookitlist.book.domain.entity.BookLike;
import cotato.bookitlist.book.domain.Book;
import cotato.bookitlist.book.domain.BookLike;
import cotato.bookitlist.book.dto.response.BookListResponse;
import cotato.bookitlist.book.repository.BookLikeRepository;
import cotato.bookitlist.book.repository.BookRepository;
import cotato.bookitlist.member.domain.Member;
import cotato.bookitlist.member.repository.MemberRepository;
import jakarta.persistence.EntityNotFoundException;
import lombok.RequiredArgsConstructor;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand Down Expand Up @@ -48,4 +50,12 @@ public void deleteLike(String isbn13, Long memberId) {

bookLikeRepository.delete(bookLike);
}

public BookListResponse getLikeBooks(Long memberId, Pageable pageable) {
return bookService.getLikeBooks(memberId, pageable);
}

public boolean likedBook(Long memberId, String isbn13) {
return bookLikeRepository.existsByBook_Isbn13AndMemberId(isbn13, memberId);
}
}
4 changes: 2 additions & 2 deletions src/main/java/cotato/bookitlist/book/service/BookService.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package cotato.bookitlist.book.service;

import cotato.bookitlist.book.domain.entity.Book;
import cotato.bookitlist.book.domain.redis.BookApiCache;
import cotato.bookitlist.book.domain.Book;
import cotato.bookitlist.book.dto.BookApiDto;
import cotato.bookitlist.book.dto.BookDto;
import cotato.bookitlist.book.dto.response.BookApiListResponse;
import cotato.bookitlist.book.dto.response.BookListResponse;
import cotato.bookitlist.book.redis.BookApiCache;
import cotato.bookitlist.book.repository.BookRepository;
import jakarta.persistence.EntityNotFoundException;
import lombok.RequiredArgsConstructor;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeHttpRequests(auth -> auth
.requestMatchers(WHITE_LIST).permitAll()
.requestMatchers(HttpMethod.GET, "/posts/likes", "/posts/me", "/books/likes").authenticated()
.requestMatchers(HttpMethod.GET, "/posts/likes", "/posts/me", "/books/likes/**").authenticated()
.requestMatchers(HttpMethod.GET).permitAll()
.requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
.anyRequest().authenticated()
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/cotato/bookitlist/mark/domain/ReadBook.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package cotato.bookitlist.mark.domain;

import cotato.bookitlist.book.domain.entity.Book;
import cotato.bookitlist.book.domain.Book;
import cotato.bookitlist.member.domain.Member;
import jakarta.persistence.*;
import lombok.AccessLevel;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package cotato.bookitlist.post.domain.entity;

import cotato.bookitlist.book.domain.entity.Book;
import cotato.bookitlist.book.domain.Book;
import cotato.bookitlist.common.domain.BaseEntity;
import cotato.bookitlist.member.domain.Member;
import cotato.bookitlist.post.domain.PostStatus;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package cotato.bookitlist.post.service;

import cotato.bookitlist.book.domain.entity.Book;
import cotato.bookitlist.book.domain.Book;
import cotato.bookitlist.book.repository.BookRepository;
import cotato.bookitlist.book.service.BookService;
import cotato.bookitlist.member.domain.Member;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package cotato.bookitlist.review.domain.entity;

import cotato.bookitlist.book.domain.entity.Book;
import cotato.bookitlist.book.domain.Book;
import cotato.bookitlist.common.domain.BaseEntity;
import cotato.bookitlist.member.domain.Member;
import cotato.bookitlist.review.domain.ReviewStatus;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package cotato.bookitlist.review.service;

import cotato.bookitlist.book.domain.entity.Book;
import cotato.bookitlist.book.domain.Book;
import cotato.bookitlist.book.repository.BookRepository;
import cotato.bookitlist.book.service.BookService;
import cotato.bookitlist.member.domain.Member;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package cotato.bookitlist.book.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import cotato.bookitlist.annotation.WithCustomMockUser;
import cotato.bookitlist.book.dto.request.BookIsbn13Request;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
Expand Down Expand Up @@ -269,28 +268,4 @@ void givenNonExistedId_whenGettingBook_thenReturnErrorResponse() throws Exceptio
.andExpect(jsonPath("$.message").value("책을 찾을 수 없습니다."))
;
}

@Test
@WithCustomMockUser
@DisplayName("찜한 책 목록을 조회한다.")
void givenLoginMember_whenGettingLikePosts_thenReturnBookListResponse() throws Exception{
//given

//when & then
mockMvc.perform(get("/books/likes"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.totalResults").value(2))
;
}

@Test
@DisplayName("로그인 없이 찜한 책 목록을 조회하면 에러를 반환한다.")
void givenNonLoginMember_whenGettingLikePosts_thenReturnErrorResponse() throws Exception {
//given

//when & then
mockMvc.perform(get("/books/likes"))
.andExpect(status().isUnauthorized())
;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,10 @@
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.transaction.annotation.Transactional;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@Transactional
@SpringBootTest
Expand Down Expand Up @@ -117,5 +116,70 @@ void givenNonExistedBookLike_whenDeletingBookLike_thenReturnErrorResponse() thro
.andDo(print())
;
}

@Test
@WithCustomMockUser
@DisplayName("찜한 책 목록을 조회한다.")
void givenLoginMember_whenGettingLikePosts_thenReturnBookListResponse() throws Exception {
//given

//when & then
mockMvc.perform(get("/books/likes/all"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.totalResults").value(2))
;
}

@Test
@DisplayName("로그인 없이 찜한 책 목록을 조회하면 에러를 반환한다.")
void givenNonLoginMember_whenGettingLikePosts_thenReturnErrorResponse() throws Exception {
//given

//when & then
mockMvc.perform(get("/books/likes/all"))
.andExpect(status().isUnauthorized())
;
}

@Test
@WithCustomMockUser
@DisplayName("로그인한 유저가 책을 좋아요 했는지 확인한다.")
void givenLoginMember_whenGettingLiked_thenReturnBookLikeResponse() throws Exception {
//given
String isbn13 = "9788931514810";

//when & then
mockMvc.perform(get("/books/likes")
.param("isbn13", isbn13))
.andExpect(status().isOk())
.andDo(print())
;
}

@Test
@WithCustomMockUser
@DisplayName("로그인한 유저가 isbn13 없이 책을 좋아요를 확인하면 에러를 반환한다.")
void givenNonIsbn13_whenGettingLiked_thenReturnErrorResponse() throws Exception {
//given

//when & then
mockMvc.perform(get("/books/likes"))
.andExpect(status().isBadRequest())
.andDo(print())
;
}

@Test
@DisplayName("로그인안한 유저가 책을 좋아요 했는지 확인하면 에러를 반환한다.")
void givenMember_whenGettingLiked_thenReturnErrorResponse() throws Exception {
//given
String isbn13 = "9788931514810";

//when & then
mockMvc.perform(get("/books/likes"))
.andExpect(status().isUnauthorized())
.andDo(print())
;
}
}

Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package cotato.bookitlist.book.service;

import cotato.bookitlist.book.domain.entity.Book;
import cotato.bookitlist.book.domain.entity.BookLike;
import cotato.bookitlist.book.domain.Book;
import cotato.bookitlist.book.domain.BookLike;
import cotato.bookitlist.book.repository.BookLikeRepository;
import cotato.bookitlist.book.repository.BookRepository;
import cotato.bookitlist.member.domain.Member;
Expand Down
3 changes: 2 additions & 1 deletion src/test/java/cotato/bookitlist/fixture/BookFixture.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cotato.bookitlist.fixture;

import cotato.bookitlist.book.domain.entity.Book;

import cotato.bookitlist.book.domain.Book;

import java.time.LocalDate;

Expand Down
4 changes: 2 additions & 2 deletions src/test/java/cotato/bookitlist/fixture/BookLikeFixture.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package cotato.bookitlist.fixture;

import cotato.bookitlist.book.domain.entity.Book;
import cotato.bookitlist.book.domain.entity.BookLike;
import cotato.bookitlist.book.domain.Book;
import cotato.bookitlist.book.domain.BookLike;
import cotato.bookitlist.member.domain.Member;
import org.springframework.test.util.ReflectionTestUtils;

Expand Down

0 comments on commit a08cfd8

Please sign in to comment.