-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
완료된 리뷰가 많은 서포터 순대로 조회하는 기능 구현 (#712)
* feat: 리뷰가 많은 사람 랭킹 구하는 기능 구현 * test: 랭킹 인수테스트와 restdocs 테스트 구현 * feat: 랭킹에 company 항목 추가 * refactor: 다른 랭킹도 추가할 수 있도록 Rankable 마커 인터페이스 구현
- Loading branch information
Showing
22 changed files
with
547 additions
and
6 deletions.
There are no files selected for viewing
Submodule secret
updated
from 9a4adb to 4223f4
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
ifndef::snippets[] | ||
:snippets: ../../../build/generated-snippets | ||
endif::[] | ||
:doctype: book | ||
:icons: font | ||
:source-highlighter: highlight.js | ||
:toc: left | ||
:toclevels: 3 | ||
:sectlinks: | ||
:operation-http-request-title: Example Request | ||
:operation-http-response-title: Example Response | ||
|
||
==== *완료된 리뷰가 많은 서포터 랭킹 조회 API* | ||
|
||
===== *Http Request* | ||
|
||
include::{snippets}/../../build/generated-snippets/rank-read-api-test/read-most-review-supporter/http-request.adoc[] | ||
|
||
===== *Http Request Query Parameters* | ||
|
||
include::{snippets}/../../build/generated-snippets/rank-read-api-test/read-most-review-supporter/query-parameters.adoc[] | ||
|
||
===== *Http Response* | ||
|
||
include::{snippets}/../../build/generated-snippets/rank-read-api-test/read-most-review-supporter/http-response.adoc[] | ||
|
||
===== *Http Response Fields* | ||
|
||
include::{snippets}/../../build/generated-snippets/rank-read-api-test/read-most-review-supporter/response-fields.adoc[] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
23 changes: 23 additions & 0 deletions
23
...d/baton/src/main/java/touch/baton/domain/member/query/controller/RankQueryController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package touch.baton.domain.member.query.controller; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RequestParam; | ||
import org.springframework.web.bind.annotation.RestController; | ||
import touch.baton.domain.member.query.controller.response.RankResponses; | ||
import touch.baton.domain.member.query.service.RankQueryService; | ||
|
||
@RequiredArgsConstructor | ||
@RequestMapping("/api/v1/rank") | ||
@RestController | ||
public class RankQueryController { | ||
|
||
private final RankQueryService rankQueryService; | ||
|
||
@GetMapping("/supporter") | ||
public ResponseEntity<RankResponses> readMostReviewSupporter(@RequestParam(defaultValue = "5") final int limit) { | ||
return ResponseEntity.ok(rankQueryService.readMostReviewSupporter(limit)); | ||
} | ||
} |
41 changes: 41 additions & 0 deletions
41
...aton/src/main/java/touch/baton/domain/member/query/controller/response/RankResponses.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
package touch.baton.domain.member.query.controller.response; | ||
|
||
import touch.baton.domain.member.command.Supporter; | ||
|
||
import java.util.List; | ||
import java.util.concurrent.atomic.AtomicInteger; | ||
|
||
public record RankResponses<T extends Rankable>(List<T> data) { | ||
|
||
public static RankResponses<SupporterRank> from(final List<Supporter> supporters) { | ||
final AtomicInteger rank = new AtomicInteger(1); | ||
final List<SupporterRank> responses = supporters.stream() | ||
.map(supporter -> new SupporterRank( | ||
rank.getAndIncrement(), | ||
supporter.getMember().getMemberName().getValue(), | ||
supporter.getId(), | ||
supporter.getReviewCount().getValue(), | ||
supporter.getMember().getImageUrl().getValue(), | ||
supporter.getMember().getGithubUrl().getValue(), | ||
supporter.getMember().getCompany().getValue(), | ||
supporter.getSupporterTechnicalTags().getSupporterTechnicalTags().stream() | ||
.map(supporterTechnicalTag -> supporterTechnicalTag.getTechnicalTag().getTagName().getValue()) | ||
.toList())) | ||
.toList(); | ||
|
||
return new RankResponses<>(responses); | ||
} | ||
|
||
public record SupporterRank( | ||
int rank, | ||
String name, | ||
long supporterId, | ||
int reviewedCount, | ||
String imageUrl, | ||
String githubUrl, | ||
String company, | ||
List<String> technicalTags | ||
) implements Rankable { | ||
|
||
} | ||
} |
4 changes: 4 additions & 0 deletions
4
...end/baton/src/main/java/touch/baton/domain/member/query/controller/response/Rankable.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
package touch.baton.domain.member.query.controller.response; | ||
|
||
public interface Rankable { | ||
} |
26 changes: 26 additions & 0 deletions
26
...aton/src/main/java/touch/baton/domain/member/query/repository/RankQuerydslRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
package touch.baton.domain.member.query.repository; | ||
|
||
import com.querydsl.jpa.impl.JPAQueryFactory; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Repository; | ||
import touch.baton.domain.member.command.Supporter; | ||
|
||
import java.util.List; | ||
|
||
import static touch.baton.domain.member.command.QMember.member; | ||
import static touch.baton.domain.member.command.QSupporter.supporter; | ||
|
||
@RequiredArgsConstructor | ||
@Repository | ||
public class RankQuerydslRepository { | ||
|
||
private final JPAQueryFactory jpaQueryFactory; | ||
|
||
public List<Supporter> findMostReviewSupporterByCount(final int count) { | ||
return jpaQueryFactory.selectFrom(supporter) | ||
.join(supporter.member, member).fetchJoin() | ||
.orderBy(supporter.reviewCount.value.desc()) | ||
.limit(count) | ||
.fetch(); | ||
} | ||
} |
19 changes: 19 additions & 0 deletions
19
backend/baton/src/main/java/touch/baton/domain/member/query/service/RankQueryService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package touch.baton.domain.member.query.service; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
import touch.baton.domain.member.query.controller.response.RankResponses; | ||
import touch.baton.domain.member.query.repository.RankQuerydslRepository; | ||
|
||
@RequiredArgsConstructor | ||
@Transactional(readOnly = true) | ||
@Service | ||
public class RankQueryService { | ||
|
||
private final RankQuerydslRepository rankQueryDslRepository; | ||
|
||
public RankResponses<RankResponses.SupporterRank> readMostReviewSupporter(final int maxCount) { | ||
return RankResponses.from(rankQueryDslRepository.findMostReviewSupporterByCount(maxCount)); | ||
} | ||
} |
45 changes: 45 additions & 0 deletions
45
backend/baton/src/test/java/touch/baton/assure/member/query/RankQueryRestAssuredTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package touch.baton.assure.member.query; | ||
|
||
import org.junit.jupiter.api.Test; | ||
import touch.baton.assure.member.support.query.RankQueryAssuredSupport; | ||
import touch.baton.config.AssuredTestConfig; | ||
import touch.baton.config.infra.auth.oauth.authcode.FakeAuthCodes; | ||
import touch.baton.domain.member.command.Supporter; | ||
import touch.baton.domain.member.command.vo.SocialId; | ||
|
||
import java.util.List; | ||
|
||
import static touch.baton.assure.member.support.query.RankQueryAssuredSupport.RankQueryResponseBuilder.서포터_리뷰_랭킹_응답; | ||
|
||
@SuppressWarnings("NonAsciiCharacters") | ||
class RankQueryRestAssuredTest extends AssuredTestConfig { | ||
|
||
@Test | ||
void 코드_리뷰를_가장_많이_한_5명을_리뷰_숫자를_기준으로_내림차순으로_반환한다() { | ||
// given | ||
final String 에단_액세스_토큰 = oauthLoginTestManager.소셜_회원가입을_진행한_후_액세스_토큰을_반환한다(FakeAuthCodes.ethanAuthCode()); | ||
final SocialId 에단_소셜_아이디 = jwtTestManager.parseToSocialId(에단_액세스_토큰); | ||
final Supporter 서포터_에단 = supporterRepository.getBySocialId(에단_소셜_아이디); | ||
rankQueryRepository.updateReviewCount(서포터_에단.getId(), 10); | ||
|
||
final String 디투_액세스_토큰 = oauthLoginTestManager.소셜_회원가입을_진행한_후_액세스_토큰을_반환한다(FakeAuthCodes.ditooAuthCode()); | ||
final SocialId 디투_소셜_아이디 = jwtTestManager.parseToSocialId(디투_액세스_토큰); | ||
final Supporter 서포터_디투 = supporterRepository.getBySocialId(디투_소셜_아이디); | ||
rankQueryRepository.updateReviewCount(서포터_디투.getId(), 5); | ||
|
||
final String 헤나_액세스_토큰 = oauthLoginTestManager.소셜_회원가입을_진행한_후_액세스_토큰을_반환한다(FakeAuthCodes.hyenaAuthCode()); | ||
final SocialId 헤나_소셜_아이디 = jwtTestManager.parseToSocialId(헤나_액세스_토큰); | ||
final Supporter 서포터_헤나 = supporterRepository.getBySocialId(헤나_소셜_아이디); | ||
rankQueryRepository.updateReviewCount(서포터_헤나.getId(), 20); | ||
|
||
// when, then | ||
RankQueryAssuredSupport.클라이언트_요청() | ||
.서포터_리뷰_랭킹을_조회한다(2) | ||
|
||
.서버_응답() | ||
.서포터_리뷰_랭킹_조회_성공을_검증한다(List.of( | ||
서포터_리뷰_랭킹_응답(1, 서포터_헤나, 20), | ||
서포터_리뷰_랭킹_응답(2, 서포터_에단, 10) | ||
)); | ||
} | ||
} |
71 changes: 71 additions & 0 deletions
71
.../baton/src/test/java/touch/baton/assure/member/support/query/RankQueryAssuredSupport.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
package touch.baton.assure.member.support.query; | ||
|
||
import io.restassured.common.mapper.TypeRef; | ||
import io.restassured.response.ExtractableResponse; | ||
import io.restassured.response.Response; | ||
import touch.baton.assure.common.AssuredSupport; | ||
import touch.baton.assure.common.QueryParams; | ||
import touch.baton.domain.member.command.Member; | ||
import touch.baton.domain.member.command.Supporter; | ||
import touch.baton.domain.member.query.controller.response.RankResponses; | ||
|
||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.Map; | ||
|
||
import static org.assertj.core.api.SoftAssertions.assertSoftly; | ||
|
||
@SuppressWarnings("NonAsciiCharacters") | ||
public class RankQueryAssuredSupport { | ||
|
||
private RankQueryAssuredSupport() { | ||
} | ||
|
||
public static RankQueryBuilder 클라이언트_요청() { | ||
return new RankQueryBuilder(); | ||
} | ||
|
||
public static class RankQueryBuilder { | ||
|
||
private ExtractableResponse<Response> response; | ||
|
||
public RankQueryBuilder 서포터_리뷰_랭킹을_조회한다(final int limit) { | ||
response = AssuredSupport.get("/api/v1/rank/supporter", new QueryParams(Map.of("limit", limit))); | ||
return this; | ||
} | ||
|
||
public RankQueryResponseBuilder 서버_응답() { | ||
return new RankQueryResponseBuilder(response); | ||
} | ||
} | ||
|
||
public static class RankQueryResponseBuilder { | ||
|
||
private final ExtractableResponse<Response> response; | ||
|
||
public RankQueryResponseBuilder(final ExtractableResponse<Response> response) { | ||
this.response = response; | ||
} | ||
|
||
public void 서포터_리뷰_랭킹_조회_성공을_검증한다(final List<RankResponses.SupporterRank> 랭킹_응답) { | ||
final RankResponses<RankResponses.SupporterRank> actual = this.response.as(new TypeRef<>(){}); | ||
|
||
assertSoftly(softly -> { | ||
softly.assertThat(actual.data()).hasSize(랭킹_응답.size()); | ||
softly.assertThat(actual.data()).isEqualTo(랭킹_응답); | ||
}); | ||
} | ||
|
||
public static RankResponses.SupporterRank 서포터_리뷰_랭킹_응답(final int 순위, final Supporter 서포터, final int 리뷰수) { | ||
final Member member = 서포터.getMember(); | ||
return new RankResponses.SupporterRank(순위, | ||
member.getMemberName().getValue(), | ||
서포터.getId(), | ||
리뷰수, | ||
member.getImageUrl().getValue(), | ||
member.getGithubUrl().getValue(), | ||
member.getCompany().getValue(), | ||
Collections.emptyList()); | ||
} | ||
} | ||
} |
31 changes: 31 additions & 0 deletions
31
backend/baton/src/test/java/touch/baton/assure/repository/TestRankQueryRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package touch.baton.assure.repository; | ||
|
||
import com.querydsl.jpa.impl.JPAQueryFactory; | ||
import org.springframework.context.annotation.Primary; | ||
import org.springframework.context.annotation.Profile; | ||
import org.springframework.stereotype.Repository; | ||
import org.springframework.transaction.annotation.Transactional; | ||
import touch.baton.domain.member.query.repository.RankQuerydslRepository; | ||
|
||
import static touch.baton.domain.member.command.QSupporter.supporter; | ||
|
||
@Profile("test") | ||
@Primary | ||
@Repository | ||
public class TestRankQueryRepository extends RankQuerydslRepository { | ||
|
||
private JPAQueryFactory jpaQueryFactory; | ||
|
||
public TestRankQueryRepository(final JPAQueryFactory jpaQueryFactory) { | ||
super(jpaQueryFactory); | ||
this.jpaQueryFactory = jpaQueryFactory; | ||
} | ||
|
||
@Transactional | ||
public void updateReviewCount(final long supporterId, final int reviewCount) { | ||
jpaQueryFactory.update(supporter) | ||
.set(supporter.reviewCount.value, supporter.reviewCount.value.add(reviewCount)) | ||
.where(supporter.id.eq(supporterId)) | ||
.execute(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.