Skip to content

Commit

Permalink
Merge pull request #302 from Team-Sopetit/feat/#284-challenge-routine
Browse files Browse the repository at this point in the history
[FEAT] 도전 루틴 목록 조회
  • Loading branch information
Chan531 authored Jun 28, 2024
2 parents 335d317 + 745b34a commit 4cf8a18
Show file tree
Hide file tree
Showing 14 changed files with 406 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public class ValueConfig {
public static final int MIN_COTTON_COUNT = 0;
public static final int DAILY_ROUTINE_MAX_COUNT = 3;
public static final String MEMBER_DOLL_CONDITION = "^[ㄱ-ㅎㅏ-ㅣ가-힣a-zA-Z]{1,10}$";
public static final long MEMBER_HAS_NOT_CHALLENGE = 0;

@PostConstruct
protected void init() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,24 @@
import com.soptie.server.routine.entity.Challenge;
import com.soptie.server.theme.entity.Theme;

import lombok.NonNull;

public record MemberChallengeResponse(
Long id,
String routineContent,
String content,
String description,
String place,
String requiredTime,
Theme theme
long id,
long challengeId,
@NonNull String routineContent,
@NonNull String content,
@NonNull String description,
@NonNull String place,
@NonNull String requiredTime,
@NonNull Theme theme
) {

@QueryProjection
public MemberChallengeResponse(MemberRoutine memberRoutine, Challenge challenge, Theme theme) {
this(
memberRoutine.getId(),
challenge.getId(),
challenge.getRoutine().getContent(),
challenge.getContent(),
challenge.getDescription(),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.soptie.server.routine.adapter;

import static com.soptie.server.routine.message.RoutineErrorCode.*;
import static com.soptie.server.routine.message.RoutineErrorCode.INVALID_ROUTINE;

import java.util.List;

Expand All @@ -9,6 +9,7 @@
import com.soptie.server.routine.entity.Routine;
import com.soptie.server.routine.exception.RoutineException;
import com.soptie.server.routine.repository.ChallengeRepository;
import com.soptie.server.routine.service.vo.ChallengeVO;

import lombok.RequiredArgsConstructor;

Expand All @@ -23,7 +24,7 @@ public Challenge findById(long id) {
.orElseThrow(() -> new RoutineException(INVALID_ROUTINE));
}

public List<Challenge> findByRoutine(Routine routine) {
return challengeRepository.findByRoutine(routine);
public List<ChallengeVO> findByRoutine(Routine routine) {
return challengeRepository.findByRoutine(routine).stream().map(ChallengeVO::from).toList();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.soptie.server.routine.controller.v2;

import java.security.Principal;

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 com.soptie.server.common.dto.SuccessResponse;
import com.soptie.server.routine.controller.v2.docs.ChallengeRoutineControllerV2Docs;
import com.soptie.server.routine.controller.v2.dto.response.ChallengeRoutineListAcquireResponseV2;
import com.soptie.server.routine.message.RoutineSuccessMessage;
import com.soptie.server.routine.service.RoutineService;

import lombok.RequiredArgsConstructor;
import lombok.val;

@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v2/routines/challenge")
public class ChallengeRoutineControllerV2 implements ChallengeRoutineControllerV2Docs {

private final RoutineService routineService;

@GetMapping
public ResponseEntity<SuccessResponse<ChallengeRoutineListAcquireResponseV2>> acquireAllByTheme(
Principal principal,
@RequestParam long themeId
) {
val memberId = Long.parseLong(principal.getName());
val response = routineService.acquireAllInChallengeWithThemeId(memberId, themeId);
return ResponseEntity.ok(SuccessResponse.success(
RoutineSuccessMessage.SUCCESS_GET_CHALLENGE_ROUTINE.getMessage(),
ChallengeRoutineListAcquireResponseV2.from(response)));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package com.soptie.server.routine.controller.v2.docs;

import java.security.Principal;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestParam;

import com.soptie.server.common.dto.ErrorResponse;
import com.soptie.server.common.dto.SuccessResponse;
import com.soptie.server.routine.controller.v2.dto.response.ChallengeRoutineListAcquireResponseV2;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.enums.ParameterIn;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.tags.Tag;

@Tag(name = "challenge routines V2", description = "도전 루틴 API Version2")
public interface ChallengeRoutineControllerV2Docs {

@Operation(
summary = "테마별 도전 루틴 목록 조회",
description = "테마에 해당되는 도전 루틴 목록을 조회한다.",
responses = {
@ApiResponse(responseCode = "200", description = "성공"),
@ApiResponse(
responseCode = "4xx",
description = "클라이언트(요청) 오류",
content = @Content(schema = @Schema(implementation = ErrorResponse.class))),
@ApiResponse(
responseCode = "500",
description = "서버 내부 오류",
content = @Content(schema = @Schema(implementation = ErrorResponse.class)))}
)
ResponseEntity<SuccessResponse<ChallengeRoutineListAcquireResponseV2>> acquireAllByTheme(
@Parameter(hidden = true) Principal principal,
@Parameter(
name = "themeId",
description = "조회할 도전 루틴 테마 id",
in = ParameterIn.QUERY,
example = "1"
) @RequestParam long themeId
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.soptie.server.routine.controller.v2.dto.response;

import java.util.List;
import java.util.Map;

import com.soptie.server.routine.service.dto.response.ChallengeRoutineListAcquireServiceResponse;

import lombok.AccessLevel;
import lombok.Builder;
import lombok.NonNull;

@Builder(access = AccessLevel.PRIVATE)
public record ChallengeRoutineListAcquireResponseV2(
@NonNull List<RoutineResponse> routines
) {

public static ChallengeRoutineListAcquireResponseV2 from(
Map<String, ChallengeRoutineListAcquireServiceResponse> challengesMap
) {
return ChallengeRoutineListAcquireResponseV2.builder()
.routines(challengesMap.keySet()
.stream()
.map(key -> RoutineResponse.from(key, challengesMap.get(key)))
.toList())
.build();
}

@Builder(access = AccessLevel.PRIVATE)
private record RoutineResponse(
@NonNull String title,
@NonNull List<ChallengeResponse> challenges
) {

private static RoutineResponse from(String title, ChallengeRoutineListAcquireServiceResponse challenges) {
return RoutineResponse.builder()
.title(title)
.challenges(challenges.challenges().stream().map(ChallengeResponse::from).toList())
.build();
}
}

@Builder(access = AccessLevel.PRIVATE)
private record ChallengeResponse(
long challengeId,
@NonNull String content,
@NonNull String description,
@NonNull String requiredTime,
@NonNull String place,
boolean hasRoutine
) {

private static ChallengeResponse from(
ChallengeRoutineListAcquireServiceResponse.ChallengeRoutineAcquireResponse challenge) {
return ChallengeResponse.builder()
.challengeId(challenge.challenge().challengeId())
.content(challenge.challenge().content())
.description(challenge.challenge().description())
.requiredTime(challenge.challenge().requiredTime())
.place(challenge.challenge().place())
.hasRoutine(challenge.hasRoutine())
.build();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public enum RoutineSuccessMessage {

SUCCESS_GET_ROUTINE("데일리 루틴 조회 성공"),
SUCCESS_GET_HAPPINESS_ROUTINE("행복 루틴 조회 성공"),
SUCCESS_GET_CHALLENGE_ROUTINE("도전 루틴 조회 성공"),
SUCCESS_GET_HAPPINESS_SUB_ROUTINES("행복 루틴 별 서브 루틴 리스트 조회 성공");

private final String message;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.soptie.server.routine.service;

import static com.soptie.server.common.config.ValueConfig.MEMBER_HAS_NOT_CHALLENGE;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
Expand All @@ -9,13 +11,17 @@
import org.springframework.transaction.annotation.Transactional;

import com.soptie.server.member.adapter.MemberFinder;
import com.soptie.server.member.entity.Member;
import com.soptie.server.memberroutine.adapter.MemberRoutineFinder;
import com.soptie.server.memberroutine.repository.dto.MemberChallengeResponse;
import com.soptie.server.routine.adapter.ChallengeFinder;
import com.soptie.server.routine.adapter.RoutineFinder;
import com.soptie.server.routine.entity.RoutineType;
import com.soptie.server.routine.service.dto.request.DailyRoutineListByThemeGetServiceRequest;
import com.soptie.server.routine.service.dto.request.DailyRoutineListByThemesGetServiceRequest;
import com.soptie.server.routine.service.dto.request.HappinessRoutineListGetServiceRequest;
import com.soptie.server.routine.service.dto.request.HappinessSubRoutineListGetServiceRequest;
import com.soptie.server.routine.service.dto.response.ChallengeRoutineListAcquireServiceResponse;
import com.soptie.server.routine.service.dto.response.DailyRoutineListGetServiceResponse;
import com.soptie.server.routine.service.dto.response.HappinessRoutineListGetServiceResponse;
import com.soptie.server.routine.service.dto.response.HappinessSubRoutineListGetServiceResponse;
Expand All @@ -34,6 +40,7 @@ public class RoutineService {
private final ThemeFinder themeFinder;
private final MemberFinder memberFinder;
private final ChallengeFinder challengeFinder;
private final MemberRoutineFinder memberRoutineFinder;

public DailyRoutineListGetServiceResponse getRoutinesByThemes(DailyRoutineListByThemesGetServiceRequest request) {
val routines = routineFinder.findDailyRoutinesByThemeIds(request.themeIds());
Expand Down Expand Up @@ -70,4 +77,24 @@ public Map<Long, List<RoutineVO>> acquireAllInDailyWithThemeId(Set<Long> themeId
}
return themeToRoutine;
}

public Map<String, ChallengeRoutineListAcquireServiceResponse> acquireAllInChallengeWithThemeId(long memberId,
long themeId) {
themeFinder.isExistById(themeId);
val member = memberFinder.findById(memberId);
val challengeIdByMember = getChallengeIdByMember(member);
val challengeRoutinesByTheme = routineFinder.findChallengeRoutinesByTheme(themeId);
val themeToChallenge = new LinkedHashMap<String, ChallengeRoutineListAcquireServiceResponse>();
for (val routine : challengeRoutinesByTheme) {
val challenges = challengeFinder.findByRoutine(routine);
themeToChallenge.put(routine.getContent(),
ChallengeRoutineListAcquireServiceResponse.of(challenges, challengeIdByMember));
}
return themeToChallenge;
}

private long getChallengeIdByMember(Member member) {
val challengeByMember = memberRoutineFinder.findChallengeByMember(member);
return challengeByMember.map(MemberChallengeResponse::challengeId).orElse(MEMBER_HAS_NOT_CHALLENGE);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.soptie.server.routine.service.dto.response;

import static lombok.AccessLevel.PRIVATE;

import java.util.List;

import com.soptie.server.routine.service.vo.ChallengeVO;

import lombok.Builder;
import lombok.NonNull;

@Builder(access = PRIVATE)
public record ChallengeRoutineListAcquireServiceResponse(
@NonNull List<ChallengeRoutineAcquireResponse> challenges
) {

public static ChallengeRoutineListAcquireServiceResponse of(List<ChallengeVO> challenges, long challengeId) {
return ChallengeRoutineListAcquireServiceResponse.builder()
.challenges(challenges.stream()
.map(challenge -> ChallengeRoutineAcquireResponse.of(challenge, challengeId))
.toList())
.build();
}

@Builder(access = PRIVATE)
public record ChallengeRoutineAcquireResponse(
ChallengeVO challenge,
boolean hasRoutine
) {

public static ChallengeRoutineAcquireResponse of(ChallengeVO challenge, long challengeId) {
return ChallengeRoutineAcquireResponse.builder()
.challenge(challenge)
.hasRoutine(challenge.challengeId() == challengeId)
.build();
}
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package com.soptie.server.routine.service.dto.response;

import static lombok.AccessLevel.*;
import static lombok.AccessLevel.PRIVATE;

import java.util.List;

import com.soptie.server.routine.entity.Challenge;
import com.soptie.server.routine.entity.Routine;
import com.soptie.server.routine.service.vo.ChallengeVO;

import lombok.Builder;

Expand All @@ -16,7 +16,7 @@ public record HappinessSubRoutineListGetServiceResponse(
List<HappinessSubRoutineServiceResponse> challenges
) {

public static HappinessSubRoutineListGetServiceResponse of(Routine routine, List<Challenge> challenges) {
public static HappinessSubRoutineListGetServiceResponse of(Routine routine, List<ChallengeVO> challenges) {
return HappinessSubRoutineListGetServiceResponse.builder()
.routineContent(routine.getContent())
.themeName(routine.getTheme().getName())
Expand All @@ -33,13 +33,13 @@ public record HappinessSubRoutineServiceResponse(
String requiredTime, String place
) {

private static HappinessSubRoutineServiceResponse of(Challenge challenge) {
private static HappinessSubRoutineServiceResponse of(ChallengeVO challenge) {
return HappinessSubRoutineServiceResponse.builder()
.challengeId(challenge.getId())
.content(challenge.getContent())
.description(challenge.getDescription())
.requiredTime(challenge.getRequiredTime())
.place(challenge.getPlace())
.challengeId(challenge.challengeId())
.content(challenge.content())
.description(challenge.description())
.requiredTime(challenge.requiredTime())
.place(challenge.place())
.build();
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.soptie.server.routine.service.vo;

import com.soptie.server.routine.entity.Challenge;

import lombok.AccessLevel;
import lombok.Builder;
import lombok.NonNull;

@Builder(access = AccessLevel.PRIVATE)
public record ChallengeVO(
long challengeId,
@NonNull String content,
@NonNull String description,
@NonNull String requiredTime,
@NonNull String place
) {

public static ChallengeVO from(Challenge challenge) {
return ChallengeVO.builder()
.challengeId(challenge.getId())
.content(challenge.getContent())
.description(challenge.getDescription())
.requiredTime(challenge.getRequiredTime())
.place(challenge.getPlace())
.build();
}
}
Loading

0 comments on commit 4cf8a18

Please sign in to comment.