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

Refactor: 챌린지 조회 시 챌린지 목표 값까지 같이 리턴할 수 있게 수정 #318

Merged
merged 5 commits into from
Dec 11, 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
@@ -1,17 +1,18 @@
package com.dnd.runus.application.challenge;

import com.dnd.runus.domain.challenge.ChallengeRepository;
import com.dnd.runus.domain.challenge.ChallengeWithCondition;
import com.dnd.runus.domain.running.RunningRecord;
import com.dnd.runus.domain.running.RunningRecordRepository;
import com.dnd.runus.presentation.v1.challenge.dto.response.ChallengesResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;

import static com.dnd.runus.global.constant.TimeConstant.SERVER_TIMEZONE_ID;

Expand All @@ -23,28 +24,37 @@ public class ChallengeService {

private final RunningRecordRepository runningRecordRepository;

public List<ChallengesResponse> getChallenges(long memberId) {
public List<ChallengeWithCondition> getChallenges(long memberId) {
OffsetDateTime todayMidnight = LocalDate.now(SERVER_TIMEZONE_ID)
.atStartOfDay(SERVER_TIMEZONE_ID)
.toOffsetDateTime();
OffsetDateTime yesterday = todayMidnight.minusDays(1);

List<ChallengesResponse> challengesResponses;
// 어제 기록이 없으면
if (!runningRecordRepository.hasByMemberIdAndStartAtBetween(memberId, yesterday, todayMidnight)) {
challengesResponses = challengeRepository.findAllIsNotDefeatYesterday().stream()
.map(ChallengesResponse::from)
.collect(Collectors.toList());
List<RunningRecord> runningRecords =
runningRecordRepository.findByMemberIdAndStartAtBetween(memberId, yesterday, todayMidnight);

List<ChallengeWithCondition> allChallengesWithConditions =
new ArrayList<>(challengeRepository.findAllActiveChallengesWithConditions());

// 어제 기록이 없으면 어제 기록과 관련된 챌린지 삭제
if (runningRecords.isEmpty()) {
allChallengesWithConditions.removeIf(
challengeWithCondition -> challengeWithCondition.challenge().isDefeatYesterdayChallenge());
} else {
challengesResponses = challengeRepository.findAllChallenges().stream()
.map(ChallengesResponse::from)
.collect(Collectors.toList());
// 어제의 기록과 관련된 챌린지면, 챌린지 비교할 값(성공 유무를 위한 목표 값) 재등록
allChallengesWithConditions.stream()
.filter(challengeWithCondition ->
challengeWithCondition.challenge().isDefeatYesterdayChallenge())
.forEach(challengeWithCondition -> challengeWithCondition
.conditions()
.forEach(condition -> condition.registerComparisonValue(
condition.goalMetricType().getActualValue(runningRecords.getFirst()))));
}

// 랜덤으로 2개 리턴
Random randomWithSeed = new Random(todayMidnight.toEpochSecond());
Collections.shuffle(challengesResponses, randomWithSeed);
Collections.shuffle(allChallengesWithConditions, randomWithSeed);

return challengesResponses.subList(0, 2);
return allChallengesWithConditions.subList(0, 2);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,6 @@
import java.util.Optional;

public interface ChallengeRepository {
List<Challenge> findAllChallenges();

List<Challenge> findAllIsNotDefeatYesterday();

List<ChallengeWithCondition> findAllActiveChallengesWithConditions();

Optional<ChallengeWithCondition> findChallengeWithConditionsByChallengeId(long challengeId);
Expand Down
12 changes: 12 additions & 0 deletions src/main/java/com/dnd/runus/domain/challenge/GoalMetricType.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.dnd.runus.domain.challenge;

import com.dnd.runus.domain.running.RunningRecord;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import lombok.RequiredArgsConstructor;

/**
Expand Down Expand Up @@ -30,4 +32,14 @@ public int getActualValue(RunningRecord record) {
case PACE -> record.averagePace().toSeconds();
};
}

@JsonCreator
public GoalMetricType fromString(String value) {
return GoalMetricType.valueOf(value.toUpperCase());
}

@JsonValue
public String toJson() {
return this.name().toLowerCase();
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
package com.dnd.runus.infrastructure.persistence.domain.challenge;

import com.dnd.runus.domain.challenge.Challenge;
import com.dnd.runus.domain.challenge.ChallengeRepository;
import com.dnd.runus.domain.challenge.ChallengeWithCondition;
import com.dnd.runus.infrastructure.persistence.jooq.challenge.JooqChallengeRepository;
import com.dnd.runus.infrastructure.persistence.jpa.challenge.JpaChallengeRepository;
import com.dnd.runus.infrastructure.persistence.jpa.challenge.entity.ChallengeEntity;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;

Expand All @@ -17,19 +14,6 @@
public class ChallengeRepositoryImpl implements ChallengeRepository {

private final JooqChallengeRepository jooqChallengeRepository;
private final JpaChallengeRepository jpaChallengeRepository;

@Override
public List<Challenge> findAllChallenges() {
return jpaChallengeRepository.findAll().stream()
.map(ChallengeEntity::toDomain)
.toList();
}

@Override
public List<Challenge> findAllIsNotDefeatYesterday() {
return jooqChallengeRepository.findAllIsNotDefeatYesterday();
}

@Override
public List<ChallengeWithCondition> findAllActiveChallengesWithConditions() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,6 @@ public class JooqChallengeRepository {

private final DSLContext dsl;

public List<Challenge> findAllIsNotDefeatYesterday() {
return dsl.select(
CHALLENGE.ID,
CHALLENGE.NAME,
CHALLENGE.EXPECTED_TIME,
CHALLENGE.IMAGE_URL,
CHALLENGE.IS_ACTIVE,
CHALLENGE.CHALLENGE_TYPE)
.from(CHALLENGE)
.where(CHALLENGE.CHALLENGE_TYPE.ne(ChallengeType.DEFEAT_YESTERDAY.toString()))
.fetch(new ChallengeMapper());
}

public ChallengeWithCondition findChallengeWithConditionsBy(long challengeId) {
return dsl.select(
CHALLENGE.ID,
Expand Down Expand Up @@ -86,20 +73,6 @@ public List<ChallengeWithCondition> findAllActiveChallengesWithConditions() {
.fetch(new ChallengeWithConditionMapper());
}

private static class ChallengeMapper implements RecordMapper<Record, Challenge> {

@Override
public Challenge map(Record record) {
return new Challenge(
record.get(CHALLENGE.ID, long.class),
record.get(CHALLENGE.NAME, String.class),
record.get(CHALLENGE.EXPECTED_TIME, int.class),
record.get(CHALLENGE.IMAGE_URL, String.class),
record.get(CHALLENGE.IS_ACTIVE, Boolean.class),
record.get(CHALLENGE.CHALLENGE_TYPE, ChallengeType.class));
}
}

private static class ChallengeWithConditionMapper implements RecordMapper<Record, ChallengeWithCondition> {
@Override
public ChallengeWithCondition map(Record record) {
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
Expand All @@ -21,21 +20,22 @@
@RequestMapping("/api/v1/challenges")
public class ChallengeController {

@Autowired
private final ChallengeService challengeService;

@Operation(
summary = "오늘의 챌린지 리스트 조회",
description =
"""
## 오늘의 챌린지 리스트를 조회합니다.
- 챌린지가 페이스와 관련된 경우 응답의 예상 소요 시간은 0으로 리턴됩니다.
- 사용자가 어제의 러닝 기록이 없는 경우 : 어제의 기록과 관련된 챌린지는 제외하고 반환합니다.
- 사용자가 어제의 러닝 기록이 있는 경우 : 모든 챌린지를 반환합니다.
""")
## 오늘의 챌린지 리스트를 조회합니다.
- 챌린지가 페이스와 관련된 경우 응답의 예상 소요 시간은 0으로 리턴됩니다.
- 사용자가 어제의 러닝 기록이 없는 경우 : 어제의 기록과 관련된 챌린지는 제외하고 반환합니다.
- 사용자가 어제의 러닝 기록이 있는 경우 : 모든 챌린지를 반환합니다., 챌린지 목표 값은 (어제 사용자 기록 + 목표값) 으로 반환됩니다.
""")
@GetMapping
@ResponseStatus(HttpStatus.OK)
public List<ChallengesResponse> getChallenges(@MemberId long memberId) {
return challengeService.getChallenges(memberId);
return challengeService.getChallenges(memberId).stream()
.map(ChallengesResponse::from)
.toList();
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
package com.dnd.runus.presentation.v1.challenge.dto.response;


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

import com.dnd.runus.domain.challenge.Challenge;
import com.dnd.runus.domain.challenge.ChallengeCondition;
import com.dnd.runus.domain.challenge.ChallengeWithCondition;
import com.dnd.runus.domain.challenge.GoalMetricType;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.annotation.Nullable;
import java.util.List;
import org.jetbrains.annotations.NotNull;

public record ChallengesResponse(
Expand All @@ -19,14 +26,35 @@ public record ChallengesResponse(
String expectedTime,
@Schema(description = "챌린지 이미지 URL")
@NotNull
String icon
String icon,
@Schema(description = "챌린지 타입 : distance, time", example = "distance")
GoalMetricType type,
@Nullable
@Schema(description = "챌린지 목표 거리(단위:km)", example = "5.0")
Double goalDistance,
@Nullable
@Schema(description = "챌린지 목표 시간(단위:초)")
Integer goalTime
) {
public static ChallengesResponse from(Challenge challenge) {
public static ChallengesResponse from(ChallengeWithCondition challengeWithCondition) {
Challenge challenge = challengeWithCondition.challenge();
List<ChallengeCondition> conditions = challengeWithCondition.conditions();

//현재는 복합 챌린지(페이스 + 거리 +..)가 없어 getFirst로 가져옵니다.
//추후 페이스 관련 챌린지가 추가 되면 변경될 수 있습니다.
ChallengeCondition condition = conditions.getFirst();
return new ChallengesResponse(
challenge.challengeId(),
challenge.name(),
challenge.formatExpectedTime(),
challenge.imageUrl()
challenge.imageUrl(),
condition.goalMetricType(),
condition.goalMetricType().equals(GoalMetricType.DISTANCE) ? calMeterToKm(condition.goalValue()) : null,
condition.goalMetricType().equals(GoalMetricType.TIME) ? condition.goalValue() : null
);
}

private static double calMeterToKm(int meter) {
return meter / METERS_IN_A_KILOMETER;
}
}
Loading