From bc876ce82cc430edadc1a0deedf43f4af4f1e307 Mon Sep 17 00:00:00 2001 From: pywoo Date: Thu, 31 Jul 2025 16:06:29 +0900 Subject: [PATCH 01/17] =?UTF-8?q?=E2=9C=A8=20=20feat:=20=EB=A9=A4=EB=B2=84?= =?UTF-8?q?=20=EC=97=94=ED=8B=B0=ED=8B=B0=EC=97=90=20=ED=8F=AC=EC=9D=B8?= =?UTF-8?q?=ED=8A=B8=20=ED=95=84=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../withtime/be/withtimebe/domain/member/entity/Member.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/entity/Member.java b/src/main/java/org/withtime/be/withtimebe/domain/member/entity/Member.java index 9969f52..3623a27 100644 --- a/src/main/java/org/withtime/be/withtimebe/domain/member/entity/Member.java +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/entity/Member.java @@ -71,6 +71,10 @@ public class Member extends BaseEntity { @Column(name = "role", nullable = false) private Role role; + @Column(name = "point", nullable = false) + @Builder.Default + private Integer point; + public void changeUsername(String newUsername) { this.username= newUsername; } From a519f80f02cde7f1e1846436d06e367db2e498e1 Mon Sep 17 00:00:00 2001 From: pywoo Date: Thu, 31 Jul 2025 16:18:32 +0900 Subject: [PATCH 02/17] =?UTF-8?q?=E2=9C=A8=20=20feat:=20Grade=20Enum=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/entity/enums/Grade.java | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/main/java/org/withtime/be/withtimebe/domain/member/entity/enums/Grade.java diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/entity/enums/Grade.java b/src/main/java/org/withtime/be/withtimebe/domain/member/entity/enums/Grade.java new file mode 100644 index 0000000..e675f8d --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/entity/enums/Grade.java @@ -0,0 +1,36 @@ +package org.withtime.be.withtimebe.domain.member.entity.enums; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum Grade { + + GUEST("Lv.0", "게스트", -1), + FLIRT("Lv.1", "첫 탐색을 시작한 유저. 데이트의 세계에 발을 디딘 입문자", 0), + EXPLORER("Lv.2", "다양한 코스를 둘러보며 취향을 탐색하는 단계", 50), + SEEKER("Lv.3", "키워드로 나만의 데이트를 계획하고 시도해 본 유저", 150), + NAVIGATOR("Lv.4", "코스를 저장하고, 추천도 해보며 길을 만들어가는 유저", 300), + JOURNEYMAN("Lv.5", "리뷰나 공유를 통해 다른 커플에게 영감을 주는 활동가", 500), + TRAILBLAZER("Lv.6", "직접 코스를 만들고, 사람들과 함께하는 데이트 리더", 800), + TIMEKEEPER("Lv.7", "추억을 기록하고 되돌아보며 서비스에 깊이 관여", 1200), + ROMANTIC_NOMAD("Lv.8", "계절별, 테마별 데이트를 기획해 나만의 지도 완성", 1700), + MASTER_OF_MOMENTS("Lv.9", "진짜 ‘데이트 큐레이터’. 추천받기보다 추천하는 사람", 2300), + WITHTIME("Lv.10", "WithTime의 세계를 완전히 정복한 전설의 사용자", 3000), + ; + + private final String level; + private final String description; + private final Integer requiredPoint; + + public static Grade fromPoint(int point) { + Grade[] grades = Grade.values(); + for (int i = grades.length - 1; i >= 0; i--) { + if (point >= grades[i].requiredPoint) { + return grades[i]; + } + } + return GUEST; + } +} From 690554f884045e891075566ce8afb8e4e9a88364 Mon Sep 17 00:00:00 2001 From: pywoo Date: Thu, 31 Jul 2025 16:41:22 +0900 Subject: [PATCH 03/17] =?UTF-8?q?=E2=9C=A8=20=20feat:=20=EB=82=98=EC=9D=98?= =?UTF-8?q?=20=EB=93=B1=EA=B8=89=20=EC=A1=B0=ED=9A=8C=20API=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/controller/MemberController.java | 12 ++++++++++++ .../domain/member/converter/MemberConverter.java | 12 ++++++++++++ .../domain/member/dto/MemberResponseDTO.java | 9 +++++++-- .../domain/member/entity/enums/Grade.java | 13 +++++++++++-- .../withtimebe/global/security/SecurityConfig.java | 1 - 5 files changed, 42 insertions(+), 5 deletions(-) diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/controller/MemberController.java b/src/main/java/org/withtime/be/withtimebe/domain/member/controller/MemberController.java index 4220e46..e86e427 100644 --- a/src/main/java/org/withtime/be/withtimebe/domain/member/controller/MemberController.java +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/controller/MemberController.java @@ -6,6 +6,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.namul.api.payload.response.DefaultResponse; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -15,6 +16,7 @@ import org.withtime.be.withtimebe.domain.member.dto.MemberResponseDTO; import org.withtime.be.withtimebe.domain.member.entity.Member; import org.withtime.be.withtimebe.domain.member.service.command.MemberCommandService; +import org.withtime.be.withtimebe.domain.member.service.query.MemberQueryService; import org.withtime.be.withtimebe.global.security.annotation.AuthenticatedMember; @RestController @@ -24,6 +26,7 @@ public class MemberController { private final MemberCommandService memberCommandService; + private final MemberQueryService memberQueryService; @Operation(summary = "비밀번호 변경 API", description = "현재 비밀번호가 맞으면 새로운 비밀번호로 변경") @ApiResponses({ @@ -75,4 +78,13 @@ public DefaultResponse changeInfo(@AuthenticatedMe Member updatedMember = memberCommandService.changeInfo(member.getId(), request); return DefaultResponse.ok(MemberConverter.toChangeInfo(updatedMember)); } + + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "등급 반환 성공"), + }) + @GetMapping("/grade") + public DefaultResponse findMyGrade(@AuthenticatedMember Member member) { + MemberResponseDTO.FindMyGrade response = MemberConverter.toFindMyGrade(member); + return DefaultResponse.ok(response); + } } diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/converter/MemberConverter.java b/src/main/java/org/withtime/be/withtimebe/domain/member/converter/MemberConverter.java index 02e018f..d6d894c 100644 --- a/src/main/java/org/withtime/be/withtimebe/domain/member/converter/MemberConverter.java +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/converter/MemberConverter.java @@ -2,6 +2,7 @@ import org.withtime.be.withtimebe.domain.member.dto.MemberResponseDTO; import org.withtime.be.withtimebe.domain.member.entity.Member; +import org.withtime.be.withtimebe.domain.member.entity.enums.Grade; public class MemberConverter { @@ -10,4 +11,15 @@ public static MemberResponseDTO.ChangeInfo toChangeInfo(Member member) { .username(member.getUsername()) .build(); } + + public static MemberResponseDTO.FindMyGrade toFindMyGrade(Member member) { + Grade grade = Grade.fromPoint(member.getPoint()); + Integer nextRequiredPoint = Grade.nextRequiredPoint(member.getPoint()); + + return MemberResponseDTO.FindMyGrade.builder() + .level(grade.getLevel()) + .description(grade.getDescription()) + .nextRequiredPoint(nextRequiredPoint) + .build(); + } } diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/dto/MemberResponseDTO.java b/src/main/java/org/withtime/be/withtimebe/domain/member/dto/MemberResponseDTO.java index c3225ea..f8d0a1c 100644 --- a/src/main/java/org/withtime/be/withtimebe/domain/member/dto/MemberResponseDTO.java +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/dto/MemberResponseDTO.java @@ -6,7 +6,12 @@ public record MemberResponseDTO() { @Builder public record ChangeInfo( String username - ) { + ) {} - } + @Builder + public record FindMyGrade( + String level, + String description, + Integer nextRequiredPoint + ) {} } diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/entity/enums/Grade.java b/src/main/java/org/withtime/be/withtimebe/domain/member/entity/enums/Grade.java index e675f8d..0478553 100644 --- a/src/main/java/org/withtime/be/withtimebe/domain/member/entity/enums/Grade.java +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/entity/enums/Grade.java @@ -7,7 +7,6 @@ @RequiredArgsConstructor public enum Grade { - GUEST("Lv.0", "게스트", -1), FLIRT("Lv.1", "첫 탐색을 시작한 유저. 데이트의 세계에 발을 디딘 입문자", 0), EXPLORER("Lv.2", "다양한 코스를 둘러보며 취향을 탐색하는 단계", 50), SEEKER("Lv.3", "키워드로 나만의 데이트를 계획하고 시도해 본 유저", 150), @@ -31,6 +30,16 @@ public static Grade fromPoint(int point) { return grades[i]; } } - return GUEST; + return FLIRT; + } + + public static Integer nextRequiredPoint(int currentPoint) { + Grade[] grades = Grade.values(); + for (int i = 0; i < grades.length - 1; i++) { + if (currentPoint < grades[i + 1].requiredPoint && currentPoint >= grades[i].requiredPoint) { + return grades[i + 1].requiredPoint - currentPoint; + } + } + return 0; } } diff --git a/src/main/java/org/withtime/be/withtimebe/global/security/SecurityConfig.java b/src/main/java/org/withtime/be/withtimebe/global/security/SecurityConfig.java index 92ea247..32f0c8a 100644 --- a/src/main/java/org/withtime/be/withtimebe/global/security/SecurityConfig.java +++ b/src/main/java/org/withtime/be/withtimebe/global/security/SecurityConfig.java @@ -55,7 +55,6 @@ public class SecurityConfig { API_PREFIX + "/faqs/**", API_PREFIX + "/logs/keyword/**", API_PREFIX + "/logs/dateplaces/**", - API_PREFIX + "/logs/datecourses/**", "/oauth2/authorization/**", "/swagger-ui/**", "/swagger-resources/**", From 2cddf59f08265bf8d4c711fc5455fcf374881e24 Mon Sep 17 00:00:00 2001 From: pywoo Date: Thu, 31 Jul 2025 16:45:27 +0900 Subject: [PATCH 04/17] =?UTF-8?q?=E2=9C=A8=20=20feat:=20=EC=9D=B4=EB=A6=84?= =?UTF-8?q?=20=ED=95=84=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../be/withtimebe/domain/member/converter/MemberConverter.java | 1 + .../be/withtimebe/domain/member/dto/MemberResponseDTO.java | 1 + 2 files changed, 2 insertions(+) diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/converter/MemberConverter.java b/src/main/java/org/withtime/be/withtimebe/domain/member/converter/MemberConverter.java index d6d894c..fe15c4c 100644 --- a/src/main/java/org/withtime/be/withtimebe/domain/member/converter/MemberConverter.java +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/converter/MemberConverter.java @@ -17,6 +17,7 @@ public static MemberResponseDTO.FindMyGrade toFindMyGrade(Member member) { Integer nextRequiredPoint = Grade.nextRequiredPoint(member.getPoint()); return MemberResponseDTO.FindMyGrade.builder() + .username(member.getUsername()) .level(grade.getLevel()) .description(grade.getDescription()) .nextRequiredPoint(nextRequiredPoint) diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/dto/MemberResponseDTO.java b/src/main/java/org/withtime/be/withtimebe/domain/member/dto/MemberResponseDTO.java index f8d0a1c..c07b55a 100644 --- a/src/main/java/org/withtime/be/withtimebe/domain/member/dto/MemberResponseDTO.java +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/dto/MemberResponseDTO.java @@ -10,6 +10,7 @@ public record ChangeInfo( @Builder public record FindMyGrade( + String username, String level, String description, Integer nextRequiredPoint From 8021eab7269cc57698d072c53524ac8be14f6dbc Mon Sep 17 00:00:00 2001 From: pywoo Date: Fri, 1 Aug 2025 13:50:06 +0900 Subject: [PATCH 05/17] =?UTF-8?q?=E2=9C=A8=20=20feat:=20=ED=96=89=EB=8F=99?= =?UTF-8?q?=20=EB=B3=84=20=ED=8F=AC=EC=9D=B8=ED=8A=B8=20=EB=88=84=EC=A0=81?= =?UTF-8?q?=20=EC=96=B4=EB=85=B8=ED=85=8C=EC=9D=B4=EC=85=98=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/annotation/GetPoint.java | 16 ++++++++++++++ .../member/annotation/enums/PointAction.java | 22 +++++++++++++++++++ 2 files changed, 38 insertions(+) create mode 100644 src/main/java/org/withtime/be/withtimebe/domain/member/annotation/GetPoint.java create mode 100644 src/main/java/org/withtime/be/withtimebe/domain/member/annotation/enums/PointAction.java diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/annotation/GetPoint.java b/src/main/java/org/withtime/be/withtimebe/domain/member/annotation/GetPoint.java new file mode 100644 index 0000000..0429dff --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/annotation/GetPoint.java @@ -0,0 +1,16 @@ +package org.withtime.be.withtimebe.domain.member.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.withtime.be.withtimebe.domain.member.annotation.enums.PointAction; + +@Documented +@Target(ElementType.METHOD) +@Retention(RetentionPolicy.RUNTIME) +public @interface GetPoint { + PointAction action(); +} diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/annotation/enums/PointAction.java b/src/main/java/org/withtime/be/withtimebe/domain/member/annotation/enums/PointAction.java new file mode 100644 index 0000000..0f51320 --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/annotation/enums/PointAction.java @@ -0,0 +1,22 @@ +package org.withtime.be.withtimebe.domain.member.annotation.enums; + +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum PointAction { + + KEYWORD_SEARCH("키워드 검색", 3), + VIEW_DATE_COURSE("데이트 코스 조회", 5), + SAVE_DATE_COURSE("데이트 코스 저장", 10), + CREATE_DATE_COURSE("데이트 코스 생성", 30), + WRITE_REVIEW("리뷰 작성", 20), + COMPLETE_TEST("취향 테스트 완료", 20), + INPUT_PROFILE("프로필 입력", 10), + // COMPLETE_MISSION("미션 완료", 0), + ; + + private final String label; + private final Integer point; +} \ No newline at end of file From 44aca0003d99f9e281961802930a30bf2960a613 Mon Sep 17 00:00:00 2001 From: pywoo Date: Fri, 1 Aug 2025 14:18:48 +0900 Subject: [PATCH 06/17] =?UTF-8?q?=E2=9C=A8=20=20feat:=20=ED=96=89=EB=8F=99?= =?UTF-8?q?=20=EB=B3=84=20=ED=8F=AC=EC=9D=B8=ED=8A=B8=20=EB=88=84=EC=A0=81?= =?UTF-8?q?=20AOP=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/member/aop/GetPointAspect.java | 44 +++++++++++++++++++ .../domain/member/entity/Member.java | 4 ++ .../service/command/MemberCommandService.java | 1 + .../command/MemberCommandServiceImpl.java | 7 +++ 4 files changed, 56 insertions(+) create mode 100644 src/main/java/org/withtime/be/withtimebe/domain/member/aop/GetPointAspect.java diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/aop/GetPointAspect.java b/src/main/java/org/withtime/be/withtimebe/domain/member/aop/GetPointAspect.java new file mode 100644 index 0000000..99071d9 --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/aop/GetPointAspect.java @@ -0,0 +1,44 @@ +package org.withtime.be.withtimebe.domain.member.aop; + +import org.aspectj.lang.JoinPoint; +import org.aspectj.lang.annotation.AfterReturning; +import org.aspectj.lang.annotation.Aspect; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Component; +import org.withtime.be.withtimebe.domain.member.annotation.GetPoint; +import org.withtime.be.withtimebe.domain.member.annotation.enums.PointAction; +import org.withtime.be.withtimebe.domain.member.service.command.MemberCommandService; +import org.withtime.be.withtimebe.global.security.domain.CustomUserDetails; + +import lombok.RequiredArgsConstructor; + +@Aspect +@Component +@RequiredArgsConstructor +public class GetPointAspect { + + private final MemberCommandService memberCommandService; + + @AfterReturning("@annotation(getPoint)") + public void addPoint(GetPoint getPoint) { + + // 행동 및 포인트 추출 + PointAction action = getPoint.action(); + Integer point = action.getPoint(); + + // 인증 객체 추출 + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if(authentication == null || !authentication.isAuthenticated()) { + return; + } + + // 포인트 적립 + UserDetails userDetails = (UserDetails) authentication.getPrincipal(); + if(userDetails instanceof CustomUserDetails customUserDetails) { + Long memberId = customUserDetails.getMember().getId(); + memberCommandService.addPoint(memberId, point); + } + } +} diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/entity/Member.java b/src/main/java/org/withtime/be/withtimebe/domain/member/entity/Member.java index 3623a27..c0136eb 100644 --- a/src/main/java/org/withtime/be/withtimebe/domain/member/entity/Member.java +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/entity/Member.java @@ -92,4 +92,8 @@ public void updateAlarmSetting(Boolean pushAlarm, Boolean emailAlarm, Boolean sm this.emailAlarm = emailAlarm; this.smsAlarm = smsAlarm; } + + public void addPoint(Integer point) { + this.point += point; + } } diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/service/command/MemberCommandService.java b/src/main/java/org/withtime/be/withtimebe/domain/member/service/command/MemberCommandService.java index eed5c12..f1e037f 100644 --- a/src/main/java/org/withtime/be/withtimebe/domain/member/service/command/MemberCommandService.java +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/service/command/MemberCommandService.java @@ -7,4 +7,5 @@ public interface MemberCommandService { void changePassword(Member member, MemberRequestDTO.ChangePassword request); void changePassword(String email, String password); Member changeInfo(Long memberId, MemberRequestDTO.ChangeInfo request); + void addPoint(Long memberId, Integer point); } diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/service/command/MemberCommandServiceImpl.java b/src/main/java/org/withtime/be/withtimebe/domain/member/service/command/MemberCommandServiceImpl.java index 48f16ec..aa43e1f 100644 --- a/src/main/java/org/withtime/be/withtimebe/domain/member/service/command/MemberCommandServiceImpl.java +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/service/command/MemberCommandServiceImpl.java @@ -46,6 +46,13 @@ public Member changeInfo(Long memberId, MemberRequestDTO.ChangeInfo request) { return member; } + @Override + public void addPoint(Long memberId, Integer point) { + Member member = memberRepository.findById(memberId).orElseThrow(() -> + new MemberException(MemberErrorCode.NOT_FOUND)); + member.addPoint(point); + } + public void validateChangePassword(Member member, String password) throws ServerApplicationException { String memberPassword = member.getPassword(); if (memberPassword == null) { From 324f12e6e688341d979a5e686f3e8628da8a9e88 Mon Sep 17 00:00:00 2001 From: pywoo Date: Fri, 1 Aug 2025 14:26:51 +0900 Subject: [PATCH 07/17] =?UTF-8?q?=E2=9C=A8=20=20feat:=20=ED=8F=AC=EC=9D=B8?= =?UTF-8?q?=ED=8A=B8=20=EC=B4=88=EA=B9=83=EA=B0=92=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/withtime/be/withtimebe/domain/member/entity/Member.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/entity/Member.java b/src/main/java/org/withtime/be/withtimebe/domain/member/entity/Member.java index c0136eb..3acf9d3 100644 --- a/src/main/java/org/withtime/be/withtimebe/domain/member/entity/Member.java +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/entity/Member.java @@ -73,7 +73,7 @@ public class Member extends BaseEntity { @Column(name = "point", nullable = false) @Builder.Default - private Integer point; + private Integer point = 0; public void changeUsername(String newUsername) { this.username= newUsername; From e052548c5fb0097db7bca71d1c0007cdb1e06fb5 Mon Sep 17 00:00:00 2001 From: pywoo Date: Fri, 1 Aug 2025 14:34:28 +0900 Subject: [PATCH 08/17] =?UTF-8?q?=E2=9C=A8=20=20feat:=20=EC=8A=A4=EC=9B=A8?= =?UTF-8?q?=EA=B1=B0=20=EC=84=A4=EB=AA=85=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../be/withtimebe/domain/member/controller/MemberController.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/controller/MemberController.java b/src/main/java/org/withtime/be/withtimebe/domain/member/controller/MemberController.java index e86e427..76506e2 100644 --- a/src/main/java/org/withtime/be/withtimebe/domain/member/controller/MemberController.java +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/controller/MemberController.java @@ -79,6 +79,7 @@ public DefaultResponse changeInfo(@AuthenticatedMe return DefaultResponse.ok(MemberConverter.toChangeInfo(updatedMember)); } + @Operation(summary = "나의 등급 조회 by 피우", description = "나의 등급을 조회하는 API 입니다. 로그인 사용자만 조회 가능합니다.") @ApiResponses({ @ApiResponse(responseCode = "200", description = "등급 반환 성공"), }) From a95285d49e939fe9bb721749d2ab9aceb828a271 Mon Sep 17 00:00:00 2001 From: pywoo Date: Fri, 1 Aug 2025 14:36:52 +0900 Subject: [PATCH 09/17] =?UTF-8?q?=F0=9F=90=9B=20fix:=20=EC=8A=A4=EC=9B=A8?= =?UTF-8?q?=EA=B1=B0=20=EC=84=A4=EB=AA=85=20=EC=88=98=EC=A0=95=20=EB=B0=8F?= =?UTF-8?q?=20security=20=EA=B2=BD=EB=A1=9C=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../datecourselog/controller/DateCourseLogQueryController.java | 2 +- .../withtime/be/withtimebe/global/security/SecurityConfig.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/withtime/be/withtimebe/domain/log/datecourselog/controller/DateCourseLogQueryController.java b/src/main/java/org/withtime/be/withtimebe/domain/log/datecourselog/controller/DateCourseLogQueryController.java index 9656523..212f544 100644 --- a/src/main/java/org/withtime/be/withtimebe/domain/log/datecourselog/controller/DateCourseLogQueryController.java +++ b/src/main/java/org/withtime/be/withtimebe/domain/log/datecourselog/controller/DateCourseLogQueryController.java @@ -22,7 +22,7 @@ public class DateCourseLogQueryController { private final DateCourseLogQueryService dateCourseLogQueryService; - @Operation(summary = "최근 1개월 WithTime 사용자의 데이트 평균 횟수와 나의 데이트 횟수 조회 API by 피우", description = "메인 페이지의 데이트 나침반에 해당하는 API입니다. 최근 1개월 WithTime 사용자의 데이트 평균 횟수와 나의 데이트 횟수 조회하는 API입니다.") + @Operation(summary = "최근 1개월 WithTime 사용자의 데이트 평균 횟수와 나의 데이트 횟수 조회 API by 피우", description = "메인 페이지의 데이트 나침반에 해당하는 API입니다. 최근 1개월 WithTime 사용자의 데이트 평균 횟수와 나의 데이트 횟수 조회하는 API입니다. 비회원은 나의 데이트 횟수가 0회로 표시됩니다.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "성공입니다.") }) diff --git a/src/main/java/org/withtime/be/withtimebe/global/security/SecurityConfig.java b/src/main/java/org/withtime/be/withtimebe/global/security/SecurityConfig.java index 32f0c8a..92ea247 100644 --- a/src/main/java/org/withtime/be/withtimebe/global/security/SecurityConfig.java +++ b/src/main/java/org/withtime/be/withtimebe/global/security/SecurityConfig.java @@ -55,6 +55,7 @@ public class SecurityConfig { API_PREFIX + "/faqs/**", API_PREFIX + "/logs/keyword/**", API_PREFIX + "/logs/dateplaces/**", + API_PREFIX + "/logs/datecourses/**", "/oauth2/authorization/**", "/swagger-ui/**", "/swagger-resources/**", From e142e25190f869199c00b7915d4b7d8042fe2bf6 Mon Sep 17 00:00:00 2001 From: pywoo Date: Fri, 1 Aug 2025 14:37:43 +0900 Subject: [PATCH 10/17] =?UTF-8?q?=F0=9F=90=9B=20fix:=20=EC=8A=A4=EC=9B=A8?= =?UTF-8?q?=EA=B1=B0=20=EC=84=A4=EB=AA=85=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../withtimebe/domain/member/controller/MemberController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/controller/MemberController.java b/src/main/java/org/withtime/be/withtimebe/domain/member/controller/MemberController.java index 76506e2..b656f9c 100644 --- a/src/main/java/org/withtime/be/withtimebe/domain/member/controller/MemberController.java +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/controller/MemberController.java @@ -79,7 +79,7 @@ public DefaultResponse changeInfo(@AuthenticatedMe return DefaultResponse.ok(MemberConverter.toChangeInfo(updatedMember)); } - @Operation(summary = "나의 등급 조회 by 피우", description = "나의 등급을 조회하는 API 입니다. 로그인 사용자만 조회 가능합니다.") + @Operation(summary = "나의 등급 조회 API by 피우", description = "나의 등급을 조회하는 API 입니다. 로그인 사용자만 조회 가능합니다.") @ApiResponses({ @ApiResponse(responseCode = "200", description = "등급 반환 성공"), }) From 925ac08468096ac017a7f2929279dc6d54d61cb1 Mon Sep 17 00:00:00 2001 From: pywoo Date: Fri, 1 Aug 2025 14:43:55 +0900 Subject: [PATCH 11/17] =?UTF-8?q?=F0=9F=90=9B=20fix:=20dto=20=EB=88=84?= =?UTF-8?q?=EB=9D=BD=20=ED=95=84=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../be/withtimebe/domain/member/converter/MemberConverter.java | 1 + .../be/withtimebe/domain/member/dto/MemberResponseDTO.java | 1 + 2 files changed, 2 insertions(+) diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/converter/MemberConverter.java b/src/main/java/org/withtime/be/withtimebe/domain/member/converter/MemberConverter.java index fe15c4c..b85af83 100644 --- a/src/main/java/org/withtime/be/withtimebe/domain/member/converter/MemberConverter.java +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/converter/MemberConverter.java @@ -18,6 +18,7 @@ public static MemberResponseDTO.FindMyGrade toFindMyGrade(Member member) { return MemberResponseDTO.FindMyGrade.builder() .username(member.getUsername()) + .grade(grade.name()) .level(grade.getLevel()) .description(grade.getDescription()) .nextRequiredPoint(nextRequiredPoint) diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/dto/MemberResponseDTO.java b/src/main/java/org/withtime/be/withtimebe/domain/member/dto/MemberResponseDTO.java index c07b55a..d680f00 100644 --- a/src/main/java/org/withtime/be/withtimebe/domain/member/dto/MemberResponseDTO.java +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/dto/MemberResponseDTO.java @@ -11,6 +11,7 @@ public record ChangeInfo( @Builder public record FindMyGrade( String username, + String grade, String level, String description, Integer nextRequiredPoint From bf32379536a7252cbb144b112f90f408b0ffb1e4 Mon Sep 17 00:00:00 2001 From: pywoo Date: Sat, 2 Aug 2025 17:14:59 +0900 Subject: [PATCH 12/17] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor:=20Grade=20?= =?UTF-8?q?=EC=97=94=ED=8B=B0=ED=8B=B0=EB=A1=9C=20=EA=B4=80=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/converter/MemberConverter.java | 12 ++--- .../domain/member/entity/Grade.java | 42 +++++++++++++++++ .../domain/member/entity/enums/Grade.java | 45 ------------------- .../domain/member/entity/enums/GradeType.java | 14 ++++++ .../member/repository/GradeRepository.java | 7 +++ 5 files changed, 69 insertions(+), 51 deletions(-) create mode 100644 src/main/java/org/withtime/be/withtimebe/domain/member/entity/Grade.java delete mode 100644 src/main/java/org/withtime/be/withtimebe/domain/member/entity/enums/Grade.java create mode 100644 src/main/java/org/withtime/be/withtimebe/domain/member/entity/enums/GradeType.java create mode 100644 src/main/java/org/withtime/be/withtimebe/domain/member/repository/GradeRepository.java diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/converter/MemberConverter.java b/src/main/java/org/withtime/be/withtimebe/domain/member/converter/MemberConverter.java index b85af83..e0a126f 100644 --- a/src/main/java/org/withtime/be/withtimebe/domain/member/converter/MemberConverter.java +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/converter/MemberConverter.java @@ -2,7 +2,7 @@ import org.withtime.be.withtimebe.domain.member.dto.MemberResponseDTO; import org.withtime.be.withtimebe.domain.member.entity.Member; -import org.withtime.be.withtimebe.domain.member.entity.enums.Grade; +import org.withtime.be.withtimebe.domain.member.entity.enums.GradeType; public class MemberConverter { @@ -13,14 +13,14 @@ public static MemberResponseDTO.ChangeInfo toChangeInfo(Member member) { } public static MemberResponseDTO.FindMyGrade toFindMyGrade(Member member) { - Grade grade = Grade.fromPoint(member.getPoint()); - Integer nextRequiredPoint = Grade.nextRequiredPoint(member.getPoint()); + GradeType gradeType = GradeType.fromPoint(member.getPoint()); + Integer nextRequiredPoint = GradeType.nextRequiredPoint(member.getPoint()); return MemberResponseDTO.FindMyGrade.builder() .username(member.getUsername()) - .grade(grade.name()) - .level(grade.getLevel()) - .description(grade.getDescription()) + .grade(gradeType.name()) + .level(gradeType.getLevel()) + .description(gradeType.getDescription()) .nextRequiredPoint(nextRequiredPoint) .build(); } diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/entity/Grade.java b/src/main/java/org/withtime/be/withtimebe/domain/member/entity/Grade.java new file mode 100644 index 0000000..0ca83f2 --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/entity/Grade.java @@ -0,0 +1,42 @@ +package org.withtime.be.withtimebe.domain.member.entity; + +import org.withtime.be.withtimebe.domain.member.entity.enums.GradeType; +import org.withtime.be.withtimebe.global.common.BaseEntity; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Entity +@Getter +@Builder +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +@Table(name = "grade") +public class Grade extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "grade_id") + private Long id; + + @Column(nullable = false, unique = true) + private GradeType gradeType; + + @Column(nullable = false) + private String level; + + @Column(nullable = false) + private String description; + + @Column(nullable = false) + private Integer requiredPoint; +} diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/entity/enums/Grade.java b/src/main/java/org/withtime/be/withtimebe/domain/member/entity/enums/Grade.java deleted file mode 100644 index 0478553..0000000 --- a/src/main/java/org/withtime/be/withtimebe/domain/member/entity/enums/Grade.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.withtime.be.withtimebe.domain.member.entity.enums; - -import lombok.Getter; -import lombok.RequiredArgsConstructor; - -@Getter -@RequiredArgsConstructor -public enum Grade { - - FLIRT("Lv.1", "첫 탐색을 시작한 유저. 데이트의 세계에 발을 디딘 입문자", 0), - EXPLORER("Lv.2", "다양한 코스를 둘러보며 취향을 탐색하는 단계", 50), - SEEKER("Lv.3", "키워드로 나만의 데이트를 계획하고 시도해 본 유저", 150), - NAVIGATOR("Lv.4", "코스를 저장하고, 추천도 해보며 길을 만들어가는 유저", 300), - JOURNEYMAN("Lv.5", "리뷰나 공유를 통해 다른 커플에게 영감을 주는 활동가", 500), - TRAILBLAZER("Lv.6", "직접 코스를 만들고, 사람들과 함께하는 데이트 리더", 800), - TIMEKEEPER("Lv.7", "추억을 기록하고 되돌아보며 서비스에 깊이 관여", 1200), - ROMANTIC_NOMAD("Lv.8", "계절별, 테마별 데이트를 기획해 나만의 지도 완성", 1700), - MASTER_OF_MOMENTS("Lv.9", "진짜 ‘데이트 큐레이터’. 추천받기보다 추천하는 사람", 2300), - WITHTIME("Lv.10", "WithTime의 세계를 완전히 정복한 전설의 사용자", 3000), - ; - - private final String level; - private final String description; - private final Integer requiredPoint; - - public static Grade fromPoint(int point) { - Grade[] grades = Grade.values(); - for (int i = grades.length - 1; i >= 0; i--) { - if (point >= grades[i].requiredPoint) { - return grades[i]; - } - } - return FLIRT; - } - - public static Integer nextRequiredPoint(int currentPoint) { - Grade[] grades = Grade.values(); - for (int i = 0; i < grades.length - 1; i++) { - if (currentPoint < grades[i + 1].requiredPoint && currentPoint >= grades[i].requiredPoint) { - return grades[i + 1].requiredPoint - currentPoint; - } - } - return 0; - } -} diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/entity/enums/GradeType.java b/src/main/java/org/withtime/be/withtimebe/domain/member/entity/enums/GradeType.java new file mode 100644 index 0000000..05b64e0 --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/entity/enums/GradeType.java @@ -0,0 +1,14 @@ +package org.withtime.be.withtimebe.domain.member.entity.enums; + +public enum GradeType { + FLIRT, + EXPLORER, + SEEKER, + NAVIGATOR, + JOURNEYMAN, + TRAILBLAZER, + TIMEKEEPER, + ROMANTIC_NOMAD, + MASTER_OF_MOMENTS, + WITHTIME +} diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/repository/GradeRepository.java b/src/main/java/org/withtime/be/withtimebe/domain/member/repository/GradeRepository.java new file mode 100644 index 0000000..d9fb5f7 --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/repository/GradeRepository.java @@ -0,0 +1,7 @@ +package org.withtime.be.withtimebe.domain.member.repository; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.withtime.be.withtimebe.domain.member.entity.Grade; + +public interface GradeRepository extends JpaRepository { +} From 0a2a4a33517bf41d74e0fd0ff7db5962beb5b2f9 Mon Sep 17 00:00:00 2001 From: pywoo Date: Fri, 8 Aug 2025 17:57:00 +0900 Subject: [PATCH 13/17] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor:=20Grade=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC=20=EB=B0=8F=20=EC=BD=94=EB=93=9C=20=EC=9E=AC?= =?UTF-8?q?=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../member/controller/GradeController.java | 44 +++++++++++++++++++ .../member/controller/MemberController.java | 10 ----- .../member/converter/GradeConverter.java | 21 +++++++++ .../member/converter/MemberConverter.java | 14 ------ .../domain/member/dto/GradeResponseDTO.java | 15 +++++++ .../domain/member/dto/MemberResponseDTO.java | 9 ---- .../member/repository/GradeRepository.java | 14 ++++++ .../service/query/GradeQueryService.java | 8 ++++ .../service/query/GradeQueryServiceImpl.java | 34 ++++++++++++++ .../global/error/code/GradeErrorCode.java | 27 ++++++++++++ .../error/exception/GradeException.java | 10 +++++ 11 files changed, 173 insertions(+), 33 deletions(-) create mode 100644 src/main/java/org/withtime/be/withtimebe/domain/member/controller/GradeController.java create mode 100644 src/main/java/org/withtime/be/withtimebe/domain/member/converter/GradeConverter.java create mode 100644 src/main/java/org/withtime/be/withtimebe/domain/member/dto/GradeResponseDTO.java create mode 100644 src/main/java/org/withtime/be/withtimebe/domain/member/service/query/GradeQueryService.java create mode 100644 src/main/java/org/withtime/be/withtimebe/domain/member/service/query/GradeQueryServiceImpl.java create mode 100644 src/main/java/org/withtime/be/withtimebe/global/error/code/GradeErrorCode.java create mode 100644 src/main/java/org/withtime/be/withtimebe/global/error/exception/GradeException.java diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/controller/GradeController.java b/src/main/java/org/withtime/be/withtimebe/domain/member/controller/GradeController.java new file mode 100644 index 0000000..6b4a2ae --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/controller/GradeController.java @@ -0,0 +1,44 @@ +package org.withtime.be.withtimebe.domain.member.controller; + +import org.namul.api.payload.response.DefaultResponse; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import org.withtime.be.withtimebe.domain.member.converter.MemberConverter; +import org.withtime.be.withtimebe.domain.member.dto.GradeResponseDTO; +import org.withtime.be.withtimebe.domain.member.dto.MemberResponseDTO; +import org.withtime.be.withtimebe.domain.member.entity.Member; +import org.withtime.be.withtimebe.domain.member.service.query.GradeQueryService; +import org.withtime.be.withtimebe.global.security.annotation.AuthenticatedMember; + +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/v1/members/grade") +@Tag(name = "사용자 등급 관련 API") +public class GradeController { + + private final GradeQueryService gradeQueryService; + + @Operation(summary = "나의 등급 조회 API by 피우", description = "나의 등급을 조회하는 API 입니다. 로그인한 사용자만 조회 가능합니다.") + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "등급 반환 성공"), + @ApiResponse( + responseCode = "404", + description = """ + 다음과 같은 이유로 실패할 수 있습니다: + - GRADE404_1: 등급을 찾지 못했습니다. + """ + ) + }) + @GetMapping("/grade") + public DefaultResponse findMyGrade(@AuthenticatedMember Member member) { + GradeResponseDTO.FindMyGrade response = gradeQueryService.findMyGrade(member); + return DefaultResponse.ok(response); + } +} diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/controller/MemberController.java b/src/main/java/org/withtime/be/withtimebe/domain/member/controller/MemberController.java index b656f9c..2315623 100644 --- a/src/main/java/org/withtime/be/withtimebe/domain/member/controller/MemberController.java +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/controller/MemberController.java @@ -78,14 +78,4 @@ public DefaultResponse changeInfo(@AuthenticatedMe Member updatedMember = memberCommandService.changeInfo(member.getId(), request); return DefaultResponse.ok(MemberConverter.toChangeInfo(updatedMember)); } - - @Operation(summary = "나의 등급 조회 API by 피우", description = "나의 등급을 조회하는 API 입니다. 로그인 사용자만 조회 가능합니다.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "등급 반환 성공"), - }) - @GetMapping("/grade") - public DefaultResponse findMyGrade(@AuthenticatedMember Member member) { - MemberResponseDTO.FindMyGrade response = MemberConverter.toFindMyGrade(member); - return DefaultResponse.ok(response); - } } diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/converter/GradeConverter.java b/src/main/java/org/withtime/be/withtimebe/domain/member/converter/GradeConverter.java new file mode 100644 index 0000000..a0d9703 --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/converter/GradeConverter.java @@ -0,0 +1,21 @@ +package org.withtime.be.withtimebe.domain.member.converter; + +import org.withtime.be.withtimebe.domain.member.dto.GradeResponseDTO; +import org.withtime.be.withtimebe.domain.member.entity.Grade; +import org.withtime.be.withtimebe.domain.member.entity.Member; + +public class GradeConverter { + + public static GradeResponseDTO.FindMyGrade toFindMyGrade(Member member, Grade current, Grade next) { + + int nextRequiredPoint = (next == null) ? 0 : next.getRequiredPoint() - member.getPoint(); + + return GradeResponseDTO.FindMyGrade.builder() + .username(member.getUsername()) + .grade(current.getGradeType().name()) + .level(current.getLevel()) + .description(current.getDescription()) + .nextRequiredPoint(nextRequiredPoint) + .build(); + } +} diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/converter/MemberConverter.java b/src/main/java/org/withtime/be/withtimebe/domain/member/converter/MemberConverter.java index e0a126f..02e018f 100644 --- a/src/main/java/org/withtime/be/withtimebe/domain/member/converter/MemberConverter.java +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/converter/MemberConverter.java @@ -2,7 +2,6 @@ import org.withtime.be.withtimebe.domain.member.dto.MemberResponseDTO; import org.withtime.be.withtimebe.domain.member.entity.Member; -import org.withtime.be.withtimebe.domain.member.entity.enums.GradeType; public class MemberConverter { @@ -11,17 +10,4 @@ public static MemberResponseDTO.ChangeInfo toChangeInfo(Member member) { .username(member.getUsername()) .build(); } - - public static MemberResponseDTO.FindMyGrade toFindMyGrade(Member member) { - GradeType gradeType = GradeType.fromPoint(member.getPoint()); - Integer nextRequiredPoint = GradeType.nextRequiredPoint(member.getPoint()); - - return MemberResponseDTO.FindMyGrade.builder() - .username(member.getUsername()) - .grade(gradeType.name()) - .level(gradeType.getLevel()) - .description(gradeType.getDescription()) - .nextRequiredPoint(nextRequiredPoint) - .build(); - } } diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/dto/GradeResponseDTO.java b/src/main/java/org/withtime/be/withtimebe/domain/member/dto/GradeResponseDTO.java new file mode 100644 index 0000000..fcc72a7 --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/dto/GradeResponseDTO.java @@ -0,0 +1,15 @@ +package org.withtime.be.withtimebe.domain.member.dto; + +import lombok.Builder; + +public record GradeResponseDTO() { + + @Builder + public record FindMyGrade( + String username, + String grade, + String level, + String description, + Integer nextRequiredPoint + ) {} +} diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/dto/MemberResponseDTO.java b/src/main/java/org/withtime/be/withtimebe/domain/member/dto/MemberResponseDTO.java index d680f00..0fa1321 100644 --- a/src/main/java/org/withtime/be/withtimebe/domain/member/dto/MemberResponseDTO.java +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/dto/MemberResponseDTO.java @@ -7,13 +7,4 @@ public record MemberResponseDTO() { public record ChangeInfo( String username ) {} - - @Builder - public record FindMyGrade( - String username, - String grade, - String level, - String description, - Integer nextRequiredPoint - ) {} } diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/repository/GradeRepository.java b/src/main/java/org/withtime/be/withtimebe/domain/member/repository/GradeRepository.java index d9fb5f7..c7cefa5 100644 --- a/src/main/java/org/withtime/be/withtimebe/domain/member/repository/GradeRepository.java +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/repository/GradeRepository.java @@ -1,7 +1,21 @@ package org.withtime.be.withtimebe.domain.member.repository; +import java.util.Optional; + import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; import org.withtime.be.withtimebe.domain.member.entity.Grade; public interface GradeRepository extends JpaRepository { + + @Query("SELECT g FROM Grade g " + + "WHERE g.requiredPoint <= :point " + + "ORDER BY g.requiredPoint DESC") + Optional findCurrentGrade(@Param("point") int point); + + @Query("SELECT g FROM Grade g " + + "WHERE g.requiredPoint > :point " + + "ORDER BY g.requiredPoint ASC") + Optional findNextGrade(@Param("point") int point); } diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/service/query/GradeQueryService.java b/src/main/java/org/withtime/be/withtimebe/domain/member/service/query/GradeQueryService.java new file mode 100644 index 0000000..c1a6b39 --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/service/query/GradeQueryService.java @@ -0,0 +1,8 @@ +package org.withtime.be.withtimebe.domain.member.service.query; + +import org.withtime.be.withtimebe.domain.member.dto.GradeResponseDTO; +import org.withtime.be.withtimebe.domain.member.entity.Member; + +public interface GradeQueryService { + GradeResponseDTO.FindMyGrade findMyGrade(Member member); +} diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/service/query/GradeQueryServiceImpl.java b/src/main/java/org/withtime/be/withtimebe/domain/member/service/query/GradeQueryServiceImpl.java new file mode 100644 index 0000000..a0e611f --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/service/query/GradeQueryServiceImpl.java @@ -0,0 +1,34 @@ +package org.withtime.be.withtimebe.domain.member.service.query; + +import org.springframework.stereotype.Service; +import org.springframework.web.ErrorResponseException; +import org.withtime.be.withtimebe.domain.member.converter.GradeConverter; +import org.withtime.be.withtimebe.domain.member.dto.GradeResponseDTO; +import org.withtime.be.withtimebe.domain.member.entity.Grade; +import org.withtime.be.withtimebe.domain.member.entity.Member; +import org.withtime.be.withtimebe.domain.member.repository.GradeRepository; +import org.withtime.be.withtimebe.global.error.code.GradeErrorCode; +import org.withtime.be.withtimebe.global.error.exception.GradeException; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class GradeQueryServiceImpl implements GradeQueryService { + + private final GradeRepository gradeRepository; + + @Override + public GradeResponseDTO.FindMyGrade findMyGrade(Member member) { + + int currentPoint = member.getPoint(); + + Grade currentGrade = gradeRepository.findCurrentGrade(currentPoint) + .orElseThrow(() -> new GradeException(GradeErrorCode.GRADE_NOT_FOUND)); + + Grade nextGrade = gradeRepository.findNextGrade(currentPoint) + .orElse(null); + + return GradeConverter.toFindMyGrade(member, currentGrade, nextGrade); + } +} diff --git a/src/main/java/org/withtime/be/withtimebe/global/error/code/GradeErrorCode.java b/src/main/java/org/withtime/be/withtimebe/global/error/code/GradeErrorCode.java new file mode 100644 index 0000000..a0900c3 --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/global/error/code/GradeErrorCode.java @@ -0,0 +1,27 @@ +package org.withtime.be.withtimebe.global.error.code; + +import org.namul.api.payload.code.BaseErrorCode; +import org.namul.api.payload.code.dto.supports.DefaultResponseErrorReasonDTO; +import org.springframework.http.HttpStatus; + +import lombok.AllArgsConstructor; + +@AllArgsConstructor +public enum GradeErrorCode implements BaseErrorCode { + + GRADE_NOT_FOUND(HttpStatus.NOT_FOUND, "GRADE404_1", "등급을 찾지 못했습니다."), + ; + + private final HttpStatus httpStatus; + private final String code; + private final String message; + + @Override + public DefaultResponseErrorReasonDTO getReason() { + return DefaultResponseErrorReasonDTO.builder() + .httpStatus(this.httpStatus) + .code(this.code) + .message(this.message) + .build(); + } +} diff --git a/src/main/java/org/withtime/be/withtimebe/global/error/exception/GradeException.java b/src/main/java/org/withtime/be/withtimebe/global/error/exception/GradeException.java new file mode 100644 index 0000000..a5a8aeb --- /dev/null +++ b/src/main/java/org/withtime/be/withtimebe/global/error/exception/GradeException.java @@ -0,0 +1,10 @@ +package org.withtime.be.withtimebe.global.error.exception; + +import org.namul.api.payload.code.BaseErrorCode; +import org.namul.api.payload.error.exception.ServerApplicationException; + +public class GradeException extends ServerApplicationException { + public GradeException(BaseErrorCode code) { + super(code); + } +} From cb2a0f8140f6190389e93a13675c7c9dc1ab9259 Mon Sep 17 00:00:00 2001 From: pywoo Date: Fri, 8 Aug 2025 17:59:32 +0900 Subject: [PATCH 14/17] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor:=20Enumerat?= =?UTF-8?q?ed=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/withtime/be/withtimebe/domain/member/entity/Grade.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/entity/Grade.java b/src/main/java/org/withtime/be/withtimebe/domain/member/entity/Grade.java index 0ca83f2..8ce85f6 100644 --- a/src/main/java/org/withtime/be/withtimebe/domain/member/entity/Grade.java +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/entity/Grade.java @@ -5,6 +5,8 @@ import jakarta.persistence.Column; import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; @@ -28,6 +30,7 @@ public class Grade extends BaseEntity { @Column(name = "grade_id") private Long id; + @Enumerated(EnumType.STRING)g @Column(nullable = false, unique = true) private GradeType gradeType; From 6d08b1e41c2bc82fff5e14430f31d2b8c27d57dc Mon Sep 17 00:00:00 2001 From: pywoo Date: Fri, 8 Aug 2025 18:00:21 +0900 Subject: [PATCH 15/17] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor:=20?= =?UTF-8?q?=EC=98=A4=ED=83=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/withtime/be/withtimebe/domain/member/entity/Grade.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/entity/Grade.java b/src/main/java/org/withtime/be/withtimebe/domain/member/entity/Grade.java index 8ce85f6..353afa9 100644 --- a/src/main/java/org/withtime/be/withtimebe/domain/member/entity/Grade.java +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/entity/Grade.java @@ -30,7 +30,7 @@ public class Grade extends BaseEntity { @Column(name = "grade_id") private Long id; - @Enumerated(EnumType.STRING)g + @Enumerated(EnumType.STRING) @Column(nullable = false, unique = true) private GradeType gradeType; From c1c4ee2193ee876c91a9e917fec9760ac9e2cd5e Mon Sep 17 00:00:00 2001 From: pywoo Date: Sat, 9 Aug 2025 21:48:11 +0900 Subject: [PATCH 16/17] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor:=20?= =?UTF-8?q?=EC=98=A4=ED=83=80=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../be/withtimebe/domain/member/controller/GradeController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/controller/GradeController.java b/src/main/java/org/withtime/be/withtimebe/domain/member/controller/GradeController.java index 6b4a2ae..0e328ac 100644 --- a/src/main/java/org/withtime/be/withtimebe/domain/member/controller/GradeController.java +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/controller/GradeController.java @@ -36,7 +36,7 @@ public class GradeController { """ ) }) - @GetMapping("/grade") + @GetMapping public DefaultResponse findMyGrade(@AuthenticatedMember Member member) { GradeResponseDTO.FindMyGrade response = gradeQueryService.findMyGrade(member); return DefaultResponse.ok(response); From 082778987a4c5ace12eab6aa80f78abe77019ec9 Mon Sep 17 00:00:00 2001 From: pywoo Date: Sat, 9 Aug 2025 22:06:22 +0900 Subject: [PATCH 17/17] =?UTF-8?q?=F0=9F=90=9B=20fix:=20=EB=88=84=EB=9D=BD?= =?UTF-8?q?=20import=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../withtimebe/domain/member/controller/MemberController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/withtime/be/withtimebe/domain/member/controller/MemberController.java b/src/main/java/org/withtime/be/withtimebe/domain/member/controller/MemberController.java index d0025ae..f357664 100644 --- a/src/main/java/org/withtime/be/withtimebe/domain/member/controller/MemberController.java +++ b/src/main/java/org/withtime/be/withtimebe/domain/member/controller/MemberController.java @@ -7,7 +7,7 @@ import lombok.RequiredArgsConstructor; import org.namul.api.payload.response.DefaultResponse; -import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping;