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

Feat: 이번달 러닝 서머리 V2 API 추가 #300

Merged
merged 2 commits into from
Nov 8, 2024
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
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@
import com.dnd.runus.domain.common.Pace;
import com.dnd.runus.domain.goalAchievement.GoalAchievement;
import com.dnd.runus.domain.goalAchievement.GoalAchievementRepository;
import com.dnd.runus.domain.level.Level;
import com.dnd.runus.domain.member.Member;
import com.dnd.runus.domain.member.MemberLevel;
import com.dnd.runus.domain.member.MemberLevelRepository;
import com.dnd.runus.domain.member.MemberRepository;
import com.dnd.runus.domain.running.DailyRunningRecordSummary;
import com.dnd.runus.domain.running.RunningRecord;
Expand Down Expand Up @@ -47,7 +44,6 @@
public class RunningRecordService {
private final RunningRecordRepository runningRecordRepository;
private final MemberRepository memberRepository;
private final MemberLevelRepository memberLevelRepository;
private final ChallengeRepository challengeRepository;
private final ChallengeAchievementRepository challengeAchievementRepository;
private final ChallengeAchievementPercentageRepository percentageValuesRepository;
Expand All @@ -61,7 +57,6 @@ public class RunningRecordService {
public RunningRecordService(
RunningRecordRepository runningRecordRepository,
MemberRepository memberRepository,
MemberLevelRepository memberLevelRepository,
ChallengeRepository challengeRepository,
ChallengeAchievementRepository challengeAchievementRepository,
ChallengeAchievementPercentageRepository percentageValuesRepository,
Expand All @@ -70,7 +65,6 @@ public RunningRecordService(
@Value("${app.default-zone-offset}") ZoneOffset defaultZoneOffset) {
this.runningRecordRepository = runningRecordRepository;
this.memberRepository = memberRepository;
this.memberLevelRepository = memberLevelRepository;
this.challengeRepository = challengeRepository;
this.challengeAchievementRepository = challengeAchievementRepository;
this.percentageValuesRepository = percentageValuesRepository;
Expand Down Expand Up @@ -223,22 +217,11 @@ public RunningRecordMonthlySummaryResponse getMonthlyRunningSummery(long memberI
OffsetDateTime startDateOfMonth =
OffsetDateTime.now(ZoneId.of(SERVER_TIMEZONE)).withDayOfMonth(1).truncatedTo(ChronoUnit.DAYS);
OffsetDateTime startDateOfNextMonth = startDateOfMonth.plusMonths(1);

int monthValue = startDateOfMonth.getMonthValue();

int monthlyTotalDistance = runningRecordRepository.findTotalDistanceMeterByMemberIdWithRangeDate(
memberId, startDateOfMonth, startDateOfNextMonth);

MemberLevel.Current currentMemberLevel = memberLevelRepository.findByMemberIdWithLevel(memberId);

long nextLevel = currentMemberLevel.level().levelId() + 1;
int remainingKmToNextLevel = currentMemberLevel.level().expRangeEnd() - currentMemberLevel.currentExp();

return new RunningRecordMonthlySummaryResponse(
monthValue,
monthlyTotalDistance,
Level.formatLevelName(nextLevel),
Level.formatExp(remainingKmToNextLevel));
return RunningRecordMonthlySummaryResponse.builder()
.month(startDateOfMonth.getMonthValue())
.monthlyTotalMeter(runningRecordRepository.findTotalDistanceMeterByMemberIdWithRangeDate(
memberId, startDateOfMonth, startDateOfNextMonth))
.build();
}

private ChallengeAchievement handleChallengeMode(Long challengeId, long memberId, RunningRecord runningRecord) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package com.dnd.runus.application.running;

import com.dnd.runus.domain.running.RunningRecordRepository;
import com.dnd.runus.domain.scale.ScaleAchievementLog;
import com.dnd.runus.domain.scale.ScaleAchievementRepository;
import com.dnd.runus.presentation.v2.running.dto.response.RunningRecordMonthlySummaryResponseV2;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.DecimalFormat;
import java.util.List;

import static com.dnd.runus.global.constant.MetricsConversionFactor.METERS_IN_A_KILOMETER;

@Service
public class RunningRecordServiceV2 {

private final RunningRecordRepository runningRecordRepository;
private final ScaleAchievementRepository scaleAchievementRepository;

private static final DecimalFormat KILO_METER_UNDER_1_POINT_FORMATTER = new DecimalFormat("#,###.#km");

public RunningRecordServiceV2(
RunningRecordRepository runningRecordRepository, ScaleAchievementRepository scaleAchievementRepository) {
this.runningRecordRepository = runningRecordRepository;
this.scaleAchievementRepository = scaleAchievementRepository;
}

// todo 지구 한바퀴 작업 후 리팩터링 예정
@Transactional(readOnly = true)
public RunningRecordMonthlySummaryResponseV2.PercentageBoxWithMessage getPercentageValues(long memberId) {
// 지구한바퀴 코스 조회
List<ScaleAchievementLog> scaleAchievementLogs = scaleAchievementRepository.findScaleAchievementLogs(memberId);
ScaleAchievementLog currentCourseLog = scaleAchievementLogs.stream()
.filter(log -> log.achievedDate() == null)
.findFirst()
.orElse(null);

// todo 정해지면 하드코드 수정
if (currentCourseLog == null) {
return RunningRecordMonthlySummaryResponseV2.PercentageBoxWithMessage.builder()
.message("축하합니다! 지구 한바퀴 완주하셨네요!")
.percentageBox(RunningRecordMonthlySummaryResponseV2.PercentageBox.builder()
.startName("한국")
.endName("지구 한바퀴")
.percentage(100)
.build())
.build();
}

// 사용자가 달린 전체 거리 확인
int totalRunningDistanceMeter = runningRecordRepository.findTotalDistanceMeterByMemberId(memberId);
// 성취한 코스의 전체 합 거리
int achievedCourseMeterSum = scaleAchievementLogs.stream()
.filter(log -> log.achievedDate() != null)
.mapToInt(log -> log.scale().sizeMeter())
.sum();

// 현재 코스에서 사용자가 성취한 거리 합
double currentCourseAchievedKmSum =
(totalRunningDistanceMeter - achievedCourseMeterSum) / METERS_IN_A_KILOMETER;
// 현재 코스 완주를 위해 필요한 키로미터 값
double courseSizeKm = currentCourseLog.scale().sizeMeter() / METERS_IN_A_KILOMETER;

double percentage = calPercentage(courseSizeKm, currentCourseAchievedKmSum);

return RunningRecordMonthlySummaryResponseV2.PercentageBoxWithMessage.builder()
.message(String.format(
"%s까지 %s 남았어요!",
currentCourseLog.scale().endName(),
KILO_METER_UNDER_1_POINT_FORMATTER.format(courseSizeKm - currentCourseAchievedKmSum)))
.percentageBox(RunningRecordMonthlySummaryResponseV2.PercentageBox.builder()
.startName(currentCourseLog.scale().startName())
.endName(currentCourseLog.scale().endName())
.percentage(percentage)
.build())
.build();
}

private double calPercentage(double totalRangeValue, double currentValue) {
if (totalRangeValue <= 0) return 0;
return currentValue / totalRangeValue;
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
package com.dnd.runus.presentation.v1.running;

import com.dnd.runus.application.member.MemberService;
import com.dnd.runus.application.running.RunningRecordService;
import com.dnd.runus.domain.level.Level;
import com.dnd.runus.global.exception.type.ApiErrorType;
import com.dnd.runus.global.exception.type.ErrorType;
import com.dnd.runus.presentation.annotation.MemberId;
import com.dnd.runus.presentation.v1.member.dto.response.MyProfileResponse;
import com.dnd.runus.presentation.v1.running.dto.request.RunningRecordRequest;
import com.dnd.runus.presentation.v1.running.dto.request.RunningRecordWeeklySummaryType;
import com.dnd.runus.presentation.v1.running.dto.response.*;
Expand All @@ -23,6 +26,7 @@
@RequestMapping("/api/v1/running-records")
public class RunningRecordController {
private final RunningRecordService runningRecordService;
private final MemberService memberService;

@GetMapping("/{runningRecordId}")
@Operation(summary = "러닝 기록 상세 조회", description = "RunngingRecord id로 러닝 상세 기록을 조회합니다.")
Expand Down Expand Up @@ -76,8 +80,17 @@ public RunningRecordAddResultResponse addRunningRecord(
""")
@ResponseStatus(HttpStatus.OK)
@GetMapping("monthly-summary")
public RunningRecordMonthlySummaryResponse getMonthlyRunningSummary(@MemberId long memberId) {
return runningRecordService.getMonthlyRunningSummery(memberId);
public RunningRecordMonthlySummaryResponseV1 getMonthlyRunningSummary(@MemberId long memberId) {
RunningRecordMonthlySummaryResponse monthlyRunningSummery =
runningRecordService.getMonthlyRunningSummery(memberId);

MyProfileResponse myProfile = memberService.getMyProfile(memberId);

return new RunningRecordMonthlySummaryResponseV1(
monthlyRunningSummery.month(),
monthlyRunningSummery.monthlyTotalMeter(),
Level.formatLevelName(myProfile.nextLevel()),
Level.formatExp(myProfile.nextLevelEndExpMeter() - myProfile.currentExpMeter()));
}

@Operation(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,13 @@
package com.dnd.runus.presentation.v1.running.dto.response;

import static com.dnd.runus.global.constant.MetricsConversionFactor.METERS_IN_A_KILOMETER;

import io.swagger.v3.oas.annotations.media.Schema;

import java.text.DecimalFormat;
import lombok.Builder;

//todo API 버저닝 관련 구조 정해지면 패키지 변경 예쩡
@Builder
public record RunningRecordMonthlySummaryResponse(
@Schema(description = "이번 달", example = "8월")
String month,
@Schema(description = "이번 달에 달린 키로 수", example = "2.55km")
String monthlyKm,
@Schema(description = "다음 레벨", example = "Level 2")
String nextLevelName,
@Schema(description = "다음 레벨까지 남은 키로 수", example = "2.55km")
String nextLevelKm
int month,
int monthlyTotalMeter
) {
private static final DecimalFormat KILO_METER_FORMATTER = new DecimalFormat("0.##km");

public RunningRecordMonthlySummaryResponse(int monthValue, int monthlyTotalMeter, String nextLevelName, String nextLevelKm) {
this(monthValue + "월", KILO_METER_FORMATTER.format(monthlyTotalMeter / METERS_IN_A_KILOMETER), nextLevelName, nextLevelKm);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.dnd.runus.presentation.v1.running.dto.response;

import static com.dnd.runus.global.constant.MetricsConversionFactor.METERS_IN_A_KILOMETER;

import io.swagger.v3.oas.annotations.media.Schema;
import java.text.DecimalFormat;

public record RunningRecordMonthlySummaryResponseV1(
@Schema(description = "이번 달", example = "8월")
String month,
@Schema(description = "이번 달에 달린 키로 수", example = "2.55km")
String monthlyKm,
@Schema(description = "다음 레벨", example = "Level 2")
String nextLevelName,
@Schema(description = "다음 레벨까지 남은 키로 수", example = "2.55km")
String nextLevelKm
) {
private static final DecimalFormat KILO_METER_FORMATTER = new DecimalFormat("0.##km");

public RunningRecordMonthlySummaryResponseV1(int monthValue, int monthlyTotalMeter, String nextLevelName, String nextLevelKm) {
this(monthValue + "월", KILO_METER_FORMATTER.format(monthlyTotalMeter / METERS_IN_A_KILOMETER), nextLevelName, nextLevelKm);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.dnd.runus.presentation.v2.running;

import com.dnd.runus.application.running.RunningRecordService;
import com.dnd.runus.application.running.RunningRecordServiceV2;
import com.dnd.runus.presentation.annotation.MemberId;
import com.dnd.runus.presentation.v1.running.dto.response.RunningRecordMonthlySummaryResponse;
import com.dnd.runus.presentation.v2.running.dto.response.RunningRecordMonthlySummaryResponseV2;
import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v2/running-records")
public class RunningRecordControllerV2 {
private final RunningRecordServiceV2 runningRecordService2;
private final RunningRecordService runningRecordService;

@Operation(summary = "이번 달 러닝 기록 조회(홈화면) V2", description = """
홈화면의 이번 달 러닝 기록을 조회 합니다.<br>
""")
@ResponseStatus(HttpStatus.OK)
@GetMapping("monthly-summary")
public RunningRecordMonthlySummaryResponseV2 getMonthlyRunningSummary(@MemberId long memberId) {
RunningRecordMonthlySummaryResponse monthlyRunningSummery =
runningRecordService.getMonthlyRunningSummery(memberId);
return new RunningRecordMonthlySummaryResponseV2(
monthlyRunningSummery.month(),
monthlyRunningSummery.monthlyTotalMeter(),
runningRecordService2.getPercentageValues(memberId));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package com.dnd.runus.presentation.v2.running.dto.response;


import static com.dnd.runus.global.constant.MetricsConversionFactor.METERS_IN_A_KILOMETER;

import io.swagger.v3.oas.annotations.media.Schema;
import java.text.DecimalFormat;
import lombok.Builder;


public record RunningRecordMonthlySummaryResponseV2(
@Schema(description = "이번 달", example = "8월")
String month,
@Schema(description = "이번 달에 달린 키로 수", example = "2.55km")
String monthlyKm,
@Schema(description = "서브 메세지", example = "대전까지 00km 남았어요!")
String message,
@Schema(description = "퍼센테이지 시작 위치 이름", example = "인천")
String startName,
@Schema(description = "퍼센테이지 종료 위치 이름", example = "대전")
String endName,
@Schema(description = "퍼센테이지값", example = "0.728")
double percentage
) {

private static final DecimalFormat KILO_METER_FORMATTER = new DecimalFormat("#,###.##km");

public RunningRecordMonthlySummaryResponseV2(
int monthValue,
int monthlyTotalMeter,
PercentageBoxWithMessage percentageBoxWithMessage) {
this(
monthValue + "월",
KILO_METER_FORMATTER.format(monthlyTotalMeter / METERS_IN_A_KILOMETER),
percentageBoxWithMessage.message,
percentageBoxWithMessage.percentageBox.startName,
percentageBoxWithMessage.percentageBox.endName,
percentageBoxWithMessage.percentageBox.percentage
);
}

@Schema(name = "RunningRecordMonthlySummaryResponseV2 PercentageBox",
description = "이번달 러닝 서머리 퍼센테이지 관련 값")
@Builder
public record PercentageBox(
String startName,
String endName,
double percentage
) {
}

@Builder
public record PercentageBoxWithMessage(
String message,
RunningRecordMonthlySummaryResponseV2.PercentageBox percentageBox
) {
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,7 @@
import com.dnd.runus.domain.common.Pace;
import com.dnd.runus.domain.goalAchievement.GoalAchievement;
import com.dnd.runus.domain.goalAchievement.GoalAchievementRepository;
import com.dnd.runus.domain.level.Level;
import com.dnd.runus.domain.member.Member;
import com.dnd.runus.domain.member.MemberLevel;
import com.dnd.runus.domain.member.MemberLevelRepository;
import com.dnd.runus.domain.member.MemberRepository;
import com.dnd.runus.domain.running.DailyRunningRecordSummary;
import com.dnd.runus.domain.running.RunningRecord;
Expand Down Expand Up @@ -60,9 +57,6 @@ class RunningRecordServiceTest {
@Mock
private MemberRepository memberRepository;

@Mock
private MemberLevelRepository memberLevelRepository;

@Mock
private ChallengeRepository challengeRepository;

Expand All @@ -85,7 +79,6 @@ void setUp() {
runningRecordService = new RunningRecordService(
runningRecordRepository,
memberRepository,
memberLevelRepository,
challengeRepository,
challengeAchievementRepository,
percentageValuesRepository,
Expand Down Expand Up @@ -416,7 +409,7 @@ void addRunningRecord_check_cal_pace() {
}

@Test
@DisplayName("이번 달, 달린 키로 수, 러닝 레벨을 조회한다.")
@DisplayName("이번 달, 달린 키로수를 조회한다.")
void getMonthlyRunningSummery() {
// given
long memberId = 1;
Expand All @@ -430,19 +423,14 @@ void getMonthlyRunningSummery() {
given(runningRecordRepository.findTotalDistanceMeterByMemberIdWithRangeDate(eq(memberId), any(), any()))
.willReturn(45_780);

given(memberLevelRepository.findByMemberIdWithLevel(memberId))
.willReturn(new MemberLevel.Current(new Level(1, 0, 50_000, "image"), 45_780));

// when
RunningRecordMonthlySummaryResponse monthlyRunningSummery =
runningRecordService.getMonthlyRunningSummery(memberId);

// then
assertNotNull(monthlyRunningSummery);
assertThat(monthlyRunningSummery.month()).isEqualTo("1월");
assertThat(monthlyRunningSummery.monthlyKm()).isEqualTo("45.78km");
assertThat(monthlyRunningSummery.nextLevelName()).isEqualTo("Level 2");
assertThat(monthlyRunningSummery.nextLevelKm()).isEqualTo("4.22km");
assertThat(monthlyRunningSummery.month()).isEqualTo(1);
assertThat(monthlyRunningSummery.monthlyTotalMeter()).isEqualTo(45_780);
}
}

Expand Down