Skip to content

Commit

Permalink
[FEAT] 펀딩 최대 기여자 페이징 조회 추가 (#331)
Browse files Browse the repository at this point in the history
  • Loading branch information
YeaChan05 authored Jul 21, 2024
2 parents e023bd5 + c538845 commit e9695bd
Show file tree
Hide file tree
Showing 8 changed files with 92 additions and 58 deletions.
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
package org.kakaoshare.backend.domain.funding.controller;

import java.util.List;
import lombok.RequiredArgsConstructor;
import org.kakaoshare.backend.common.dto.PageResponse;

import org.kakaoshare.backend.domain.funding.dto.FundingCheckRequest;
import org.kakaoshare.backend.domain.funding.dto.inquiry.request.FriendFundingInquiryRequest;
import org.kakaoshare.backend.domain.funding.dto.FriendFundingItemRequest;
import org.kakaoshare.backend.domain.funding.dto.FundingCheckRequest;
import org.kakaoshare.backend.domain.funding.dto.FundingResponse;
import org.kakaoshare.backend.domain.funding.dto.ProgressResponse;
import org.kakaoshare.backend.domain.funding.dto.RegisterRequest;
import org.kakaoshare.backend.domain.funding.dto.RegisterResponse;
import org.kakaoshare.backend.domain.funding.dto.inquiry.request.FriendFundingInquiryRequest;
import org.kakaoshare.backend.domain.funding.dto.preview.request.FundingPreviewRequest;
import org.kakaoshare.backend.domain.funding.dto.preview.response.FundingPreviewResponse;
import org.kakaoshare.backend.domain.funding.entity.FundingStatus;
Expand All @@ -24,18 +22,21 @@
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RequiredArgsConstructor
@RestController
@RequestMapping("/api/v1")
public class FundingController {
private static final int DEFAULT_FUNDING_SIZE = 20;
private static final int DEFAULT_TOP_CONTRIBUTORS_SIZE = 5;

private final FundingService fundingService;
private final FundingDetailService fundingDetailService;
private static final int FUNDING_DEFAULT_SIZE = 20;

@PostMapping("/funding/{productId}")
public ResponseEntity<?> registerFunding(@PathVariable("productId") Long productId,
Expand Down Expand Up @@ -74,7 +75,7 @@ public ResponseEntity<?> getFriendsActiveFundingItems(@LoggedInMember String pro
@GetMapping("/members/funding/products")
public ResponseEntity<?> getMyAllFundingProducts(@LoggedInMember String providerId,
@RequestParam(name = "status", required = false) FundingStatus status,
@PageableDefault(size = FUNDING_DEFAULT_SIZE) final Pageable pageable) {
@PageableDefault(size = DEFAULT_FUNDING_SIZE) final Pageable pageable) {
PageResponse<?> response = fundingService.getMyFilteredFundingProducts(providerId, status, pageable);
return ResponseEntity.ok(response);
}
Expand All @@ -85,14 +86,10 @@ public ResponseEntity<?> preview(@RequestBody final FundingPreviewRequest fundin
return ResponseEntity.ok(fundingPreviewResponse);
}

@GetMapping("/{fundingId}/contributors")
public ResponseEntity<?> getTopContributors(@PathVariable Long fundingId,
@PageableDefault(size = 5) Pageable pageable,
@RequestHeader("Authorization") String accessToken) {

accessToken = accessToken.substring("Bearer ".length());
PageResponse<?> contributors = fundingDetailService.getTopContributors(fundingId, pageable,
accessToken);
return ResponseEntity.ok(contributors);
@GetMapping("/funding/{fundingId}/contributors")
public ResponseEntity<?> getTopContributors(@PathVariable final Long fundingId,
@PageableDefault(size = DEFAULT_TOP_CONTRIBUTORS_SIZE) final Pageable pageable) {
final PageResponse<?> response = fundingDetailService.getTopContributors(fundingId, pageable);
return ResponseEntity.ok(response);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.kakaoshare.backend.domain.funding.dto.rank.response;

public record TopContributorResponse(
String profileUrl,
String name,
Double rate
) {
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.kakaoshare.backend.domain.funding.repository;

import org.kakaoshare.backend.domain.funding.dto.rank.response.TopContributorResponse;
import org.kakaoshare.backend.domain.funding.entity.Funding;
import org.kakaoshare.backend.domain.funding.entity.FundingDetail;
import org.kakaoshare.backend.domain.funding.repository.query.FundingDetailRepositoryCustom;
Expand All @@ -21,7 +22,9 @@ public interface FundingDetailRepository extends JpaRepository<FundingDetail, Lo
"WHERE fd.funding.fundingId =:fundingId")
List<FundingDetail> findAllByFundingId(@Param("fundingId") final Long fundingId);

@Query("SELECT fd FROM FundingDetail fd WHERE fd.funding.fundingId = :fundingId ORDER BY fd.amount DESC")
Page<FundingDetail> findTopContributorsByFundingId(@Param("fundingId") Long fundingId, Pageable pageable);

@Query("SELECT NEW org.kakaoshare.backend.domain.funding.dto.rank.response.TopContributorResponse(fd.member.profileImageUrl, fd.member.name, fd.rate) " +
"FROM FundingDetail fd " +
"LEFT JOIN fd.member m ON m.memberId = fd.member.memberId " +
"WHERE fd.funding.fundingId = :fundingId")
Page<TopContributorResponse> findTopContributorsByFundingId(@Param("fundingId") Long fundingId, Pageable pageable);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,22 @@
import com.querydsl.core.util.StringUtils;
import lombok.RequiredArgsConstructor;
import org.kakaoshare.backend.common.dto.PageResponse;
import org.kakaoshare.backend.domain.friend.service.KakaoFriendService;
import org.kakaoshare.backend.domain.funding.dto.inquiry.ContributedFundingHistoryDto;
import org.kakaoshare.backend.domain.funding.dto.inquiry.request.ContributedFundingHistoryRequest;
import org.kakaoshare.backend.domain.funding.dto.inquiry.response.ContributedFundingHistoryResponse;
import org.kakaoshare.backend.domain.funding.dto.inquiry.response.FundingContributorResponse;
import org.kakaoshare.backend.domain.funding.entity.FundingDetail;
import org.kakaoshare.backend.domain.funding.dto.rank.response.TopContributorResponse;
import org.kakaoshare.backend.domain.funding.repository.FundingDetailRepository;
import org.kakaoshare.backend.domain.funding.vo.FundingHistoryDate;
import org.kakaoshare.backend.domain.member.dto.oauth.profile.detail.KakaoFriendListDto;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class FundingDetailService {
private final FundingDetailRepository fundingDetailRepository;
private final KakaoFriendService kakaoFriendService;

public PageResponse<?> lookUp(final String providerId,
final ContributedFundingHistoryRequest contributedFundingHistoryRequest,
Expand All @@ -45,36 +38,8 @@ private Page<ContributedFundingHistoryDto> getFundingDetailHistoryDto(final Stri
return fundingDetailRepository.findHistoryByCondition(providerId, date, status, pageable);
}

public PageResponse<?> getTopContributors(Long fundingId, Pageable pageable, String accessToken) {
Page<FundingDetail> fundingDetails = fundingDetailRepository.findTopContributorsByFundingId(fundingId, pageable);

List<KakaoFriendListDto> friendsList = kakaoFriendService.getFriendsList(accessToken);

List<FundingContributorResponse> responses = fundingDetails.stream()
.map(detail -> {
KakaoFriendListDto friendProfile = findFriendProfile(detail.getMember().getProviderId(), friendsList);
return FundingContributorResponse.of(
friendProfile.getProfileThumbnailImage(),
friendProfile.getProfileNickname(),
detail.getAmount(),
calculateContributionPercentage(detail)
);
}).toList();

Page<FundingContributorResponse> contributorResponses = new PageImpl<>(responses, pageable, fundingDetails.getTotalElements());
return PageResponse.from(contributorResponses);
}

private KakaoFriendListDto findFriendProfile(String providerId, List<KakaoFriendListDto> friendsList) {
return friendsList.stream()
.filter(friend -> friend.getId().equals(providerId))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("No matching friend found for providerId: " + providerId));
}



private double calculateContributionPercentage(FundingDetail detail) {
return 100.0 * detail.getAmount() / detail.getFunding().getGoalAmount();
public PageResponse<?> getTopContributors(final Long fundingId, final Pageable pageable) {
final Page<TopContributorResponse> page = fundingDetailRepository.findTopContributorsByFundingId(fundingId, pageable);
return PageResponse.from(page);
}
}
4 changes: 4 additions & 0 deletions src/main/resources/testdata/initial_5_payment.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
INSERT INTO payment (created_at, delivery_price, payment_id, purchase_price, total_price, payment_number, method)
VALUES (NOW(), 0, 1, 3000, 3000, '1', 'KAKAO_PAY'),
(NOW(), 0, 2, 2000, 2000, '2', 'KAKAO_PAY'),
(NOW(), 0, 3, 1000, 1000, '3', 'KAKAO_PAY');
4 changes: 4 additions & 0 deletions src/main/resources/testdata/initial_6_funding_detail.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
INSERT INTO funding_detail (created_at, amount, rate, funding_id, payment_id, member_id, status)
VALUES (NOW(), 3000, 30.0, 1, 1, 1, 'PROGRESS'),
(NOW(), 2000, 20.0, 1, 1, 2, 'PROGRESS'),
(NOW(), 1000, 10.0, 1, 1, 3, 'PROGRESS');
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package org.kakaoshare.backend.domain.funding.repository;

import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.kakaoshare.backend.common.RepositoryTest;
import org.kakaoshare.backend.domain.funding.dto.rank.response.TopContributorResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;

import java.util.List;

@RepositoryTest
class FundingDetailRepositoryTest {
@Autowired
FundingDetailRepository fundingDetailRepository;

@Test
@DisplayName("최대 기여자 조회")
public void findTopContributorsByFundingId() throws Exception {
final Long fundingId = 1L;
final Pageable pageable = PageRequest.of(0, 5, Sort.by(Sort.Direction.DESC, "rate"));
final Page<TopContributorResponse> page = fundingDetailRepository.findTopContributorsByFundingId(fundingId, pageable);
final List<TopContributorResponse> content = page.getContent();
Assertions.assertThat(content.get(0).rate()).isEqualTo(30.0);
Assertions.assertThat(content.get(1).rate()).isEqualTo(20.0);
Assertions.assertThat(content.get(2).rate()).isEqualTo(10.0);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.EmptySource;
Expand All @@ -12,6 +13,7 @@
import org.kakaoshare.backend.domain.funding.dto.inquiry.ContributedFundingHistoryDto;
import org.kakaoshare.backend.domain.funding.dto.inquiry.request.ContributedFundingHistoryRequest;
import org.kakaoshare.backend.domain.funding.dto.inquiry.response.ContributedFundingHistoryResponse;
import org.kakaoshare.backend.domain.funding.dto.rank.response.TopContributorResponse;
import org.kakaoshare.backend.domain.funding.repository.FundingDetailRepository;
import org.kakaoshare.backend.domain.funding.vo.FundingHistoryDate;
import org.kakaoshare.backend.domain.member.entity.Member;
Expand Down Expand Up @@ -156,6 +158,25 @@ public void lookUpWhenInvalidDateRange(final String status) throws Exception {
.isInstanceOf(DateException.class);
}


@Test
@DisplayName("최대 기여자 조회")
public void getTopContributors() throws Exception {
final Long fundingId = 1L;
final List<TopContributorResponse> content = List.of(
new TopContributorResponse("profileUrl1", "테스터1", 30.0),
new TopContributorResponse("profileUrl1", "테스터2", 20.0),
new TopContributorResponse("profileUrl1", "테스터3", 10.0)
);

final Page<TopContributorResponse> page = new PageImpl<>(content, pageable, content.size());
doReturn(page).when(fundingDetailRepository).findTopContributorsByFundingId(fundingId, pageable);

final PageResponse<?> expect = PageResponse.from(page);
final PageResponse<?> actual = fundingDetailService.getTopContributors(fundingId, pageable);
assertThat(actual).usingRecursiveComparison().isEqualTo(expect);
}

private ProductDto getProductDto(final Product product) {
return new ProductDto(
product.getProductId(),
Expand Down

0 comments on commit e9695bd

Please sign in to comment.