Skip to content

Commit

Permalink
(회원) 게시글 검색 기능 (#314)
Browse files Browse the repository at this point in the history
* refactor : (#290) (회원) 게시글 검색 기능 api 추가

* test : (#290) 테스트 코드 추가

* feat : (#290) swagger 추가

* style : (#290) 개행 추가

* refactor: (#289) swagger 예외 응답 어노테이션 추가

* refactor: (#289) 개행, assertAll사용, 클래스이름 대문자, //given 리펙터링

* test: (#289) 제목 + 내용에 둘 다 포함되어있는 키워드 검색 테스트 추가

* test: (#290) 테스트 코드 추가

* refactor: (#290) 충돌 해결

* refactor: (#290) 충돌 해결
  • Loading branch information
aiaiaiai1 authored Aug 12, 2023
1 parent a29a821 commit 80c95ab
Show file tree
Hide file tree
Showing 7 changed files with 326 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,25 @@ public ResponseEntity<Void> closePostEarly(
return ResponseEntity.ok().build();
}

@Operation(summary = "게시글 검색(회원)", description = "회원으로 키워드를 통해 게시글을 검색한다.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "게시글 검색 성공"),
@ApiResponse(responseCode = "400", description = "잘못된 쿼리 파라미터값 입력"),
})
@GetMapping("/search")
public ResponseEntity<List<PostResponse>> searchPostsWithKeyword(
@RequestParam final String keyword,
@RequestParam final int page,
@RequestParam final PostClosingType postClosingType,
@RequestParam final PostSortType postSortType,
@RequestParam(required = false, name = "category") final Long categoryId,
@Auth final Member member
) {
final List<PostResponse> responses =
postService.searchPostsWithKeyword(keyword, page, postClosingType, postSortType, categoryId, member);
return ResponseEntity.ok(responses);
}

@Operation(summary = "작성한 게시글 조회", description = "회원본인이 작성한 게시글 목록을 조회한다.")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "회원본인이 작성한 게시글 조회 성공")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,14 @@ List<Post> findAllByClosingTypeAndSortTypeAndCategoryId(
final Pageable pageable
);

List<Post> findAllWithKeyword(
final String keyword,
final PostClosingType postClosingType,
final PostSortType postSortType,
final Long categoryId,
final Pageable pageable
);

List<Post> findAllByWriterWithClosingTypeAndSortTypeAndCategoryId(
final Member writer,
final PostClosingType postClosingType,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,4 +94,32 @@ private OrderSpecifier orderBy(final PostSortType postSortType) {
}
}

@Override
public List<Post> findAllWithKeyword(
final String keyword,
final PostClosingType postClosingType,
final PostSortType postSortType,
final Long categoryId,
final Pageable pageable
) {
return jpaQueryFactory
.selectFrom(post)
.join(post.writer).fetchJoin()
.leftJoin(post.postCategories.postCategories, postCategory)
.where(
containsKeywordInTitleOrContent(keyword),
categoryIdEq(categoryId),
deadlineEq(postClosingType)
)
.orderBy(orderBy(postSortType))
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch();
}

private BooleanExpression containsKeywordInTitleOrContent(final String keyword) {
return post.postBody.title.contains(keyword)
.or(post.postBody.content.contains(keyword));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,24 @@ public List<PostResponse> getPostsByWriter(
.toList();
}

public List<PostResponse> searchPostsWithKeyword(
final String keyword,
final int page,
final PostClosingType postClosingType,
final PostSortType postSortType,
final Long categoryId,
final Member member
) {
final Pageable pageable = PageRequest.of(page, BASIC_PAGING_SIZE);
final List<Post> posts =
postRepository.findAllWithKeyword(keyword, postClosingType, postSortType, categoryId, pageable);

return posts.stream()
.map(post -> PostResponse.of(post, member))
.toList();
}


@Transactional
public void delete(final Long postId) {
final Post post = postRepository.findById(postId)
Expand Down Expand Up @@ -327,3 +345,4 @@ private <T, R> List<R> transformElements(final List<T> elements, final Function<
}

}

Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@
import com.votogether.domain.post.entity.Post;
import com.votogether.domain.post.entity.PostBody;
import com.votogether.domain.post.entity.PostClosingType;
import com.votogether.domain.post.entity.PostOption;
import com.votogether.domain.post.entity.PostSortType;
import com.votogether.domain.post.service.PostService;
import com.votogether.exception.GlobalExceptionHandler;
Expand Down Expand Up @@ -659,7 +658,6 @@ void postClosedEarly() throws Exception {
assertThat(response.statusCode()).isEqualTo(HttpStatus.OK.value());
}

@Test
@DisplayName("회원본인이 작성한 게시글 목록을 조회한다.")
void getPostsByWriter() throws JsonProcessingException {
// given
Expand Down Expand Up @@ -714,6 +712,53 @@ void getPostsByWriter() throws JsonProcessingException {
);
}

@Test
@DisplayName("키워드를 통해 게시글 목록을 조회한다.")
void searchPostsWithKeyword() throws JsonProcessingException {
// given
long postId = 1L;
Member member = MemberFixtures.FEMALE_20.get();

TokenPayload tokenPayload = new TokenPayload(1L, 1L, 1L);
given(tokenProcessor.resolveToken(anyString())).willReturn("token");
given(tokenProcessor.parseToken(anyString())).willReturn(tokenPayload);
given(memberService.findById(anyLong())).willReturn(member);

PostBody postBody = PostBody.builder()
.title("title")
.content("content")
.build();

Post post = Post.builder()
.writer(MALE_30.get())
.postBody(postBody)
.deadline(LocalDateTime.now().plusDays(3L).truncatedTo(ChronoUnit.MINUTES))
.build();

PostResponse postResponse = PostResponse.of(post, member);

given(postService.searchPostsWithKeyword(anyString(), anyInt(), any(), any(), anyLong(), any(Member.class)))
.willReturn(List.of(postResponse));

// when
List<PostResponse> result = RestAssuredMockMvc.given().log().all()
.headers(HttpHeaders.AUTHORIZATION, "Bearer token")
.param("keyword", "하이")
.param("page", 0)
.param("postClosingType", PostClosingType.PROGRESS)
.param("postSortType", PostSortType.LATEST)
.param("category", 1L)
.when().get("/posts/search")
.then().log().all()
.status(HttpStatus.OK)
.extract()
.as(new ParameterizedTypeReference<List<PostResponse>>() {
}.getType());

// then
assertThat(result.get(0)).usingRecursiveComparison().isEqualTo(postResponse);
}

@DisplayName("게시글을 삭제한다.")
void delete() {
// given
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -405,8 +405,10 @@ void findClosedPostsVotedByMember() {
Slice<Post> posts = postRepository.findClosedPostsVotedByMember(member, pageRequest);

// then
assertThat(posts).hasSize(2);
assertThat(posts.getContent().get(0)).usingRecursiveComparison().isEqualTo(closedPost1);
assertAll(
() -> assertThat(posts).hasSize(2),
() -> assertThat(posts.getContent().get(0)).usingRecursiveComparison().isEqualTo(closedPost1)
);
}

@Test
Expand Down Expand Up @@ -472,8 +474,10 @@ void findOpenPostsVotedByMember() {
Slice<Post> posts = postRepository.findOpenPostsVotedByMember(member, pageRequest);

// then
assertThat(posts).hasSize(2);
assertThat(posts.getContent().get(0)).usingRecursiveComparison().isEqualTo(openPost1);
assertAll(
() -> assertThat(posts).hasSize(2),
() -> assertThat(posts.getContent().get(0)).usingRecursiveComparison().isEqualTo(openPost1)
);
}

@Test
Expand Down Expand Up @@ -526,6 +530,127 @@ void findPostsVotedByMember() {

}

@Nested
@DisplayName("키워드 검색을 통해 게시글 목록을 조회한다.")
class FindingPostsByKeyword {

Category development;
Category love;

Post devClosedPost;
Post devOpenPost;
Post loveClosedPost;
Post loveOpenPost;

@BeforeEach
void setUp() {
development = categoryRepository.save(Category.builder().name("개발").build());
love = categoryRepository.save(Category.builder().name("연애").build());

devClosedPost = postTestPersister.builder()
.postBody(PostBody.builder().title("자바제목").content("자바내용").build())
.deadline(LocalDateTime.of(1000, 7, 12, 0, 0))
.save();
postCategoryRepository.save(PostCategory.builder().post(devClosedPost).category(development).build());

devOpenPost = postTestPersister.builder()
.postBody(PostBody.builder().title("자바제목1").content("자바내용1").build())
.deadline(LocalDateTime.of(3000, 7, 12, 0, 0))
.save();
postCategoryRepository.save(PostCategory.builder().post(devOpenPost).category(development).build());

loveClosedPost = postTestPersister.builder()
.postBody(PostBody.builder().title("커플제목").content("커플내용").build())
.deadline(LocalDateTime.of(1000, 7, 12, 0, 0))
.save();
postCategoryRepository.save(PostCategory.builder().post(loveClosedPost).category(love).build());

loveOpenPost = postTestPersister.builder()
.postBody(PostBody.builder().title("커플제목1").content("커플내용1").build())
.deadline(LocalDateTime.of(3000, 7, 12, 0, 0))
.save();
postCategoryRepository.save(PostCategory.builder().post(loveOpenPost).category(love).build());

}

@Test
@DisplayName("특정 카테고리에 속한 게시글 목록을 키워드를 통해 검색한다.")
void searchPostsWithCategory() {
// when
List<Post> posts = postRepository.findAllWithKeyword(
"자바",
PostClosingType.ALL,
PostSortType.LATEST,
development.getId(),
PageRequest.of(0, 10)
);

//then
assertAll(
() -> assertThat(posts).hasSize(2),
() -> assertThat(posts.get(0)).isEqualTo(devOpenPost),
() -> assertThat(posts.get(1)).isEqualTo(devClosedPost)
);
}

@Test
@DisplayName("게시글 목록을 키워드를 통해 검색한다.(제목)")
void searchPostsWithKeywordInTitle() {
// when
List<Post> posts = postRepository.findAllWithKeyword(
"제목1",
PostClosingType.ALL,
PostSortType.LATEST,
null,
PageRequest.of(0, 10)
);

//then
assertAll(
() -> assertThat(posts).hasSize(2),
() -> assertThat(posts.get(0)).isEqualTo(loveOpenPost),
() -> assertThat(posts.get(1)).isEqualTo(devOpenPost)
);
}

@Test
@DisplayName("게시글 목록을 키워드를 통해 검색한다.(내용)")
void searchPostsWithKeywordInContent() {
// when
List<Post> posts = postRepository.findAllWithKeyword(
"내용",
PostClosingType.ALL,
PostSortType.LATEST,
null,
PageRequest.of(0, 10)
);

//then
assertThat(posts).hasSize(4);
}

@Test
@DisplayName("게시글 목록을 키워드를 통해 검색한다.(제목 + 내용)")
void searchPostsWithKeywordInTitleAndContent() {
// when
List<Post> posts = postRepository.findAllWithKeyword(
"1",
PostClosingType.ALL,
PostSortType.LATEST,
null,
PageRequest.of(0, 10)
);

//then
assertAll(
() -> assertThat(posts).hasSize(2),
() -> assertThat(posts.get(0)).isEqualTo(loveOpenPost),
() -> assertThat(posts.get(1)).isEqualTo(devOpenPost)
);
}

}

@Nested
@DisplayName("회원이 작성한 게시글 목록을 조회한다.")
class findPostsByWriter {
Expand Down
Loading

0 comments on commit 80c95ab

Please sign in to comment.