diff --git a/smeem-api/src/main/java/com/smeem/api/member/api/MemberApi.java b/smeem-api/src/main/java/com/smeem/api/member/api/MemberApi.java index f28f1154..ea0fbae1 100644 --- a/smeem-api/src/main/java/com/smeem/api/member/api/MemberApi.java +++ b/smeem-api/src/main/java/com/smeem/api/member/api/MemberApi.java @@ -93,4 +93,21 @@ public interface MemberApi { ResponseEntity> getPerformanceSummary( @Parameter(hidden = true) Principal principal ); + + @Operation(summary = "사용자 플랜 조회 API") + @Parameter(name = "Authorization", description = "Bearer ${Smeme Access Token}", in = HEADER, required = true) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "요청 성공"), + @ApiResponse( + responseCode = "401", + description = "유효하지 않은 토큰", + content = @Content(schema = @Schema(implementation = FailureResponse.class)) + ), + @ApiResponse( + responseCode = "500", + description = "서버 내부 오류", + content = @Content(schema = @Schema(implementation = FailureResponse.class)) + ) + }) + ResponseEntity getMemberPlan(@Parameter(hidden = true) Principal principal); } diff --git a/smeem-api/src/main/java/com/smeem/api/member/api/MemberController.java b/smeem-api/src/main/java/com/smeem/api/member/api/MemberController.java index ac6a2da8..db34b192 100644 --- a/smeem-api/src/main/java/com/smeem/api/member/api/MemberController.java +++ b/smeem-api/src/main/java/com/smeem/api/member/api/MemberController.java @@ -1,19 +1,13 @@ package com.smeem.api.member.api; -import com.smeem.api.member.api.dto.response.MemberPerformanceGetResponse; -import com.smeem.api.member.service.dto.request.MemberPerformanceGetServiceRequest; +import com.smeem.api.member.api.dto.response.*; +import com.smeem.api.member.service.dto.request.*; import com.smeem.api.support.ApiResponseGenerator; import com.smeem.api.common.SuccessResponse; import com.smeem.api.member.api.dto.request.MemberPlanUpdateRequest; import com.smeem.api.member.api.dto.request.MemberPushUpdateRequest; import com.smeem.api.member.api.dto.request.MemberUpdateRequest; -import com.smeem.api.member.api.dto.response.MemberGetResponse; -import com.smeem.api.member.api.dto.response.MemberNameResponse; -import com.smeem.api.member.api.dto.response.MemberUpdateResponse; import com.smeem.api.member.service.MemberService; -import com.smeem.api.member.service.dto.request.MemberPushUpdateServiceRequest; -import com.smeem.api.member.service.dto.request.MemberUpdatePlanServiceRequest; -import com.smeem.api.member.service.dto.request.MemberServiceUpdateUserProfileRequest; import com.smeem.api.support.PrincipalConverter; import io.swagger.v3.oas.annotations.Parameter; import jakarta.validation.Valid; @@ -81,4 +75,14 @@ public ResponseEntity> getPerforma return ApiResponseGenerator.success(SUCCESS_GET_PERFORMANCE_SUMMARY, response); } + @Override + @GetMapping("/plan") + public ResponseEntity getMemberPlan(Principal principal) { + val memberId = PrincipalConverter.getMemberId(principal); + val response = memberService.getMemberPlan(MemberPlanGetServiceRequest.of(memberId)) + .map(MemberPlanGetResponse::of) + .orElse(null); + return ApiResponseGenerator.success(SUCCESS_GET_PLAN, response); + } + } diff --git a/smeem-api/src/main/java/com/smeem/api/member/api/dto/response/MemberPlanGetResponse.java b/smeem-api/src/main/java/com/smeem/api/member/api/dto/response/MemberPlanGetResponse.java new file mode 100644 index 00000000..95e3f8e9 --- /dev/null +++ b/smeem-api/src/main/java/com/smeem/api/member/api/dto/response/MemberPlanGetResponse.java @@ -0,0 +1,24 @@ +package com.smeem.api.member.api.dto.response; + +import com.smeem.api.member.service.dto.response.MemberPlanGetServiceResponse; +import lombok.Builder; + +import static lombok.AccessLevel.PRIVATE; + +@Builder(access = PRIVATE) +public record MemberPlanGetResponse( + String plan, + String goal, + int clearedCount, + int clearCount +) { + + public static MemberPlanGetResponse of(MemberPlanGetServiceResponse response) { + return MemberPlanGetResponse.builder() + .plan(response.plan().content()) + .goal(response.goal().goalType().getDescription()) + .clearedCount(response.plan().clearedCount()) + .clearCount(response.plan().clearCount()) + .build(); + } +} diff --git a/smeem-api/src/main/java/com/smeem/api/member/service/MemberService.java b/smeem-api/src/main/java/com/smeem/api/member/service/MemberService.java index bf280132..5fdc58cb 100644 --- a/smeem-api/src/main/java/com/smeem/api/member/service/MemberService.java +++ b/smeem-api/src/main/java/com/smeem/api/member/service/MemberService.java @@ -4,11 +4,7 @@ import com.smeem.api.badge.service.dto.response.BadgeServiceResponse; import com.smeem.api.goal.service.GoalService; import com.smeem.api.goal.service.dto.request.GoalGetServiceRequest; -import com.smeem.api.member.service.dto.request.MemberPerformanceGetServiceRequest; -import com.smeem.api.member.service.dto.request.MemberPushUpdateServiceRequest; -import com.smeem.api.member.service.dto.request.MemberServiceUpdateUserProfileRequest; -import com.smeem.api.member.service.dto.request.MemberUpdatePlanServiceRequest; -import com.smeem.api.member.service.dto.request.TrainingTimeServiceRequest; +import com.smeem.api.member.service.dto.request.*; import com.smeem.api.member.service.dto.response.*; import com.smeem.common.config.ValueConfig; import com.smeem.domain.badge.adapter.BadgeFinder; @@ -29,6 +25,8 @@ import java.util.ArrayList; import java.util.List; +import java.util.Objects; +import java.util.Optional; import java.util.stream.Collectors; import static com.smeem.common.code.failure.MemberFailureCode.DUPLICATE_USERNAME; @@ -111,6 +109,13 @@ public MemberPerformanceGetServiceResponse getPerformanceSummary(final MemberPer return MemberPerformanceGetServiceResponse.of(member); } + public Optional getMemberPlan(final MemberPlanGetServiceRequest request) { + val member = memberFinder.findById(request.memberId()); + return Objects.nonNull(member.getPlan()) + ? Optional.of(MemberPlanGetServiceResponse.of(member)) + : Optional.empty(); + } + private void updateTrainingTime(Member member, TrainingTimeServiceRequest request) { if (nonNull(request) && StringUtils.hasText(request.day())) { trainingTimeService.deleteAll(member); diff --git a/smeem-api/src/main/java/com/smeem/api/member/service/dto/request/MemberPlanGetServiceRequest.java b/smeem-api/src/main/java/com/smeem/api/member/service/dto/request/MemberPlanGetServiceRequest.java new file mode 100644 index 00000000..f6d85e72 --- /dev/null +++ b/smeem-api/src/main/java/com/smeem/api/member/service/dto/request/MemberPlanGetServiceRequest.java @@ -0,0 +1,17 @@ +package com.smeem.api.member.service.dto.request; + +import lombok.Builder; + +import static lombok.AccessLevel.PRIVATE; + +@Builder(access = PRIVATE) +public record MemberPlanGetServiceRequest( + long memberId +) { + + public static MemberPlanGetServiceRequest of(long memberId) { + return MemberPlanGetServiceRequest.builder() + .memberId(memberId) + .build(); + } +} diff --git a/smeem-api/src/main/java/com/smeem/api/member/service/dto/response/MemberPlanGetServiceResponse.java b/smeem-api/src/main/java/com/smeem/api/member/service/dto/response/MemberPlanGetServiceResponse.java new file mode 100644 index 00000000..f3dac797 --- /dev/null +++ b/smeem-api/src/main/java/com/smeem/api/member/service/dto/response/MemberPlanGetServiceResponse.java @@ -0,0 +1,52 @@ +package com.smeem.api.member.service.dto.response; + +import com.smeem.domain.goal.model.GoalType; +import com.smeem.domain.member.model.Member; +import lombok.Builder; +import lombok.val; + +import static lombok.AccessLevel.PRIVATE; + +@Builder(access = PRIVATE) +public record MemberPlanGetServiceResponse( + MemberGoalServiceResponse goal, + MemberPlanServiceResponse plan +) { + + public static MemberPlanGetServiceResponse of(Member member) { + return MemberPlanGetServiceResponse.builder() + .goal(MemberGoalServiceResponse.of(member)) + .plan(MemberPlanServiceResponse.of(member)) + .build(); + } + + @Builder(access = PRIVATE) + public record MemberPlanServiceResponse( + String content, + int clearCount, + int clearedCount + ) { + + private static MemberPlanServiceResponse of(Member member) { + val plan = member.getPlan(); + return MemberPlanServiceResponse.builder() + .content(plan.getContent()) + .clearCount(plan.getClearCount()) + .clearedCount(member.getDiaryCountInWeek()) + .build(); + } + } + + @Builder(access = PRIVATE) + public record MemberGoalServiceResponse( + GoalType goalType + ) { + + private static MemberGoalServiceResponse of(Member member) { + val goalType = member.getGoal(); + return MemberGoalServiceResponse.builder() + .goalType(goalType) + .build(); + } + } +} diff --git a/smeem-common/src/main/java/com/smeem/common/code/success/MemberSuccessCode.java b/smeem-common/src/main/java/com/smeem/common/code/success/MemberSuccessCode.java index 39d4a9a3..ad773310 100644 --- a/smeem-common/src/main/java/com/smeem/common/code/success/MemberSuccessCode.java +++ b/smeem-common/src/main/java/com/smeem/common/code/success/MemberSuccessCode.java @@ -19,6 +19,7 @@ public enum MemberSuccessCode implements SuccessCode { SUCCESS_CHECK_DUPLICATED_NAME(OK, "닉네임 중복 검사 성공"), SUCCESS_UPDATE_USER_PUSH(OK, "회원 푸시알람 동의여부 업데이트 성공"), SUCCESS_GET_PERFORMANCE_SUMMARY(OK, "성과 요약 조회 성공"), + SUCCESS_GET_PLAN(OK, "플랜 및 목표 조회 성공"), ; private final HttpStatus status; diff --git a/smeem-domain/src/main/java/com/smeem/domain/member/model/Member.java b/smeem-domain/src/main/java/com/smeem/domain/member/model/Member.java index 67991aa3..bce20db5 100644 --- a/smeem-domain/src/main/java/com/smeem/domain/member/model/Member.java +++ b/smeem-domain/src/main/java/com/smeem/domain/member/model/Member.java @@ -143,4 +143,19 @@ public int getVisitCount() { val visitCount = Objects.nonNull(this.visitInfo) ? this.visitInfo.getVisitCount() : null; return Objects.nonNull(visitCount) ? visitCount : 1; } + + public int getDiaryCountInWeek() { + return this.diaries.stream() + .filter(diary -> isBetweenThisWeek(diary.getCreatedAt().toLocalDate())) + .toList() + .size(); + } + + private boolean isBetweenThisWeek(LocalDate date) { + val today = LocalDate.now(); + val dayNum = today.getDayOfWeek().getValue(); + val monday = today.minusDays(dayNum - 1); + val sunday = today.plusDays(7 - dayNum); + return date.isAfter(monday.minusDays(1)) && date.isBefore(sunday.plusDays(1)); + } }