From 3fe0b4efe5d66dd38734172e85dd92c684c2d355 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=9E=AC=EC=A4=91?= <126754298+m-a-king@users.noreply.github.com> Date: Mon, 2 Dec 2024 17:35:49 +0900 Subject: [PATCH 01/13] =?UTF-8?q?feat(VolunteerProfileQueryController):=20?= =?UTF-8?q?=EC=97=94=EB=93=9C=ED=8F=AC=EC=9D=B8=ED=8A=B8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 스웨거 태그 수정 --- .../volunteer/controller/VolunteerProfileQueryController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/somemore/volunteer/controller/VolunteerProfileQueryController.java b/src/main/java/com/somemore/volunteer/controller/VolunteerProfileQueryController.java index 7ff1459c8..a1ddeaf0e 100644 --- a/src/main/java/com/somemore/volunteer/controller/VolunteerProfileQueryController.java +++ b/src/main/java/com/somemore/volunteer/controller/VolunteerProfileQueryController.java @@ -19,8 +19,8 @@ @RestController @Slf4j @RequiredArgsConstructor -@RequestMapping("/api/profile") -@Tag(name = "GET Volunteer", description = "봉사자 조회") +@RequestMapping("/api/volunteer/profile") +@Tag(name = "GET Volunteer Profile", description = "봉사자 조회") public class VolunteerProfileQueryController { private final VolunteerQueryUseCase volunteerQueryUseCase; From 63f09d236696aaeccf58fe7fb2d75c775df4c695 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=9E=AC=EC=A4=91?= <126754298+m-a-king@users.noreply.github.com> Date: Mon, 2 Dec 2024 22:58:36 +0900 Subject: [PATCH 02/13] =?UTF-8?q?feat(VolunteerRepository):=20=EB=B4=89?= =?UTF-8?q?=EC=82=AC=20=EC=8B=9C=EA=B0=84=20=EB=82=B4=EB=A6=BC=EC=B0=A8?= =?UTF-8?q?=EC=88=9C=20=EB=B4=89=EC=82=AC=EC=9E=90=20=EB=9E=AD=ED=82=B9=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - mapper 추가 (VolunteerOverviewForRankingByHours) - 사용하지 않는 deleteAllInBatch 삭제 --- .../repository/VolunteerRepository.java | 5 ++++- .../repository/VolunteerRepositoryImpl.java | 20 +++++++++++++++++-- .../VolunteerOverviewForRankingByHours.java | 15 ++++++++++++++ 3 files changed, 37 insertions(+), 3 deletions(-) create mode 100644 src/main/java/com/somemore/volunteer/repository/mapper/VolunteerOverviewForRankingByHours.java diff --git a/src/main/java/com/somemore/volunteer/repository/VolunteerRepository.java b/src/main/java/com/somemore/volunteer/repository/VolunteerRepository.java index 364db842b..d87653764 100644 --- a/src/main/java/com/somemore/volunteer/repository/VolunteerRepository.java +++ b/src/main/java/com/somemore/volunteer/repository/VolunteerRepository.java @@ -1,8 +1,11 @@ package com.somemore.volunteer.repository; import com.somemore.volunteer.domain.Volunteer; +import com.somemore.volunteer.dto.response.VolunteerRankingResponseDto; +import com.somemore.volunteer.repository.mapper.VolunteerOverviewForRankingByHours; import org.springframework.stereotype.Repository; +import java.util.List; import java.util.Optional; import java.util.UUID; @@ -12,5 +15,5 @@ public interface VolunteerRepository { Optional findById(UUID id); Optional findByOauthId(String oauthId); String findNicknameById(UUID id); - void deleteAllInBatch(); + List findRankingByVolunteerHours(); } diff --git a/src/main/java/com/somemore/volunteer/repository/VolunteerRepositoryImpl.java b/src/main/java/com/somemore/volunteer/repository/VolunteerRepositoryImpl.java index 779d04cac..dc64d7beb 100644 --- a/src/main/java/com/somemore/volunteer/repository/VolunteerRepositoryImpl.java +++ b/src/main/java/com/somemore/volunteer/repository/VolunteerRepositoryImpl.java @@ -1,13 +1,16 @@ package com.somemore.volunteer.repository; import com.querydsl.core.types.Path; +import com.querydsl.core.types.Projections; import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.jpa.impl.JPAQueryFactory; import com.somemore.volunteer.domain.QVolunteer; import com.somemore.volunteer.domain.Volunteer; +import com.somemore.volunteer.repository.mapper.VolunteerOverviewForRankingByHours; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; +import java.util.List; import java.util.Optional; import java.util.UUID; @@ -42,8 +45,21 @@ public String findNicknameById(UUID id) { } @Override - public void deleteAllInBatch() { - volunteerJpaRepository.deleteAllInBatch(); + public List findRankingByVolunteerHours() { + return queryFactory + .select(Projections.constructor(VolunteerOverviewForRankingByHours.class, + volunteer.id, + volunteer.nickname, + volunteer.imgUrl, + volunteer.introduce, + volunteer.tier, + volunteer.totalVolunteerHours + )) + .from(volunteer) + .where(isNotDeleted()) + .orderBy(volunteer.totalVolunteerHours.desc()) + .limit(4) + .fetch(); } private Optional findOne(BooleanExpression condition) { diff --git a/src/main/java/com/somemore/volunteer/repository/mapper/VolunteerOverviewForRankingByHours.java b/src/main/java/com/somemore/volunteer/repository/mapper/VolunteerOverviewForRankingByHours.java new file mode 100644 index 000000000..48f77c212 --- /dev/null +++ b/src/main/java/com/somemore/volunteer/repository/mapper/VolunteerOverviewForRankingByHours.java @@ -0,0 +1,15 @@ +package com.somemore.volunteer.repository.mapper; + +import com.somemore.volunteer.domain.Tier; + +import java.util.UUID; + +public record VolunteerOverviewForRankingByHours( + UUID volunteerId, + String nickname, + String imgUrl, + String introduce, + Tier tier, + Integer totalVolunteerHours +) { +} From eb0b039bb576f206b2151629b3d9704aff204258 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=9E=AC=EC=A4=91?= <126754298+m-a-king@users.noreply.github.com> Date: Mon, 2 Dec 2024 22:59:30 +0900 Subject: [PATCH 03/13] =?UTF-8?q?feat(VolunteerRankingResponseDto):=20?= =?UTF-8?q?=EB=B4=89=EC=82=AC=EC=9E=90=20=EB=9E=AD=ED=82=B9=20=EC=9D=91?= =?UTF-8?q?=EB=8B=B5=20DTO=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - VolunteerRankingResponseDto 생성 및 VolunteerOverview 내 포함 - VolunteerOverviewForRankingByHours(mapper)를 기반으로 DTO 변환 로직 추가 --- .../response/VolunteerRankingResponseDto.java | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 src/main/java/com/somemore/volunteer/dto/response/VolunteerRankingResponseDto.java diff --git a/src/main/java/com/somemore/volunteer/dto/response/VolunteerRankingResponseDto.java b/src/main/java/com/somemore/volunteer/dto/response/VolunteerRankingResponseDto.java new file mode 100644 index 000000000..0a4a8d6ef --- /dev/null +++ b/src/main/java/com/somemore/volunteer/dto/response/VolunteerRankingResponseDto.java @@ -0,0 +1,57 @@ +package com.somemore.volunteer.dto.response; + +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.fasterxml.jackson.databind.annotation.JsonNaming; +import com.somemore.volunteer.repository.mapper.VolunteerOverviewForRankingByHours; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; + +import java.util.List; + +@JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) +@Builder +public record VolunteerRankingResponseDto( + @Schema(description = "랭킹에 포함된 봉사자 리스트") + List rankings +) { + @JsonNaming(PropertyNamingStrategies.SnakeCaseStrategy.class) + @Builder + public record VolunteerOverview( + @Schema(description = "봉사자 ID", example = "uuid-uuid-uuid-uuid") + String volunteerId, + + @Schema(description = "봉사자 닉네임", example = "길동이") + String nickname, + + @Schema(description = "봉사자 이미지 URL", example = "http://example.com/image.jpg") + String imgUrl, + + @Schema(description = "봉사자 소개글", example = "안녕하세요! 저는 자원봉사자 홍길동입니다.") + String introduce, + + @Schema(description = "봉사자 티어", example = "red") + String tier, + + @Schema(description = "봉사자의 총 봉사 시간", example = "120") + Integer totalVolunteerHours + ) { + private static VolunteerOverview from(VolunteerOverviewForRankingByHours source) { + return VolunteerOverview.builder() + .volunteerId(source.volunteerId().toString()) + .nickname(source.nickname()) + .imgUrl(source.imgUrl()) + .introduce(source.introduce()) + .tier(source.tier().name()) + .totalVolunteerHours(source.totalVolunteerHours()) + .build(); + } + } + + public static VolunteerRankingResponseDto from(List sources) { + return VolunteerRankingResponseDto.builder() + .rankings(sources.stream() + .map(VolunteerOverview::from) + .toList()) + .build(); + } +} \ No newline at end of file From fb0c4fa23cf7a6ed2b7a9d5aaace830cc7574163 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=9E=AC=EC=A4=91?= <126754298+m-a-king@users.noreply.github.com> Date: Mon, 2 Dec 2024 23:00:10 +0900 Subject: [PATCH 04/13] =?UTF-8?q?feat(VolunteerQueryService):=20=EB=B4=89?= =?UTF-8?q?=EC=82=AC=20=EC=8B=9C=EA=B0=84=20=EB=82=B4=EB=A6=BC=EC=B0=A8?= =?UTF-8?q?=EC=88=9C=20=EB=B4=89=EC=82=AC=EC=9E=90=20=EB=9E=AD=ED=82=B9=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../volunteer/service/VolunteerQueryService.java | 10 +++++++++- .../volunteer/usecase/VolunteerQueryUseCase.java | 3 +++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/somemore/volunteer/service/VolunteerQueryService.java b/src/main/java/com/somemore/volunteer/service/VolunteerQueryService.java index 4e57e2bef..cdaa6af59 100644 --- a/src/main/java/com/somemore/volunteer/service/VolunteerQueryService.java +++ b/src/main/java/com/somemore/volunteer/service/VolunteerQueryService.java @@ -5,14 +5,17 @@ import com.somemore.volunteer.domain.Volunteer; import com.somemore.volunteer.domain.VolunteerDetail; import com.somemore.volunteer.dto.response.VolunteerProfileResponseDto; +import com.somemore.volunteer.dto.response.VolunteerRankingResponseDto; import com.somemore.volunteer.repository.VolunteerDetailRepository; import com.somemore.volunteer.repository.VolunteerRepository; +import com.somemore.volunteer.repository.mapper.VolunteerOverviewForRankingByHours; import com.somemore.volunteer.usecase.VolunteerQueryUseCase; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.List; import java.util.UUID; import static com.somemore.global.exception.ExceptionMessage.NOT_EXISTS_VOLUNTEER; @@ -72,10 +75,15 @@ public String getNicknameById(UUID id) { return nickname; } + @Override + public VolunteerRankingResponseDto getRankingByHours() { + List rankingByVolunteerHours = volunteerRepository.findRankingByVolunteerHours(); + return VolunteerRankingResponseDto.from(rankingByVolunteerHours); + } + private Volunteer findVolunteer(UUID volunteerId) { return volunteerRepository.findById(volunteerId) .orElseThrow(() -> new BadRequestException(NOT_EXISTS_VOLUNTEER)); - } private VolunteerDetail findVolunteerDetail(UUID volunteerId) { diff --git a/src/main/java/com/somemore/volunteer/usecase/VolunteerQueryUseCase.java b/src/main/java/com/somemore/volunteer/usecase/VolunteerQueryUseCase.java index 18b00a044..2635d8686 100644 --- a/src/main/java/com/somemore/volunteer/usecase/VolunteerQueryUseCase.java +++ b/src/main/java/com/somemore/volunteer/usecase/VolunteerQueryUseCase.java @@ -1,6 +1,7 @@ package com.somemore.volunteer.usecase; import com.somemore.volunteer.dto.response.VolunteerProfileResponseDto; +import com.somemore.volunteer.dto.response.VolunteerRankingResponseDto; import java.util.UUID; @@ -15,4 +16,6 @@ public interface VolunteerQueryUseCase { UUID getVolunteerIdByOAuthId(String oAuthId); String getNicknameById(UUID id); + + VolunteerRankingResponseDto getRankingByHours(); } From 1629402f74a501e9eacfec4da7b36f274e478b8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=9E=AC=EC=A4=91?= <126754298+m-a-king@users.noreply.github.com> Date: Mon, 2 Dec 2024 23:00:47 +0900 Subject: [PATCH 05/13] =?UTF-8?q?feat(VolunteerRankingQueryController):=20?= =?UTF-8?q?=EB=B4=89=EC=82=AC=20=EC=8B=9C=EA=B0=84=20=EB=82=B4=EB=A6=BC?= =?UTF-8?q?=EC=B0=A8=EC=88=9C=20=EB=B4=89=EC=82=AC=EC=9E=90=20=EB=9E=AD?= =?UTF-8?q?=ED=82=B9=20=EC=A1=B0=ED=9A=8C=20=EC=BB=A8=ED=8A=B8=EB=A1=A4?= =?UTF-8?q?=EB=9F=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../VolunteerRankingQueryController.java | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 src/main/java/com/somemore/volunteer/controller/VolunteerRankingQueryController.java diff --git a/src/main/java/com/somemore/volunteer/controller/VolunteerRankingQueryController.java b/src/main/java/com/somemore/volunteer/controller/VolunteerRankingQueryController.java new file mode 100644 index 000000000..6ec7f64d4 --- /dev/null +++ b/src/main/java/com/somemore/volunteer/controller/VolunteerRankingQueryController.java @@ -0,0 +1,32 @@ +package com.somemore.volunteer.controller; + +import com.somemore.global.common.response.ApiResponse; +import com.somemore.volunteer.dto.response.VolunteerRankingResponseDto; +import com.somemore.volunteer.usecase.VolunteerQueryUseCase; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@Slf4j +@RequiredArgsConstructor +@RequestMapping("/api/volunteer/ranking") +@Tag(name = "GET Volunteer ranking", description = "봉사자 랭킹 조회") +public class VolunteerRankingQueryController { + + private final VolunteerQueryUseCase volunteerQueryUseCase; + + @Operation(summary = "봉사 시간 랭킹 조회", description = "봉사 시간 내림차순 4명 조회") + @GetMapping("/hours") + public ApiResponse getRankingByHours() { + + return ApiResponse.ok( + 200, + volunteerQueryUseCase.getRankingByHours(), + "랭킹(시간) 조회 성공"); + } +} From 88527c0c45144f701a307f3694858711485a37b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=9E=AC=EC=A4=91?= <126754298+m-a-king@users.noreply.github.com> Date: Mon, 2 Dec 2024 23:38:17 +0900 Subject: [PATCH 06/13] =?UTF-8?q?feat(Volunteer):=20=EB=B4=89=EC=82=AC=20?= =?UTF-8?q?=EC=8B=9C=EA=B0=84,=20=EB=B4=89=EC=82=AC=20=ED=9A=9F=EC=88=98?= =?UTF-8?q?=20=EC=97=85=EB=8D=B0=EC=9D=B4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/somemore/volunteer/domain/Volunteer.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/main/java/com/somemore/volunteer/domain/Volunteer.java b/src/main/java/com/somemore/volunteer/domain/Volunteer.java index e98872fa1..deb9a5abc 100644 --- a/src/main/java/com/somemore/volunteer/domain/Volunteer.java +++ b/src/main/java/com/somemore/volunteer/domain/Volunteer.java @@ -65,6 +65,11 @@ public void updateWith(VolunteerProfileUpdateRequestDto dto, String imgUrl) { this.imgUrl = imgUrl; } + public void updateVolunteerStats(int hours, int count) { + this.totalVolunteerHours += hours; + this.totalVolunteerCount += count; + } + @Builder private Volunteer( OAuthProvider oauthProvider, From ff98bcf2b14203c92178af70e043fd97eda5d2c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=9E=AC=EC=A4=91?= <126754298+m-a-king@users.noreply.github.com> Date: Mon, 2 Dec 2024 23:39:02 +0900 Subject: [PATCH 07/13] =?UTF-8?q?feat(VolunteerRepository):=20deleteAllInB?= =?UTF-8?q?atch=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../somemore/volunteer/repository/VolunteerRepository.java | 2 ++ .../volunteer/repository/VolunteerRepositoryImpl.java | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/src/main/java/com/somemore/volunteer/repository/VolunteerRepository.java b/src/main/java/com/somemore/volunteer/repository/VolunteerRepository.java index d87653764..ee17c4c5e 100644 --- a/src/main/java/com/somemore/volunteer/repository/VolunteerRepository.java +++ b/src/main/java/com/somemore/volunteer/repository/VolunteerRepository.java @@ -16,4 +16,6 @@ public interface VolunteerRepository { Optional findByOauthId(String oauthId); String findNicknameById(UUID id); List findRankingByVolunteerHours(); + + void deleteAllInBatch(); } diff --git a/src/main/java/com/somemore/volunteer/repository/VolunteerRepositoryImpl.java b/src/main/java/com/somemore/volunteer/repository/VolunteerRepositoryImpl.java index dc64d7beb..b49af5143 100644 --- a/src/main/java/com/somemore/volunteer/repository/VolunteerRepositoryImpl.java +++ b/src/main/java/com/somemore/volunteer/repository/VolunteerRepositoryImpl.java @@ -62,6 +62,11 @@ public List findRankingByVolunteerHours() { .fetch(); } + @Override + public void deleteAllInBatch() { + volunteerJpaRepository.deleteAllInBatch(); + } + private Optional findOne(BooleanExpression condition) { return Optional.ofNullable( From 3dfb0b2cec8b79d4644a980ee8c18cd1110bb8f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=9E=AC=EC=A4=91?= <126754298+m-a-king@users.noreply.github.com> Date: Mon, 2 Dec 2024 23:39:44 +0900 Subject: [PATCH 08/13] =?UTF-8?q?test(VolunteerRepository):=20=EB=B4=89?= =?UTF-8?q?=EC=82=AC=20=EC=8B=9C=EA=B0=84=20=EA=B8=B0=EC=A4=80=20=EB=B4=89?= =?UTF-8?q?=EC=82=AC=EC=9E=90=20=EC=A1=B0=ED=9A=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 상위 4명 조회 - 봉사자 없으면 빈 리스트 반환 - 봉사자 4명 미만이면 전체 조회 --- .../repository/VolunteerRepositoryTest.java | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/test/java/com/somemore/volunteer/repository/VolunteerRepositoryTest.java b/src/test/java/com/somemore/volunteer/repository/VolunteerRepositoryTest.java index c0f63d749..a966cec77 100644 --- a/src/test/java/com/somemore/volunteer/repository/VolunteerRepositoryTest.java +++ b/src/test/java/com/somemore/volunteer/repository/VolunteerRepositoryTest.java @@ -3,12 +3,14 @@ import com.somemore.IntegrationTestSupport; import com.somemore.auth.oauth.OAuthProvider; import com.somemore.volunteer.domain.Volunteer; +import com.somemore.volunteer.repository.mapper.VolunteerOverviewForRankingByHours; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; +import java.util.List; import java.util.Optional; import java.util.UUID; @@ -76,4 +78,57 @@ void findByOauthId() { assertThat(foundVolunteer.get().getOauthId()).isEqualTo(oAuthId); assertThat(foundVolunteer.get().getNickname()).isEqualTo(volunteer.getNickname()); } + + @DisplayName("봉사 시간 기준 상위 4명을 조회한다.") + @Test + void findRankingByVolunteerHours_top4() { + // given + for (int i = 1; i <= 5; i++) { + createVolunteerAndUpdateVolunteerStats(i); + } + + // when + List rankings = volunteerRepository.findRankingByVolunteerHours(); + + // then + assertThat(rankings).hasSize(4); + assertThat(rankings.get(0).totalVolunteerHours()).isGreaterThan(rankings.get(1).totalVolunteerHours()); + } + + @DisplayName("등록된 봉사자가 없는 경우 빈 리스트를 반환한다.") + @Test + void findRankingByVolunteerHours_noVolunteers() { + // given + volunteerRepository.deleteAllInBatch(); + + // when + List rankings = volunteerRepository.findRankingByVolunteerHours(); + + // then + assertThat(rankings).isEmpty(); + } + + @DisplayName("등록된 봉사자가 4명 이하인 경우 전체 봉사자를 반환한다.") + @Test + void findRankingByVolunteerHours_lessThan4Volunteers() { + // given + volunteerRepository.deleteAllInBatch(); + + for (int i = 1; i <= 3; i++) { + createVolunteerAndUpdateVolunteerStats(i); + } + + // when + List rankings = volunteerRepository.findRankingByVolunteerHours(); + + // then + assertThat(rankings).hasSize(3); + assertThat(rankings.get(0).totalVolunteerHours()).isGreaterThan(rankings.get(1).totalVolunteerHours()); + } + + private void createVolunteerAndUpdateVolunteerStats(int i) { + Volunteer volunteer = Volunteer.createDefault(OAuthProvider.NAVER, "oauth-id-" + i); + volunteer.updateVolunteerStats(i * 10, i); + volunteerRepository.save(volunteer); + } } \ No newline at end of file From e3104ec70663bac9a6b2626ad9a8274baaa77f68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=9E=AC=EC=A4=91?= <126754298+m-a-king@users.noreply.github.com> Date: Mon, 2 Dec 2024 23:40:14 +0900 Subject: [PATCH 09/13] =?UTF-8?q?test(VolunteerQueryService):=20=EB=B4=89?= =?UTF-8?q?=EC=82=AC=20=EC=8B=9C=EA=B0=84=20=EA=B8=B0=EC=A4=80=20=EB=B4=89?= =?UTF-8?q?=EC=82=AC=EC=9E=90=20=EC=A1=B0=ED=9A=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 상위 4명 조회 - 봉사자 없으면 빈 리스트 반환 --- .../service/VolunteerQueryServiceTest.java | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/test/java/com/somemore/volunteer/service/VolunteerQueryServiceTest.java b/src/test/java/com/somemore/volunteer/service/VolunteerQueryServiceTest.java index 000cfe1a5..09fc4ce5b 100644 --- a/src/test/java/com/somemore/volunteer/service/VolunteerQueryServiceTest.java +++ b/src/test/java/com/somemore/volunteer/service/VolunteerQueryServiceTest.java @@ -7,6 +7,7 @@ import com.somemore.volunteer.domain.VolunteerDetail; import com.somemore.volunteer.dto.request.VolunteerRegisterRequestDto; import com.somemore.volunteer.dto.response.VolunteerProfileResponseDto; +import com.somemore.volunteer.dto.response.VolunteerRankingResponseDto; import com.somemore.volunteer.repository.VolunteerDetailRepository; import com.somemore.volunteer.repository.VolunteerRepository; import org.junit.jupiter.api.DisplayName; @@ -14,6 +15,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; +import java.util.List; import java.util.UUID; import static com.somemore.global.exception.ExceptionMessage.NOT_EXISTS_VOLUNTEER; @@ -152,6 +154,40 @@ void getVolunteerDetailedProfile() { .hasMessage(UNAUTHORIZED_VOLUNTEER_DETAIL.getMessage()); } + @DisplayName("봉사 시간 기준 상위 4명의 랭킹을 조회한다.") + @Test + void getRankingByHours() { + // given + for (int i = 1; i <= 5; i++) { + Volunteer volunteer = Volunteer.createDefault(oAuthProvider, "oauth-id-" + i); + volunteer.updateVolunteerStats(i * 10, i); + volunteerRepository.save(volunteer); + } + + // when + VolunteerRankingResponseDto response = volunteerQueryService.getRankingByHours(); + + // then + assertThat(response).isNotNull(); + assertThat(response.rankings()).hasSize(4); + + List hours = response.rankings().stream() + .map(VolunteerRankingResponseDto.VolunteerOverview::totalVolunteerHours) + .toList(); + assertThat(hours).isSortedAccordingTo((a, b) -> b - a); + } + + @DisplayName("등록된 봉사자가 없는 경우 빈 랭킹 리스트를 반환한다.") + @Test + void getRankingByHours_noVolunteers() { + // when + VolunteerRankingResponseDto response = volunteerQueryService.getRankingByHours(); + + // then + assertThat(response).isNotNull(); + assertThat(response.rankings()).isEmpty(); + } + private static VolunteerDetail createVolunteerDetail(UUID volunteerId) { VolunteerRegisterRequestDto volunteerRegisterRequestDto = From 9467a7e1bf779cc708e9cb05b4eed949c549b49c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=9E=AC=EC=A4=91?= <126754298+m-a-king@users.noreply.github.com> Date: Mon, 2 Dec 2024 23:45:42 +0900 Subject: [PATCH 10/13] =?UTF-8?q?chore:=20=EB=B6=88=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20=EA=B0=9C=ED=96=89=20=EC=82=AD=EC=A0=9C,=20?= =?UTF-8?q?=ED=95=84=EC=9A=94=ED=95=9C=20=EA=B0=9C=ED=96=89=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../volunteer/dto/response/VolunteerRankingResponseDto.java | 2 +- .../com/somemore/volunteer/repository/VolunteerRepository.java | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/somemore/volunteer/dto/response/VolunteerRankingResponseDto.java b/src/main/java/com/somemore/volunteer/dto/response/VolunteerRankingResponseDto.java index 0a4a8d6ef..dbdb690d2 100644 --- a/src/main/java/com/somemore/volunteer/dto/response/VolunteerRankingResponseDto.java +++ b/src/main/java/com/somemore/volunteer/dto/response/VolunteerRankingResponseDto.java @@ -54,4 +54,4 @@ public static VolunteerRankingResponseDto from(List findByOauthId(String oauthId); String findNicknameById(UUID id); List findRankingByVolunteerHours(); - void deleteAllInBatch(); } From 8fcfe9bb0452809f5b5198009434dcc3e1cee004 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=9E=AC=EC=A4=91?= <126754298+m-a-king@users.noreply.github.com> Date: Tue, 3 Dec 2024 02:40:10 +0900 Subject: [PATCH 11/13] =?UTF-8?q?fix:=20=EC=82=AD=EC=A0=9C=EB=90=9C=20?= =?UTF-8?q?=EA=B4=84=ED=98=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/somemore/volunteer/service/VolunteerQueryService.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/somemore/volunteer/service/VolunteerQueryService.java b/src/main/java/com/somemore/volunteer/service/VolunteerQueryService.java index 1049f7755..440f8efef 100644 --- a/src/main/java/com/somemore/volunteer/service/VolunteerQueryService.java +++ b/src/main/java/com/somemore/volunteer/service/VolunteerQueryService.java @@ -81,6 +81,7 @@ public String getNicknameById(UUID id) { public VolunteerRankingResponseDto getRankingByHours() { List rankingByVolunteerHours = volunteerRepository.findRankingByVolunteerHours(); return VolunteerRankingResponseDto.from(rankingByVolunteerHours); + } @Override public List getAllByIds(List volunteerIds) { From ebe985041fc06a1b76916e722282dedbe424ae2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=9E=AC=EC=A4=91?= <126754298+m-a-king@users.noreply.github.com> Date: Tue, 3 Dec 2024 09:21:54 +0900 Subject: [PATCH 12/13] =?UTF-8?q?test(VolunteerQueryService):=20deleteAllI?= =?UTF-8?q?nBatch=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - getRankingByHours_noVolunteers 오류 해결 --- .../somemore/volunteer/service/VolunteerQueryServiceTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/test/java/com/somemore/volunteer/service/VolunteerQueryServiceTest.java b/src/test/java/com/somemore/volunteer/service/VolunteerQueryServiceTest.java index 830fbda8f..e2a7c6319 100644 --- a/src/test/java/com/somemore/volunteer/service/VolunteerQueryServiceTest.java +++ b/src/test/java/com/somemore/volunteer/service/VolunteerQueryServiceTest.java @@ -181,6 +181,9 @@ void getRankingByHours() { @DisplayName("등록된 봉사자가 없는 경우 빈 랭킹 리스트를 반환한다.") @Test void getRankingByHours_noVolunteers() { + // given + volunteerRepository.deleteAllInBatch(); + // when VolunteerRankingResponseDto response = volunteerQueryService.getRankingByHours(); From ceb4ffbb4c6cc90db3421ea0db90d5da5caad609 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=9E=AC=EC=A4=91?= <126754298+m-a-king@users.noreply.github.com> Date: Tue, 3 Dec 2024 09:30:21 +0900 Subject: [PATCH 13/13] =?UTF-8?q?refactor:=20unusedImport=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C,=20=EB=B3=80=EC=88=98=20=EB=AA=85=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/VolunteerRepository.java | 2 -- .../repository/VolunteerRepositoryImpl.java | 2 -- .../service/VolunteerQueryService.java | 9 ++++----- .../repository/VolunteerRepositoryTest.java | 9 +++------ .../service/VolunteerQueryServiceTest.java | 17 +++++++++-------- 5 files changed, 16 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/somemore/volunteer/repository/VolunteerRepository.java b/src/main/java/com/somemore/volunteer/repository/VolunteerRepository.java index 2ae137569..4710eb824 100644 --- a/src/main/java/com/somemore/volunteer/repository/VolunteerRepository.java +++ b/src/main/java/com/somemore/volunteer/repository/VolunteerRepository.java @@ -1,14 +1,12 @@ package com.somemore.volunteer.repository; import com.somemore.volunteer.domain.Volunteer; -import com.somemore.volunteer.dto.response.VolunteerRankingResponseDto; import com.somemore.volunteer.repository.mapper.VolunteerOverviewForRankingByHours; import org.springframework.stereotype.Repository; import java.util.List; import java.util.Optional; import java.util.UUID; -import org.springframework.stereotype.Repository; @Repository public interface VolunteerRepository { diff --git a/src/main/java/com/somemore/volunteer/repository/VolunteerRepositoryImpl.java b/src/main/java/com/somemore/volunteer/repository/VolunteerRepositoryImpl.java index dce71b381..6b9fdf178 100644 --- a/src/main/java/com/somemore/volunteer/repository/VolunteerRepositoryImpl.java +++ b/src/main/java/com/somemore/volunteer/repository/VolunteerRepositoryImpl.java @@ -13,8 +13,6 @@ import java.util.List; import java.util.Optional; import java.util.UUID; -import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Repository; @RequiredArgsConstructor @Repository diff --git a/src/main/java/com/somemore/volunteer/service/VolunteerQueryService.java b/src/main/java/com/somemore/volunteer/service/VolunteerQueryService.java index 440f8efef..ab08cd948 100644 --- a/src/main/java/com/somemore/volunteer/service/VolunteerQueryService.java +++ b/src/main/java/com/somemore/volunteer/service/VolunteerQueryService.java @@ -1,7 +1,5 @@ package com.somemore.volunteer.service; -import static com.somemore.global.exception.ExceptionMessage.NOT_EXISTS_VOLUNTEER; - import com.somemore.facade.validator.VolunteerDetailAccessValidator; import com.somemore.global.exception.BadRequestException; import com.somemore.volunteer.domain.Volunteer; @@ -12,13 +10,14 @@ import com.somemore.volunteer.repository.VolunteerRepository; import com.somemore.volunteer.repository.mapper.VolunteerOverviewForRankingByHours; import com.somemore.volunteer.usecase.VolunteerQueryUseCase; -import java.util.List; -import java.util.UUID; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.List; +import java.util.UUID; + import static com.somemore.global.exception.ExceptionMessage.NOT_EXISTS_VOLUNTEER; @Slf4j @@ -50,7 +49,7 @@ public VolunteerProfileResponseDto getVolunteerProfile(UUID volunteerId) { @Override public VolunteerProfileResponseDto getVolunteerDetailedProfile(UUID volunteerId, - UUID centerId) { + UUID centerId) { volunteerDetailAccessValidator.validateByCenterId(centerId, volunteerId); return VolunteerProfileResponseDto.from( diff --git a/src/test/java/com/somemore/volunteer/repository/VolunteerRepositoryTest.java b/src/test/java/com/somemore/volunteer/repository/VolunteerRepositoryTest.java index 67ef74c32..d517ad410 100644 --- a/src/test/java/com/somemore/volunteer/repository/VolunteerRepositoryTest.java +++ b/src/test/java/com/somemore/volunteer/repository/VolunteerRepositoryTest.java @@ -1,12 +1,9 @@ package com.somemore.volunteer.repository; -import static org.assertj.core.api.Assertions.assertThat; - import com.somemore.IntegrationTestSupport; import com.somemore.auth.oauth.OAuthProvider; import com.somemore.volunteer.domain.Volunteer; import com.somemore.volunteer.repository.mapper.VolunteerOverviewForRankingByHours; - import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; @@ -130,9 +127,9 @@ void findRankingByVolunteerHours_lessThan4Volunteers() { } private void createVolunteerAndUpdateVolunteerStats(int i) { - Volunteer volunteer = Volunteer.createDefault(OAuthProvider.NAVER, "oauth-id-" + i); - volunteer.updateVolunteerStats(i * 10, i); - volunteerRepository.save(volunteer); + Volunteer newVolunteer = Volunteer.createDefault(OAuthProvider.NAVER, "oauth-id-" + i); + newVolunteer.updateVolunteerStats(i * 10, i); + volunteerRepository.save(newVolunteer); } @DisplayName("아이디 리스트로 봉사자를 조회할 수있다.") diff --git a/src/test/java/com/somemore/volunteer/service/VolunteerQueryServiceTest.java b/src/test/java/com/somemore/volunteer/service/VolunteerQueryServiceTest.java index e2a7c6319..855dcdfc6 100644 --- a/src/test/java/com/somemore/volunteer/service/VolunteerQueryServiceTest.java +++ b/src/test/java/com/somemore/volunteer/service/VolunteerQueryServiceTest.java @@ -1,11 +1,5 @@ package com.somemore.volunteer.service; -import static com.somemore.global.exception.ExceptionMessage.NOT_EXISTS_VOLUNTEER; -import static com.somemore.global.exception.ExceptionMessage.UNAUTHORIZED_VOLUNTEER_DETAIL; -import static com.somemore.volunteer.domain.Volunteer.createDefault; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - import com.somemore.IntegrationTestSupport; import com.somemore.auth.oauth.OAuthProvider; import com.somemore.global.exception.BadRequestException; @@ -16,13 +10,20 @@ import com.somemore.volunteer.dto.response.VolunteerRankingResponseDto; import com.somemore.volunteer.repository.VolunteerDetailRepository; import com.somemore.volunteer.repository.VolunteerRepository; -import java.util.List; -import java.util.UUID; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; +import java.util.List; +import java.util.UUID; + +import static com.somemore.global.exception.ExceptionMessage.NOT_EXISTS_VOLUNTEER; +import static com.somemore.global.exception.ExceptionMessage.UNAUTHORIZED_VOLUNTEER_DETAIL; +import static com.somemore.volunteer.domain.Volunteer.createDefault; +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + @Transactional class VolunteerQueryServiceTest extends IntegrationTestSupport {