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

Feature/#658 자신이 작성한 피드 목록 조회 #675

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions backend/emm-sale/src/documentTest/asciidoc/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,17 @@ include::{snippets}/find-all-feed/http-response.adoc[]
.HTTP response 설명
include::{snippets}/find-all-feed/response-fields.adoc[]

=== `GET`: 자신이 작성한 피드 목록 조회

.HTTP request
include::{snippets}/find-all-my-feed/http-request.adoc[]

.HTTP response
include::{snippets}/find-all-my-feed/http-response.adoc[]

.HTTP response 설명
include::{snippets}/find-all-my-feed/response-fields.adoc[]

=== `GET`: 피드 상세 조회

.HTTP request
Expand All @@ -737,15 +748,9 @@ Content-Type: multipart/form-data; boundary=6o2knFse3p53ty9dmcQvWAIx1zInP11uCfbm
Host: localhost:8080
```

.HTTP request 설명
include::{snippets}/post-feed/request-fields.adoc[]

.HTTP response
include::{snippets}/post-feed/http-response.adoc[]

.HTTP response 설명
include::{snippets}/post-feed/response-fields.adoc[]

=== `PUT`: 피드 업데이트

.HTTP request
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import java.util.List;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.restdocs.payload.JsonFieldType;
Expand Down Expand Up @@ -110,6 +111,41 @@ void findDetailFeedTest() throws Exception {
.andDo(document("find-detail-feed", responseFields));
}

@Test
@DisplayName("자신의 피드 목록을 성공적으로 반환하면 200 OK를 반환한다.")
void findAllMyFeedsTest() throws Exception {
//given
final ResponseFieldsSnippet responseFields = responseFields(
fieldWithPath("[].id").type(JsonFieldType.NUMBER).description("피드 id"),
fieldWithPath("[].title").type(JsonFieldType.STRING).description("피드 제목"),
fieldWithPath("[].content").type(JsonFieldType.STRING).description("피드 내용"),
fieldWithPath("[].images").type(JsonFieldType.ARRAY).description("피드 이미지 url 리스트"),
fieldWithPath("[].writerId").type(JsonFieldType.NUMBER).description("피드 작성자 id"),
fieldWithPath("[].commentCount").type(JsonFieldType.NUMBER).description("피드의 댓글 개수"),
fieldWithPath("[].createdAt").type(JsonFieldType.STRING).description("피드 생성 일시"),
fieldWithPath("[].updatedAt").type(JsonFieldType.STRING).description("피드 업데이트 일시")
);

final List<FeedSimpleResponse> feeds = List.of(
new FeedSimpleResponse(34L, "피드1 제목", "피드 내용", 23L,
List.of("https://image1.url", "https://image2.url"), 0L,
LocalDateTime.of(LocalDate.of(2023, 7, 13), LocalTime.of(11, 43, 11)),
LocalDateTime.of(LocalDate.of(2023, 7, 13), LocalTime.of(11, 43, 11))),
new FeedSimpleResponse(35L, "피드2 제목", "피드 내용", 43L, Collections.emptyList(), 3L,
LocalDateTime.of(LocalDate.of(2023, 7, 22), LocalTime.of(23, 54, 49)),
LocalDateTime.of(LocalDate.of(2023, 7, 22), LocalTime.of(23, 54, 49)))
);

when(feedQueryService.findAllMyFeeds(any())).thenReturn(feeds);

//when & then
mockMvc.perform(get("/feeds/my")
.header(HttpHeaders.AUTHORIZATION, "Bearer accessToken"))
.andExpect(status().isOk())
.andDo(print())
.andDo(document("find-all-my-feed", responseFields));
}

@Test
@DisplayName("이벤트의 피드를 성공적으로 저장하면 201 CREATED를 반환한다.")
void postFeedTest() throws Exception {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.emmsale.feed.application.dto.FeedDetailResponse;
import com.emmsale.feed.application.dto.FeedListResponse;
import com.emmsale.feed.application.dto.FeedPostRequest;
import com.emmsale.feed.application.dto.FeedSimpleResponse;
import com.emmsale.feed.application.dto.FeedUpdateRequest;
import com.emmsale.feed.application.dto.FeedUpdateResponse;
import com.emmsale.member.domain.Member;
Expand Down Expand Up @@ -43,6 +44,11 @@ public FeedDetailResponse findFeed(final Member member, @PathVariable final Long
return feedQueryService.findFeed(member, id);
}

@GetMapping("/my")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

의견을 낼 때, 다른 제안을 같이 드려야하는데 뭔가 my 보다 좋은게 없는 것 같기도 하고,,

다른 분들은 어떻게 생각하시나요?

/feeds/my

Copy link
Collaborator Author

@hyeonjerry hyeonjerry Sep 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저도 이 부분은 고민이 많았었는데 feeds/myfeeds?member-id={member-id}feeds/my를 선택했습니다.
이유는 이미 Member를 파라미터로 받고 있는데 사용자의 id를 추가로 받을 경우 불필요한 파라미터가 추가되고 유효성 검사를 해주어야 하는데 이 또한 member-id를 받지 않으면 유효성 검사를 되므로 불필요하다고 생각했기 때문입니다.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

전 조금 애매한 것 같아요.

사실 member-id를 따로 받는 것이 조금 더 정석적이긴 하지만, 굳이 해야하나? 라는 생각이 들기도 하더라고요.

그리고 , /feeds?member-id = 형식으로 짜면

위에 /feeds?event-id = 랑 겹쳐서 문제가 생길거에요.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

전 확장성을 고려했을 때 /feeds/member-id={member_id}도 괜찮은 것 같아요. 특정 사용자가 작성한 feed 목록을 조회하는 요구사항이 생긴다면 유연하게 사용할 수 있을 것 같아서요~!

public List<FeedSimpleResponse> findAllMyFeeds(final Member member) {
return feedQueryService.findAllMyFeeds(member);
}

@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public Long postFeed(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,4 +129,24 @@ private void validateDeletedFeed(final Feed feed) {
throw new FeedException(FeedExceptionType.FORBIDDEN_DELETED_FEED);
}
}

public List<FeedSimpleResponse> findAllMyFeeds(final Member member) {
final List<Feed> feeds = feedRepository.findByMember(member);

final List<Long> feedIds = feeds.stream()
.map(Feed::getId)
.collect(Collectors.toList());

final Map<Long, Long> feedCommentCounts = getFeedIdCommentCountMap(feedIds);
final Map<Long, List<Image>> feedImages = getFeedImagesMap(feedIds);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

내가 쓴 피드 목록을 볼 때 모든 이미지가 필요한가요??

화면이 제대로 없어서 잘 모르겠지만, 썸네일만 보여주지 않을까라는 생각이 듭니다

이 부분이 안드 분과 논의된 내용인지 말씀해주시면 좋을 것 같습니다

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

기존 피드 목록과 api를 완전히 통일해 달라는 요청이 있었기 때문에 이처럼 구현했습니다.
저도 추후 시간이 난다면 api에 대해 다시 이야기 하여 images와 thumbnail를 분리하고 목록에서는 images를 생략할 필요가 있다고 생각합니다.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ㅇㅈ 추후 생략해야 할 것 같아요


return feeds.stream()
.map(feed -> {
final List<Image> images = feedImages.getOrDefault(feed.getId(), Collections.emptyList());
final Long commentCount = feedCommentCounts.getOrDefault(feed.getId(),
DEFAULT_COMMENT_COUNT);
return FeedSimpleResponse.from(feed, images, commentCount);
})
.collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.emmsale.feed.domain.repository;

import com.emmsale.feed.domain.Feed;
import com.emmsale.member.domain.Member;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
Expand All @@ -11,4 +12,7 @@ public interface FeedRepository extends JpaRepository<Feed, Long> {

@Query("select f from Feed f where f.event.id = :eventId and f.isDeleted = false")
List<Feed> findAllByEventIdAndNotDeleted(Long eventId);

@Query("select f from Feed f where f.writer = :member and f.isDeleted = false")
List<Feed> findByMember(Member member);
}
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,49 @@ void findFeedWithDeletedFeedIdTest() {
}
}

@Nested
@DisplayName("자신이 작성한 피드 목록 조회 테스트")
class FindAllMy {

@Test
@DisplayName("자신이 작성한 모든 피드를 조회한다.")
void findAllFeedsTest() {
//given
final List<FeedSimpleResponse> expect = List.of(
FeedSimpleResponse.from(feed1, Collections.emptyList(), 0L),
FeedSimpleResponse.from(feed2, Collections.emptyList(), 0L)
);

//when
final List<FeedSimpleResponse> actual = feedQueryService.findAllMyFeeds(writer);

//then
assertThat(actual)
.usingRecursiveComparison()
.isEqualTo(expect);
}

@Test
@DisplayName("삭제된 피드는 자신이 작성한 피드 목록에 조회되지 않는다.")
void findAllFeedsWithWithDeletedFeedTest() {
//given
feed1.delete();
feedRepository.save(feed1);

final List<FeedSimpleResponse> expect = List.of(
FeedSimpleResponse.from(feed2, Collections.emptyList(), 0L)
);

//when
final List<FeedSimpleResponse> actual = feedQueryService.findAllMyFeeds(writer);

//then
assertThat(actual)
.usingRecursiveComparison()
.isEqualTo(expect);
}
}

@Nested
@DisplayName("피드 이미지 조회 테스트")
class FeedQueryWithImage {
Expand Down
Loading