From 71cfccd441080a474b5dc75582c584ec43a1eac5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 16 Feb 2025 00:51:55 +0900 Subject: [PATCH 01/20] =?UTF-8?q?feat(GroupController)=20:=20=EA=B7=B8?= =?UTF-8?q?=EB=A3=B9=20=EC=A1=B0=ED=9A=8C=20API=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `/api/v1/groups` 엔드포인트에 그룹 조회 기능 추가 - `GroupService.findGroups(memberId)`를 호출하여 그룹 정보를 반환 - `@GetMapping`을 사용하여 그룹 조회 요청 처리 - 현재 `@AuthenticationPrincipal`을 사용하지 않고 `memberId = 1L`로 테스트 향후 인증 정보를 적용하여 `memberId`를 동적으로 설정할 예정 --- .../org/noostak/group/api/GroupController.java | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/noostak/group/api/GroupController.java b/src/main/java/org/noostak/group/api/GroupController.java index a8b913c7..98bf0e74 100644 --- a/src/main/java/org/noostak/group/api/GroupController.java +++ b/src/main/java/org/noostak/group/api/GroupController.java @@ -5,15 +5,14 @@ import org.noostak.group.application.GroupService; import org.noostak.group.dto.request.GroupCreateRequest; import org.noostak.group.dto.response.GroupCreateResponse; +import org.noostak.group.dto.response.GroupsRetrieveResponse; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import java.io.IOException; import static org.noostak.group.common.success.GroupSuccessCode.GROUP_CREATED; +import static org.noostak.group.common.success.GroupSuccessCode.GROUP_RETRIEVED; @RestController @RequestMapping("/api/v1/groups") @@ -32,4 +31,14 @@ public ResponseEntity> createGroup( GroupCreateResponse response = groupService.createGroup(memberId, request); return ResponseEntity.ok((SuccessResponse.of(GROUP_CREATED, response))); } + + @GetMapping + public ResponseEntity> getGroups( + // @AuthenticationPrincipal Long memberId + ) { + // TODO: AuthenticationPrincipal + Long memberId = 1L; + GroupsRetrieveResponse groups = groupService.findGroups(memberId); + return ResponseEntity.ok(SuccessResponse.of(GROUP_RETRIEVED, groups)); + } } From af3120e3c4ebcbe6a248517aef71a3aac742cf5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 16 Feb 2025 00:52:10 +0900 Subject: [PATCH 02/20] =?UTF-8?q?feat(GroupRetrieveService)=20:=20?= =?UTF-8?q?=EA=B7=B8=EB=A3=B9=20=EC=A1=B0=ED=9A=8C=20=EC=84=9C=EB=B9=84?= =?UTF-8?q?=EC=8A=A4=20=EC=9D=B8=ED=84=B0=ED=8E=98=EC=9D=B4=EC=8A=A4=20?= =?UTF-8?q?=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `GroupsRetrieveResponse findGroups(Long memberId)` 메서드 추가 - 그룹 조회 기능을 위한 서비스 인터페이스 생성 - `GroupRetrieveServiceImpl`에서 해당 인터페이스를 구현하여 사용 예정 --- .../noostak/group/application/GroupRetrieveService.java | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 src/main/java/org/noostak/group/application/GroupRetrieveService.java diff --git a/src/main/java/org/noostak/group/application/GroupRetrieveService.java b/src/main/java/org/noostak/group/application/GroupRetrieveService.java new file mode 100644 index 00000000..45b41c31 --- /dev/null +++ b/src/main/java/org/noostak/group/application/GroupRetrieveService.java @@ -0,0 +1,7 @@ +package org.noostak.group.application; + +import org.noostak.group.dto.response.GroupsRetrieveResponse; + +public interface GroupRetrieveService { + GroupsRetrieveResponse findGroups(Long memberId); +} From 15dd0aa2a460854bd66b74c558e4ae29f89df9ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 16 Feb 2025 00:52:31 +0900 Subject: [PATCH 03/20] =?UTF-8?q?feat(GroupRetrieveServiceImpl)=20:=20?= =?UTF-8?q?=EA=B7=B8=EB=A3=B9=20=EC=A1=B0=ED=9A=8C=20=EC=84=9C=EB=B9=84?= =?UTF-8?q?=EC=8A=A4=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `GroupRetrieveService` 인터페이스 구현 - `findGroups(Long memberId)` 메서드를 통해 회원이 속한 그룹 조회 - `MemberGroupRepository`를 사용하여 회원 그룹 조회 및 변환 - `S3Service`를 이용해 그룹 프로필 이미지 URL 생성 - `GroupInternalRetrieveResponse`를 통해 그룹 정보를 가공 후 반환 그룹 조회 시 존재하지 않는 경우 `GroupException`을 발생시킴 --- .../application/GroupRetrieveServiceImpl.java | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 src/main/java/org/noostak/group/application/GroupRetrieveServiceImpl.java diff --git a/src/main/java/org/noostak/group/application/GroupRetrieveServiceImpl.java b/src/main/java/org/noostak/group/application/GroupRetrieveServiceImpl.java new file mode 100644 index 00000000..a6da47b8 --- /dev/null +++ b/src/main/java/org/noostak/group/application/GroupRetrieveServiceImpl.java @@ -0,0 +1,58 @@ +package org.noostak.group.application; + +import lombok.RequiredArgsConstructor; +import org.noostak.group.common.exception.GroupErrorCode; +import org.noostak.group.common.exception.GroupException; +import org.noostak.group.domain.Groups; +import org.noostak.group.dto.response.GroupInternalRetrieveResponse; +import org.noostak.group.dto.response.GroupRetrieveResponse; +import org.noostak.group.dto.response.GroupsRetrieveResponse; +import org.noostak.infra.S3Service; +import org.noostak.membergroup.domain.MemberGroup; +import org.noostak.membergroup.domain.MemberGroupRepository; +import org.noostak.membergroup.domain.MemberGroups; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class GroupRetrieveServiceImpl implements GroupRetrieveService { + + private final MemberGroupRepository memberGroupRepository; + private final S3Service s3Service; + + @Override + public GroupsRetrieveResponse findGroups(Long memberId) { + MemberGroups memberGroups = getMemberGroups(memberId); + Groups groups = convertToGroups(memberGroups); + return convertToResponse(groups); + } + + private MemberGroups getMemberGroups(Long memberId) { + List foundMemberGroups = memberGroupRepository.findByMemberId(memberId); + MemberGroups memberGroups = MemberGroups.of(foundMemberGroups); + + if (memberGroups.isEmpty()) { + throw new GroupException(GroupErrorCode.GROUP_NOT_FOUND); + } + + return memberGroups; + } + + private Groups convertToGroups(MemberGroups memberGroups) { + return Groups.of(memberGroups.toGroups()); + } + + private GroupsRetrieveResponse convertToResponse(Groups groups) { + List internalResponses = groups.getGroups().stream() + .map(group -> GroupInternalRetrieveResponse.of(group, s3Service.getImageUrl(group.getKey().value()))) + .toList(); + + List groupResponses = internalResponses.stream() + .map(internal -> GroupRetrieveResponse.of(internal.group(), internal.groupProfileImageUrl())) + .toList(); + + return GroupsRetrieveResponse.of(groupResponses); + } +} From 1f27c4915b8394677340cc0c868039ca1aad8c07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 16 Feb 2025 00:52:54 +0900 Subject: [PATCH 04/20] =?UTF-8?q?feat(GroupService)=20:=20=EA=B7=B8?= =?UTF-8?q?=EB=A3=B9=20=EC=A1=B0=ED=9A=8C=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `GroupRetrieveService`를 주입하여 그룹 조회 기능 추가 - `findGroups(Long memberId)` 메서드를 통해 그룹 목록 조회 - 기존 그룹 생성 기능(`createGroup`)과 함께 서비스 계층에서 그룹 관리 지원 그룹 조회 기능이 `GroupRetrieveServiceImpl`을 통해 실행되도록 구조 개선 --- .../java/org/noostak/group/application/GroupService.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/java/org/noostak/group/application/GroupService.java b/src/main/java/org/noostak/group/application/GroupService.java index 58aab347..6e40051d 100644 --- a/src/main/java/org/noostak/group/application/GroupService.java +++ b/src/main/java/org/noostak/group/application/GroupService.java @@ -4,6 +4,7 @@ import org.noostak.group.dto.request.GroupCreateRequest; import org.noostak.group.dto.response.GroupCreateInternalResponse; import org.noostak.group.dto.response.GroupCreateResponse; +import org.noostak.group.dto.response.GroupsRetrieveResponse; import org.springframework.stereotype.Service; import java.io.IOException; @@ -13,9 +14,14 @@ public class GroupService { private final GroupCreateService groupCreateService; + private final GroupRetrieveService groupRetrieveService; public GroupCreateResponse createGroup(Long memberId, GroupCreateRequest request) throws IOException { GroupCreateInternalResponse response = groupCreateService.createGroup(memberId, request); return GroupCreateResponse.of(response.group(), response.groupProfileImageUrl()); } + + public GroupsRetrieveResponse findGroups(Long memberId) { + return groupRetrieveService.findGroups(memberId); + } } From e95415f5fffe1ce7a8e02a7e11163d880e70d23a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 16 Feb 2025 00:53:06 +0900 Subject: [PATCH 05/20] =?UTF-8?q?del(temp)=20:=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=ED=95=98=EC=A7=80=20=EC=95=8A=EB=8A=94=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/org/noostak/membergroup/domain/temp | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/main/java/org/noostak/membergroup/domain/temp diff --git a/src/main/java/org/noostak/membergroup/domain/temp b/src/main/java/org/noostak/membergroup/domain/temp deleted file mode 100644 index e69de29b..00000000 From aead4f1f09690b051501573d3a53703a5107a723 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 16 Feb 2025 00:53:40 +0900 Subject: [PATCH 06/20] =?UTF-8?q?feat(GroupErrorCode)=20:=20=EA=B7=B8?= =?UTF-8?q?=EB=A3=B9=20=EA=B4=80=EB=A0=A8=20=EC=98=88=EC=99=B8=20=EC=BD=94?= =?UTF-8?q?=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 - `GROUP_NOT_FOUND` : 존재하지 않는 그룹 조회 시 예외 발생 - `GROUP_MEMBER_NOT_FOUND` : 그룹 내 멤버가 없을 경우 예외 발생 --- .../java/org/noostak/group/common/exception/GroupErrorCode.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/noostak/group/common/exception/GroupErrorCode.java b/src/main/java/org/noostak/group/common/exception/GroupErrorCode.java index 31c20f50..8fa98d1b 100644 --- a/src/main/java/org/noostak/group/common/exception/GroupErrorCode.java +++ b/src/main/java/org/noostak/group/common/exception/GroupErrorCode.java @@ -25,6 +25,8 @@ public enum GroupErrorCode implements ErrorCode { GROUP_CREATION_FAILED(HttpStatus.INTERNAL_SERVER_ERROR, "그룹 생성에 실패했습니다."), GROUP_PROFILE_IMAGE_DELETE_FAILED(HttpStatus.INTERNAL_SERVER_ERROR, "그룹 프로필 이미지 삭제에 실패했습니다."), + GROUP_NOT_FOUND(HttpStatus.NOT_FOUND, "그룹을 찾을 수 없습니다."), + GROUP_MEMBER_NOT_FOUND(HttpStatus.NOT_FOUND, "그룹 멤버를 찾을 수 없습니다."), ; public static final String PREFIX = "[GROUP ERROR] "; From 2082328f3c80873aaf63d06a58e2f4f04773d0dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 16 Feb 2025 00:53:57 +0900 Subject: [PATCH 07/20] =?UTF-8?q?feat(GroupSuccessCode)=20:=20=EA=B7=B8?= =?UTF-8?q?=EB=A3=B9=20=EC=A1=B0=ED=9A=8C=20=EC=84=B1=EA=B3=B5=20=EC=BD=94?= =?UTF-8?q?=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 - `GROUP_RETRIEVED` : 그룹 조회 성공 시 반환되는 메시지 추가 - HTTP 상태 코드 `200 OK` 적용 그룹 조회 API 응답을 보다 명확하게 정의하기 위해 성공 코드 추가 --- .../java/org/noostak/group/common/success/GroupSuccessCode.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/org/noostak/group/common/success/GroupSuccessCode.java b/src/main/java/org/noostak/group/common/success/GroupSuccessCode.java index 7e0932a7..32593e1c 100644 --- a/src/main/java/org/noostak/group/common/success/GroupSuccessCode.java +++ b/src/main/java/org/noostak/group/common/success/GroupSuccessCode.java @@ -9,6 +9,8 @@ @AllArgsConstructor public enum GroupSuccessCode implements SuccessCode { GROUP_CREATED(HttpStatus.CREATED, "그룹이 성공적으로 생성되었습니다."), + + GROUP_RETRIEVED(HttpStatus.OK, "그룹이 성공적으로 조회되었습니다."), ; private final HttpStatus status; From 88ef6caba5989b6f5e4fe9cf8c2fc02d61c29f0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 16 Feb 2025 00:54:16 +0900 Subject: [PATCH 08/20] =?UTF-8?q?feat(Groups)=20:=20=EA=B7=B8=EB=A3=B9=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D=EC=9D=84=20=EA=B4=80=EB=A6=AC=ED=95=98?= =?UTF-8?q?=EB=8A=94=20=EB=8F=84=EB=A9=94=EC=9D=B8=20=EA=B0=9D=EC=B2=B4=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 - `List`을 포함하는 `Groups` 클래스 생성 - `of(List)` 팩토리 메서드를 통해 객체 생성 - `getGroups()`에서 불변 리스트(`unmodifiableList`) 반환하여 캡슐화 강화 그룹 목록을 일관되게 관리하기 위해 `Groups` 도메인 객체를 도입 --- .../java/org/noostak/group/domain/Groups.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 src/main/java/org/noostak/group/domain/Groups.java diff --git a/src/main/java/org/noostak/group/domain/Groups.java b/src/main/java/org/noostak/group/domain/Groups.java new file mode 100644 index 00000000..9fdd19d0 --- /dev/null +++ b/src/main/java/org/noostak/group/domain/Groups.java @@ -0,0 +1,20 @@ +package org.noostak.group.domain; + +import java.util.Collections; +import java.util.List; + +public class Groups { + private final List groups; + + private Groups(List groups) { + this.groups = groups; + } + + public static Groups of(final List groups) { + return new Groups(groups); + } + + public List getGroups() { + return Collections.unmodifiableList(groups); + } +} From f5d5d5af7850c0e42c32a84541aa27e488aaab0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 16 Feb 2025 00:54:33 +0900 Subject: [PATCH 09/20] =?UTF-8?q?refactor(GroupCreateResponse)=20:=20?= =?UTF-8?q?=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20=EC=A4=91=EA=B4=84?= =?UTF-8?q?=ED=98=B8=20=EB=B0=8F=20=EC=A4=91=EB=B3=B5=20=EC=BD=94=EB=93=9C?= =?UTF-8?q?=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `of(Group, String)` 팩토리 메서드 내 불필요한 중괄호 제거 - `@Builder`를 사용하지 않는 방식으로 객체 생성 방식 통일 - 중복된 `return` 구문 제거하여 코드 간결화 코드 가독성을 높이고 불필요한 구조를 정리하여 유지보수성을 개선 --- .../dto/response/GroupCreateResponse.java | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/noostak/group/dto/response/GroupCreateResponse.java b/src/main/java/org/noostak/group/dto/response/GroupCreateResponse.java index d46be194..bcd2d5ae 100644 --- a/src/main/java/org/noostak/group/dto/response/GroupCreateResponse.java +++ b/src/main/java/org/noostak/group/dto/response/GroupCreateResponse.java @@ -1,9 +1,7 @@ package org.noostak.group.dto.response; -import lombok.Builder; import org.noostak.group.domain.Group; -@Builder public record GroupCreateResponse( Long groupId, String groupName, @@ -11,13 +9,11 @@ public record GroupCreateResponse( String groupInvitationCode ) { public static GroupCreateResponse of(final Group group, final String groupProfileImageUrl) { - { - return GroupCreateResponse.builder() - .groupId(group.getGroupId()) - .groupName(group.getName().value()) - .groupProfileImageUrl(groupProfileImageUrl) - .groupInvitationCode(group.getCode().value()) - .build(); - } + return new GroupCreateResponse( + group.getGroupId(), + group.getName().value(), + groupProfileImageUrl, + group.getCode().value() + ); } -} +} \ No newline at end of file From faf0acda9d8fa3391de315a35be0ba03b2344546 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 16 Feb 2025 00:54:49 +0900 Subject: [PATCH 10/20] =?UTF-8?q?feat(GroupInternalRetrieveResponse)=20:?= =?UTF-8?q?=20=EB=82=B4=EB=B6=80=20=EA=B7=B8=EB=A3=B9=20=EC=A1=B0=ED=9A=8C?= =?UTF-8?q?=20=EC=9D=91=EB=8B=B5=20DTO=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 그룹 정보를 포함하는 `GroupInternalRetrieveResponse` 생성 - `Group` 객체와 `groupProfileImageUrl`을 함께 반환 - `of(Group, String)` 팩토리 메서드를 통해 객체 생성 그룹 조회 과정에서 중간 데이터를 관리하기 위한 DTO를 추가 --- .../response/GroupInternalRetrieveResponse.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 src/main/java/org/noostak/group/dto/response/GroupInternalRetrieveResponse.java diff --git a/src/main/java/org/noostak/group/dto/response/GroupInternalRetrieveResponse.java b/src/main/java/org/noostak/group/dto/response/GroupInternalRetrieveResponse.java new file mode 100644 index 00000000..12b5519f --- /dev/null +++ b/src/main/java/org/noostak/group/dto/response/GroupInternalRetrieveResponse.java @@ -0,0 +1,15 @@ +package org.noostak.group.dto.response; + +import org.noostak.group.domain.Group; + +public record GroupInternalRetrieveResponse( + Group group, + String groupProfileImageUrl +) { + public static GroupInternalRetrieveResponse of(final Group group, final String groupProfileImageUrl) { + return new GroupInternalRetrieveResponse( + group, + groupProfileImageUrl + ); + } +} From d17114d9d4de2729272fcdb8e15bcf0fe5703349 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 16 Feb 2025 00:55:07 +0900 Subject: [PATCH 11/20] =?UTF-8?q?feat(GroupRetrieveResponse)=20:=20?= =?UTF-8?q?=EA=B7=B8=EB=A3=B9=20=EC=A1=B0=ED=9A=8C=20=EC=9D=91=EB=8B=B5=20?= =?UTF-8?q?DTO=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `GroupRetrieveResponse`를 통해 그룹 정보 반환 - `groupId`, `groupName`, `groupMemberCount`, `groupProfileImageUrl` 포함 - `of(Group, String)` 팩토리 메서드를 통해 DTO 생성 그룹 조회 API 응답을 명확하게 정의하고, DTO를 통해 응답 구조를 관리 --- .../dto/response/GroupRetrieveResponse.java | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/main/java/org/noostak/group/dto/response/GroupRetrieveResponse.java diff --git a/src/main/java/org/noostak/group/dto/response/GroupRetrieveResponse.java b/src/main/java/org/noostak/group/dto/response/GroupRetrieveResponse.java new file mode 100644 index 00000000..eef05a5e --- /dev/null +++ b/src/main/java/org/noostak/group/dto/response/GroupRetrieveResponse.java @@ -0,0 +1,19 @@ +package org.noostak.group.dto.response; + +import org.noostak.group.domain.Group; + +public record GroupRetrieveResponse( + Long groupId, + String groupName, + Long groupMemberCount, + String groupProfileImageUrl +) { + public static GroupRetrieveResponse of(final Group group, final String groupProfileImageUrl) { + return new GroupRetrieveResponse( + group.getGroupId(), + group.getName().value(), + group.getCount().value(), + groupProfileImageUrl + ); + } +} \ No newline at end of file From 998ee952f355361ab29ab728f8898331d804e493 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 16 Feb 2025 00:55:24 +0900 Subject: [PATCH 12/20] =?UTF-8?q?feat(GroupsRetrieveResponse)=20:=20?= =?UTF-8?q?=EA=B7=B8=EB=A3=B9=20=EB=AA=A9=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?=EC=9D=91=EB=8B=B5=20DTO=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 그룹 목록을 포함하는 `GroupsRetrieveResponse` 생성 - `List`를 필드로 가지며 일괄 응답 제공 - `of(List)` 팩토리 메서드를 통해 객체 생성 그룹 조회 API의 응답 구조를 일관성 있게 관리하기 위한 DTO 추가 --- .../group/dto/response/GroupsRetrieveResponse.java | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/main/java/org/noostak/group/dto/response/GroupsRetrieveResponse.java diff --git a/src/main/java/org/noostak/group/dto/response/GroupsRetrieveResponse.java b/src/main/java/org/noostak/group/dto/response/GroupsRetrieveResponse.java new file mode 100644 index 00000000..acbc6461 --- /dev/null +++ b/src/main/java/org/noostak/group/dto/response/GroupsRetrieveResponse.java @@ -0,0 +1,11 @@ +package org.noostak.group.dto.response; + +import java.util.List; + +public record GroupsRetrieveResponse( + List groups +) { + public static GroupsRetrieveResponse of(final List groupResponses) { + return new GroupsRetrieveResponse(groupResponses); + } +} From 06703daf9edfa1e62098282f59b1d7fc682717e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 16 Feb 2025 00:55:39 +0900 Subject: [PATCH 13/20] =?UTF-8?q?refactor(S3Service)=20:=20=EB=B6=88?= =?UTF-8?q?=ED=95=84=EC=9A=94=ED=95=9C=20=EB=A9=94=EC=84=9C=EB=93=9C=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0=20=EB=B0=8F=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20?= =?UTF-8?q?=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `findImageUrl(String key)` 메서드 제거 (중복 가능성 고려) - `getImageUrl(String key)` 메서드를 유지하여 일관성 확보 - `deleteImage(String key)` 포함하여 이미지 삭제 기능 명확화 S3 이미지 관리 기능을 정리하여 보다 명확한 역할을 수행하도록 개선 --- src/main/java/org/noostak/infra/S3Service.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/org/noostak/infra/S3Service.java b/src/main/java/org/noostak/infra/S3Service.java index 0d875f88..2dbe1aaf 100644 --- a/src/main/java/org/noostak/infra/S3Service.java +++ b/src/main/java/org/noostak/infra/S3Service.java @@ -6,8 +6,6 @@ public interface S3Service { KeyAndUrl uploadImage(S3DirectoryPath dirPath, MultipartFile image) throws IOException; - - String findImageUrl(String key); - + String getImageUrl(String key); void deleteImage(String key); } From a5e1dc5663061aa7f3452f24b21bc37b2380892b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 16 Feb 2025 00:56:00 +0900 Subject: [PATCH 14/20] =?UTF-8?q?refactor(S3ServiceImpl)=20:=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EB=84=A4=EC=9D=B4=EB=B0=8D=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `findImageUrl(String key)` → `getImageUrl(String key)`로 변경 - 기존 `findImageUrl` 네이밍이 불명확하여 통일성을 위해 수정 - `s3Storage.findPublicUrlByKey(key)` 호출 방식 유지 S3 이미지 URL 조회 기능의 가독성을 높이고 일관된 네이밍을 적용 --- src/main/java/org/noostak/infra/S3ServiceImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/noostak/infra/S3ServiceImpl.java b/src/main/java/org/noostak/infra/S3ServiceImpl.java index 94eb62c4..368f1778 100644 --- a/src/main/java/org/noostak/infra/S3ServiceImpl.java +++ b/src/main/java/org/noostak/infra/S3ServiceImpl.java @@ -24,7 +24,7 @@ public KeyAndUrl uploadImage(S3DirectoryPath dirPath, MultipartFile image) throw } @Override - public String findImageUrl(String key) { + public String getImageUrl(String key) { return s3Storage.findPublicUrlByKey(key); } From 3f0a29e4f0227861730101fbe62f14e244f2521a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 16 Feb 2025 00:56:26 +0900 Subject: [PATCH 15/20] =?UTF-8?q?feat(MemberGroup)=20:=20=ED=9A=8C?= =?UTF-8?q?=EC=9B=90-=EA=B7=B8=EB=A3=B9=20=EA=B4=80=EA=B3=84=20=EC=97=94?= =?UTF-8?q?=ED=8B=B0=ED=8B=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `MemberGroup` 엔티티를 생성하여 회원과 그룹의 매핑 관리 - `@ManyToOne(fetch = FetchType.LAZY)`을 사용하여 `Member` 및 `Group`과 연관 관계 설정 - `BaseTimeEntity`를 상속받아 생성 및 수정 시간 자동 관리 - `of(Member, Group)` 정적 팩토리 메서드를 추가하여 객체 생성 방식 통일 회원과 그룹 간의 관계를 관리하는 엔티티를 추가하여 도메인 구조 개선 --- .../membergroup/domain/MemberGroup.java | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 src/main/java/org/noostak/membergroup/domain/MemberGroup.java diff --git a/src/main/java/org/noostak/membergroup/domain/MemberGroup.java b/src/main/java/org/noostak/membergroup/domain/MemberGroup.java new file mode 100644 index 00000000..b2ca0246 --- /dev/null +++ b/src/main/java/org/noostak/membergroup/domain/MemberGroup.java @@ -0,0 +1,35 @@ +package org.noostak.membergroup.domain; + +import jakarta.persistence.*; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.noostak.global.entity.BaseTimeEntity; +import org.noostak.group.domain.Group; +import org.noostak.member.domain.Member; + +@Entity +@Getter +@NoArgsConstructor +public class MemberGroup extends BaseTimeEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long memberGroupId; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id") + private Member member; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "group_id") + private Group group; + + private MemberGroup(final Member member, final Group groups) { + this.member = member; + this.group = groups; + } + + public static MemberGroup of(final Member member, final Group group) { + return new MemberGroup(member, group); + } +} From 5a077add04065d61460949d50956e283990e9052 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 16 Feb 2025 00:56:41 +0900 Subject: [PATCH 16/20] =?UTF-8?q?feat(MemberGroupRepository)=20:=20?= =?UTF-8?q?=ED=9A=8C=EC=9B=90-=EA=B7=B8=EB=A3=B9=20=EA=B4=80=EA=B3=84=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=EB=A5=BC=20=EC=9C=84=ED=95=9C=20=EB=A0=88?= =?UTF-8?q?=ED=8F=AC=EC=A7=80=ED=86=A0=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `JpaRepository`을 상속하여 기본 CRUD 기능 제공 - `findByMemberId(Long memberId)` 메서드를 추가하여 특정 회원의 그룹 조회 지원 회원이 속한 그룹을 효율적으로 조회할 수 있도록 레포지토리 구현 --- .../membergroup/domain/MemberGroupRepository.java | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 src/main/java/org/noostak/membergroup/domain/MemberGroupRepository.java diff --git a/src/main/java/org/noostak/membergroup/domain/MemberGroupRepository.java b/src/main/java/org/noostak/membergroup/domain/MemberGroupRepository.java new file mode 100644 index 00000000..0db9351c --- /dev/null +++ b/src/main/java/org/noostak/membergroup/domain/MemberGroupRepository.java @@ -0,0 +1,10 @@ +package org.noostak.membergroup.domain; + +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +public interface MemberGroupRepository extends JpaRepository { + + List findByMemberId(Long memberId); +} From 0ea880732d99fd119c1178fccb553143333cf46e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 16 Feb 2025 00:56:56 +0900 Subject: [PATCH 17/20] =?UTF-8?q?refactor(MemberGroups)=20:=20=ED=9A=8C?= =?UTF-8?q?=EC=9B=90-=EA=B7=B8=EB=A3=B9=20=EC=BB=AC=EB=A0=89=EC=85=98=20?= =?UTF-8?q?=EA=B4=80=EB=A6=AC=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `MemberGroups`를 엔티티에서 일급 컬렉션으로 변경하여 관리 - `BaseTimeEntity` 상속 제거 (별도 관리 필요 없음) - `List`을 불변 리스트로 반환하는 `getMemberGroups()` 추가 - `toGroups()` 메서드를 통해 `List` 변환 지원 - `isEmpty()` 메서드를 추가하여 빈 목록 확인 기능 제공 회원-그룹 관계를 보다 명확하게 관리하기 위해 컬렉션 객체로 개선 --- .../membergroup/domain/MemberGroups.java | 42 +++++++++---------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/src/main/java/org/noostak/membergroup/domain/MemberGroups.java b/src/main/java/org/noostak/membergroup/domain/MemberGroups.java index 17c4f3b8..483d9757 100644 --- a/src/main/java/org/noostak/membergroup/domain/MemberGroups.java +++ b/src/main/java/org/noostak/membergroup/domain/MemberGroups.java @@ -1,35 +1,31 @@ package org.noostak.membergroup.domain; -import jakarta.persistence.*; -import lombok.Getter; -import lombok.NoArgsConstructor; -import org.noostak.global.entity.BaseTimeEntity; import org.noostak.group.domain.Group; -import org.noostak.member.domain.Member; +import java.util.Collections; +import java.util.List; -@Entity -@Getter -@NoArgsConstructor -public class MemberGroups extends BaseTimeEntity { +public class MemberGroups { + private final List memberGroups; - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long memberGroupId; + private MemberGroups(List memberGroups) { + this.memberGroups = memberGroups; + } - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "member_id") - private Member member; + public static MemberGroups of(final List memberGroups) { + return new MemberGroups(memberGroups); + } - @ManyToOne(fetch = FetchType.LAZY) - @JoinColumn(name = "group_id") - private Group group; + public List getMemberGroups() { + return Collections.unmodifiableList(memberGroups); + } - private MemberGroups(final Member member, final Group groups) { - this.member = member; - this.group = groups; + public List toGroups() { + return memberGroups.stream() + .map(MemberGroup::getGroup) + .toList(); } - public static MemberGroups of(final Member member, final Group group) { - return new MemberGroups(member, group); + public boolean isEmpty() { + return memberGroups.isEmpty(); } } From 1a8e1c6a1df0a66f9049140747337a2f326bdc1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 16 Feb 2025 00:57:12 +0900 Subject: [PATCH 18/20] =?UTF-8?q?test(GroupRetrieveServiceImpl)=20:=20?= =?UTF-8?q?=EA=B7=B8=EB=A3=B9=20=EC=A1=B0=ED=9A=8C=20=EC=84=9C=EB=B9=84?= =?UTF-8?q?=EC=8A=A4=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `GroupRetrieveServiceImplTest`를 추가하여 그룹 조회 기능 검증 - 성공 케이스: - 멤버가 여러 개의 그룹을 조회하는 경우 - 하나의 그룹만 속한 경우 정상 조회 - 여러 명의 멤버가 같은 그룹에 속한 경우 특정 멤버 조회 - 실패 케이스: - 멤버가 속한 그룹이 없는 경우 예외 발생 - 그룹이 삭제된 후 멤버가 속한 그룹을 조회하면 예외 발생 - 멤버 ID가 `null`이면 `GroupException` 발생 그룹 조회 서비스의 정상 동작과 예외 처리를 검증하기 위한 단위 테스트 추가 --- .../GroupRetrieveServiceImplTest.java | 202 ++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 src/test/java/org/noostak/group/application/GroupRetrieveServiceImplTest.java diff --git a/src/test/java/org/noostak/group/application/GroupRetrieveServiceImplTest.java b/src/test/java/org/noostak/group/application/GroupRetrieveServiceImplTest.java new file mode 100644 index 00000000..aa8bd091 --- /dev/null +++ b/src/test/java/org/noostak/group/application/GroupRetrieveServiceImplTest.java @@ -0,0 +1,202 @@ +package org.noostak.group.application; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.noostak.group.common.exception.GroupErrorCode; +import org.noostak.group.common.exception.GroupException; +import org.noostak.group.domain.Group; +import org.noostak.group.domain.GroupRepository; +import org.noostak.group.domain.vo.GroupName; +import org.noostak.group.domain.vo.GroupProfileImageKey; +import org.noostak.group.dto.response.GroupsRetrieveResponse; +import org.noostak.infra.S3Service; +import org.noostak.member.MemberRepositoryTest; +import org.noostak.member.domain.Member; +import org.noostak.member.domain.MemberRepository; +import org.noostak.member.domain.vo.AuthId; +import org.noostak.member.domain.vo.AuthType; +import org.noostak.member.domain.vo.MemberName; +import org.noostak.member.domain.vo.MemberProfileImageKey; +import org.noostak.membergroup.MemberGroupRepositoryTest; +import org.noostak.membergroup.domain.MemberGroup; +import org.noostak.membergroup.domain.MemberGroupRepository; +import org.noostak.server.group.domain.GroupRepositoryTest; + +import java.util.List; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.mock; + +class GroupRetrieveServiceImplTest { + + private MemberRepository memberRepository; + private GroupRepository groupRepository; + private MemberGroupRepository memberGroupRepository; + private GroupRetrieveServiceImpl groupRetrieveService; + private final S3Service s3Service = mock(S3Service.class); + + private Long savedMemberId; + private Long savedGroup1Id; + private Long savedGroup2Id; + private Long savedGroup3Id; + + @BeforeEach + void setUp() { + memberRepository = new MemberRepositoryTest(); + memberGroupRepository = new MemberGroupRepositoryTest(); + groupRepository = new GroupRepositoryTest(); + memberGroupRepository.deleteAll(); + + groupRetrieveService = new GroupRetrieveServiceImpl(memberGroupRepository, s3Service); + + Member savedMember = saveMember("MemberOne", "key1", "authId1", "refreshToken1"); + savedMemberId = savedMember.getMemberId(); + + Group savedGroup1 = saveGroup(savedMemberId, "StudyGroup", "group-images/1", "ABC123"); + Group savedGroup2 = saveGroup(savedMemberId, "GamingClub", "group-images/2", "XYZ789"); + Group savedGroup3 = saveGroup(savedMemberId, "BookClub", "group-images/3", "LMN456"); + savedGroup1Id = savedGroup1.getGroupId(); + savedGroup2Id = savedGroup2.getGroupId(); + savedGroup3Id = savedGroup3.getGroupId(); + + saveMemberGroup(savedMemberId, savedGroup1Id); + saveMemberGroup(savedMemberId, savedGroup2Id); + saveMemberGroup(savedMemberId, savedGroup3Id); + } + + + @Nested + @DisplayName("성공 케이스") + class Success { + + @Test + @DisplayName("멤버가 여러 개의 그룹을 정상적으로 조회한다.") + void shouldRetrieveMultipleGroupsSuccessfully() { + // given + Long memberId = savedMemberId; + + List memberGroups = memberGroupRepository.findByMemberId(memberId); + assertThat(memberGroups).isNotEmpty(); + + // when + GroupsRetrieveResponse response = groupRetrieveService.findGroups(memberId); + + // then + assertThat(response).isNotNull(); + assertThat(response.groups()).hasSize(3); + } + + @Test + @DisplayName("멤버가 하나의 그룹만 속해 있는 경우 정상 조회") + void shouldRetrieveSingleGroupSuccessfully() { + // given + Long memberId = saveMember("singleUser", "keySingle", "authIdSingle", "refreshTokenSingle").getMemberId(); + Long groupId = saveGroup(memberId, "SingleGroup", "group-images/single", "SINGLE").getGroupId(); + saveMemberGroup(memberId, groupId); + + // when + GroupsRetrieveResponse response = groupRetrieveService.findGroups(memberId); + + // then + assertThat(response).isNotNull(); + assertThat(response.groups()).hasSize(1); + } + + @Test + @DisplayName("여러 명의 멤버가 같은 그룹에 속한 경우 특정 멤버가 정상적으로 조회") + void shouldRetrieveGroupsWhenMultipleMembersInSameGroup() { + // given + Long member1 = saveMember("memberOne", "key1", "authId1", "refreshToken1").getMemberId(); + Long member2 = saveMember("memberTwo", "key2", "authId2", "refreshToken2").getMemberId(); + Long groupId = saveGroup(member1, "SharedGroup", "group-images/shared", "SHARED").getGroupId(); + + saveMemberGroup(member1, groupId); + saveMemberGroup(member2, groupId); + + // when + GroupsRetrieveResponse response1 = groupRetrieveService.findGroups(member1); + GroupsRetrieveResponse response2 = groupRetrieveService.findGroups(member2); + + // then + assertThat(response1.groups()).hasSize(1); + assertThat(response2.groups()).hasSize(1); + } + } + + @Nested + @DisplayName("실패 케이스") + class Failure { + + @Test + @DisplayName("멤버가 속한 그룹이 없는 경우 예외를 발생시킨다.") + void shouldThrowExceptionWhenNoGroupsFound() { + // given + Long invalidMemberId = 999L; + + // when & then + assertThatThrownBy(() -> groupRetrieveService.findGroups(invalidMemberId)) + .isInstanceOf(GroupException.class) + .hasMessage(GroupErrorCode.GROUP_NOT_FOUND.getMessage()); + } + + @Test + @DisplayName("그룹이 삭제된 후 멤버가 속한 그룹을 조회하면 예외 발생") + void shouldThrowExceptionWhenGroupIsDeleted() { + // given + Long memberId = savedMemberId; + memberGroupRepository.deleteAll(); + + // when & then + assertThatThrownBy(() -> groupRetrieveService.findGroups(memberId)) + .isInstanceOf(GroupException.class) + .hasMessage(GroupErrorCode.GROUP_NOT_FOUND.getMessage()); + } + + @Test + @DisplayName("멤버 ID가 null이면 GroupException 발생") + void shouldThrowExceptionWhenMemberIdIsNull() { + // when & then + assertThatThrownBy(() -> groupRetrieveService.findGroups(null)) + .isInstanceOf(GroupException.class) + .hasMessage(GroupErrorCode.GROUP_NOT_FOUND.getMessage()); + } + } + + private Group saveGroup(Long groupHostId, String groupName, String groupImageUrl, String inviteCode) { + return groupRepository.save( + Group.of( + groupHostId, + GroupName.from(groupName), + GroupProfileImageKey.from(groupImageUrl), + inviteCode + ) + ); + } + + private Member saveMember(String name, String key, String authId, String refreshToken) { + return memberRepository.save( + Member.of( + MemberName.from(name), + MemberProfileImageKey.from(key), + AuthType.GOOGLE, + AuthId.from(authId), + refreshToken + ) + ); + } + + private MemberGroup saveMemberGroup(Long memberId, Long groupId) { + Member member = memberRepository.findById(memberId) + .orElseThrow(() -> new GroupException(GroupErrorCode.GROUP_MEMBER_NOT_FOUND)); + + Group group = groupRepository.findById(groupId) + .orElseThrow(() -> new GroupException(GroupErrorCode.GROUP_NOT_FOUND)); + + MemberGroup memberGroup = MemberGroup.of(member, group); + MemberGroup savedMemberGroup = memberGroupRepository.save(memberGroup); + + return savedMemberGroup; + } +} From 1b15541ff4c7d025d6f7680f1e6896eeb8143798 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 16 Feb 2025 00:57:27 +0900 Subject: [PATCH 19/20] =?UTF-8?q?refactor(GroupRepositoryTest)=20:=20?= =?UTF-8?q?=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C=20=EA=B0=9C=ED=96=89=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0=20=EB=B0=8F=20=EC=BD=94=EB=93=9C=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `GroupRepositoryTest` 클래스의 불필요한 개행 제거 - 코드 스타일을 일관되게 유지하여 가독성 개선 테스트 코드 유지보수성을 높이기 위해 불필요한 공백을 정리 --- src/test/java/org/noostak/group/domain/GroupRepositoryTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/org/noostak/group/domain/GroupRepositoryTest.java b/src/test/java/org/noostak/group/domain/GroupRepositoryTest.java index 04f2ab5c..58b5772f 100644 --- a/src/test/java/org/noostak/group/domain/GroupRepositoryTest.java +++ b/src/test/java/org/noostak/group/domain/GroupRepositoryTest.java @@ -2,6 +2,7 @@ import org.noostak.group.domain.Group; import org.noostak.group.domain.GroupRepository; +import org.noostak.group.domain.Groups; import org.springframework.context.annotation.Primary; import org.springframework.data.domain.Example; import org.springframework.data.domain.Page; @@ -191,5 +192,4 @@ public List findAll(Sort sort) { public Page findAll(Pageable pageable) { return null; } - } From 0703f8390688b5cbaa50a9f0c0746a68d1e3d47c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E1=84=80=E1=85=AF=E1=86=AB=E1=84=8C=E1=85=A1=E1=86=BC?= =?UTF-8?q?=E1=84=89=E1=85=AE=E1=86=AB?= Date: Sun, 16 Feb 2025 00:57:43 +0900 Subject: [PATCH 20/20] =?UTF-8?q?test(MemberGroupRepositoryTest)=20:=20?= =?UTF-8?q?=ED=9A=8C=EC=9B=90-=EA=B7=B8=EB=A3=B9=20=EA=B4=80=EA=B3=84=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EB=A6=AC=ED=8F=AC=EC=A7=80?= =?UTF-8?q?=ED=86=A0=EB=A6=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `MemberGroupRepositoryTest`를 구현하여 인메모리 방식으로 테스트 가능하도록 구성 - `save(MemberGroup)` 메서드에서 `memberGroupId` 자동 증가 처리 - `findByMemberId(Long memberId)`를 통해 특정 회원의 그룹 조회 기능 제공 - `deleteAll()` 및 `deleteById(Long id)`를 구현하여 데이터 초기화 지원 - JPA 기본 메서드를 오버라이드하되, 테스트에 필요한 기능만 구현 회원-그룹 관계를 테스트할 수 있도록 리포지토리를 인메모리 방식으로 구현 --- .../MemberGroupRepositoryTest.java | 196 ++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 src/test/java/org/noostak/membergroup/MemberGroupRepositoryTest.java diff --git a/src/test/java/org/noostak/membergroup/MemberGroupRepositoryTest.java b/src/test/java/org/noostak/membergroup/MemberGroupRepositoryTest.java new file mode 100644 index 00000000..2991813e --- /dev/null +++ b/src/test/java/org/noostak/membergroup/MemberGroupRepositoryTest.java @@ -0,0 +1,196 @@ +package org.noostak.membergroup; + +import org.noostak.membergroup.domain.MemberGroup; +import org.noostak.membergroup.domain.MemberGroupRepository; +import org.springframework.data.domain.*; +import org.springframework.data.repository.query.FluentQuery; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicLong; +import java.util.function.Function; + +public class MemberGroupRepositoryTest implements MemberGroupRepository { + + private final List memberGroups = new ArrayList<>(); + private final AtomicLong idGenerator = new AtomicLong(1); + + @Override + public MemberGroup save(MemberGroup memberGroup) { + try { + if (memberGroup.getMemberGroupId() == null) { + var idField = MemberGroup.class.getDeclaredField("memberGroupId"); + idField.setAccessible(true); + idField.set(memberGroup, idGenerator.getAndIncrement()); + } + } catch (NoSuchFieldException e) { + throw new RuntimeException("[ERROR] 'memberGroupId' 필드를 MemberGroup 클래스에서 찾을 수 없습니다. 필드 이름이 정확한지 확인하세요.", e); + } catch (IllegalAccessException e) { + throw new RuntimeException("[ERROR] MemberGroup 클래스의 'memberGroupId' 필드에 접근할 수 없습니다. 접근 제한자가 적절한지 확인하세요.", e); + } + memberGroups.add(memberGroup); + return memberGroup; + } + + @Override + public Optional findById(Long id) { + return memberGroups.stream() + .filter(memberGroup -> memberGroup.getMemberGroupId().equals(id)) + .findFirst(); + } + + @Override + public List findByMemberId(Long memberId) { + return memberGroups.stream() + .filter(memberGroup -> memberGroup.getMember().getMemberId().equals(memberId)) + .toList(); + } + + @Override + public List findAll() { + return new ArrayList<>(memberGroups); + } + + @Override + public void deleteAll() { + memberGroups.clear(); + } + + @Override + public void deleteById(Long id) { + memberGroups.removeIf(memberGroup -> memberGroup.getMemberGroupId().equals(id)); + } + + @Override + public void delete(MemberGroup entity) { + + } + + @Override + public void deleteAllById(Iterable longs) { + + } + + @Override + public void deleteAll(Iterable entities) { + + } + + @Override + public boolean existsById(Long id) { + return memberGroups.stream().anyMatch(memberGroup -> memberGroup.getMemberGroupId().equals(id)); + } + + @Override + public long count() { + return memberGroups.size(); + } + + @Override + public List findAllById(Iterable ids) { + List result = new ArrayList<>(); + ids.forEach(id -> findById(id).ifPresent(result::add)); + return result; + } + + @Override + public List saveAll(Iterable entities) { + List result = new ArrayList<>(); + entities.forEach(entity -> { + MemberGroup savedMemberGroup = save(entity); + result.add((S) savedMemberGroup); + }); + return result; + } + + @Override + public void flush() { + + } + + @Override + public S saveAndFlush(S entity) { + return null; + } + + @Override + public List saveAllAndFlush(Iterable entities) { + return List.of(); + } + + @Override + public void deleteAllInBatch(Iterable entities) { + + } + + @Override + public void deleteAllByIdInBatch(Iterable longs) { + + } + + @Override + public void deleteAllInBatch() { + + } + + @Override + public MemberGroup getOne(Long aLong) { + return null; + } + + @Override + public MemberGroup getById(Long aLong) { + return null; + } + + @Override + public MemberGroup getReferenceById(Long aLong) { + return null; + } + + @Override + public Optional findOne(Example example) { + return Optional.empty(); + } + + @Override + public List findAll(Example example) { + return List.of(); + } + + @Override + public List findAll(Example example, Sort sort) { + return List.of(); + } + + @Override + public Page findAll(Example example, Pageable pageable) { + return null; + } + + @Override + public long count(Example example) { + return 0; + } + + @Override + public boolean exists(Example example) { + return false; + } + + @Override + public R findBy(Example example, Function, R> queryFunction) { + return null; + } + + @Override + public List findAll(Sort sort) { + return List.of(); + } + + @Override + public Page findAll(Pageable pageable) { + return null; + } +}