From 28928ac85c102e99cb387696744f57155795bb41 Mon Sep 17 00:00:00 2001 From: choiseoji Date: Sat, 2 Aug 2025 00:18:50 +0900 Subject: [PATCH 01/14] =?UTF-8?q?[#28]=20delete:=20=EC=82=AC=EC=9A=A9?= =?UTF-8?q?=ED=95=98=EC=A7=80=20=EC=95=8A=EB=8A=94=20DTO=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/crew/dto/response/CrewMemberProfile.java | 4 ---- .../domain/crew/dto/response/CrewMemberResponse.java | 8 -------- 2 files changed, 12 deletions(-) delete mode 100644 src/main/java/run/backend/domain/crew/dto/response/CrewMemberProfile.java delete mode 100644 src/main/java/run/backend/domain/crew/dto/response/CrewMemberResponse.java diff --git a/src/main/java/run/backend/domain/crew/dto/response/CrewMemberProfile.java b/src/main/java/run/backend/domain/crew/dto/response/CrewMemberProfile.java deleted file mode 100644 index d65e068..0000000 --- a/src/main/java/run/backend/domain/crew/dto/response/CrewMemberProfile.java +++ /dev/null @@ -1,4 +0,0 @@ -package run.backend.domain.crew.dto.response; - -public record CrewMemberProfile() { -} diff --git a/src/main/java/run/backend/domain/crew/dto/response/CrewMemberResponse.java b/src/main/java/run/backend/domain/crew/dto/response/CrewMemberResponse.java deleted file mode 100644 index 693abe3..0000000 --- a/src/main/java/run/backend/domain/crew/dto/response/CrewMemberResponse.java +++ /dev/null @@ -1,8 +0,0 @@ -package run.backend.domain.crew.dto.response; - -import java.util.List; - -public record CrewMemberResponse( - List crewMembers -) { -} From 9e71e97b058804328049eefbbabd55efaf30b86b Mon Sep 17 00:00:00 2001 From: choiseoji Date: Sat, 2 Aug 2025 00:19:26 +0900 Subject: [PATCH 02/14] =?UTF-8?q?[#28]=20feat:=20=ED=81=AC=EB=A3=A8?= =?UTF-8?q?=EC=9B=90=20=EC=A1=B0=ED=9A=8C,=20=ED=81=AC=EB=A3=A8=EC=9B=90?= =?UTF-8?q?=20=EC=97=AD=ED=95=A0=20=EB=B3=80=EA=B2=BD=20API=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 --- .../crew/controller/CrewController.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/main/java/run/backend/domain/crew/controller/CrewController.java b/src/main/java/run/backend/domain/crew/controller/CrewController.java index d70ac7b..a2d00ee 100644 --- a/src/main/java/run/backend/domain/crew/controller/CrewController.java +++ b/src/main/java/run/backend/domain/crew/controller/CrewController.java @@ -8,9 +8,11 @@ import org.springframework.web.multipart.MultipartFile; import run.backend.domain.crew.dto.common.CrewInviteCodeDto; import run.backend.domain.crew.dto.request.CrewInfoRequest; +import run.backend.domain.crew.dto.request.MemberRoleChangeRequest; import run.backend.domain.crew.dto.response.*; import run.backend.domain.crew.entity.Crew; import run.backend.domain.crew.service.CrewEventService; +import run.backend.domain.crew.service.CrewMemberService; import run.backend.domain.crew.service.CrewRankingService; import run.backend.domain.crew.service.CrewService; import run.backend.domain.member.entity.Member; @@ -27,6 +29,7 @@ public class CrewController { private final CrewService crewService; private final CrewEventService crewEventService; + private final CrewMemberService crewMemberService; private final CrewRankingService crewRankingService; @PostMapping @@ -132,4 +135,23 @@ public CommonResponse getCrewRankingsStatus(@MemberCr CrewRankingStatusResponse response = crewRankingService.getCrewRankingStatus(crew); return new CommonResponse<>("크루 땅따먹기 현황 조회 성공", response); } + + @GetMapping("/members") + @Operation(summary = "크루원 조회", description = "전체 크루원 조회하는 API 입니다.") + public CommonResponse getCrewMembers(@MemberCrew Crew crew) { + + CrewMemberResponse response = crewMemberService.getCrewMembers(crew); + return new CommonResponse<>("크루원 조회 성공", response); + } + + @PostMapping("/members/{memberId}/role") + @PreAuthorize("hasRole('MANAGER') or hasRole('LEADER')") + @Operation(summary = "크루원 역할 변경", description = "크루원 역할 변경하는 API 입니다.") + public CommonResponse updateCrewMemberRole( + @PathVariable Long memberId, + @RequestBody MemberRoleChangeRequest request + ) { + crewMemberService.updateCrewMemberRole(memberId, request); + return new CommonResponse<>("크루원 역할 변경 성공"); + } } From f5e93a1d78cc66f290564599371e500891fc4c2e Mon Sep 17 00:00:00 2001 From: choiseoji Date: Sat, 2 Aug 2025 00:19:50 +0900 Subject: [PATCH 03/14] =?UTF-8?q?[#28]=20feat:=20CrewMemberResponse?= =?UTF-8?q?=EB=A1=9C=20=EB=A7=A4=ED=95=91=ED=95=98=EB=8A=94=20CrewMapper?= =?UTF-8?q?=20=EC=BD=94=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 --- .../domain/crew/mapper/CrewMapper.java | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/src/main/java/run/backend/domain/crew/mapper/CrewMapper.java b/src/main/java/run/backend/domain/crew/mapper/CrewMapper.java index 447f22c..4e487f3 100644 --- a/src/main/java/run/backend/domain/crew/mapper/CrewMapper.java +++ b/src/main/java/run/backend/domain/crew/mapper/CrewMapper.java @@ -3,13 +3,12 @@ import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.ReportingPolicy; -import run.backend.domain.crew.dto.response.CrewBaseInfoResponse; -import run.backend.domain.crew.dto.response.CrewProfileResponse; -import run.backend.domain.crew.dto.response.CrewRankingResponse; -import run.backend.domain.crew.dto.response.CrewRankingStatusResponse; +import run.backend.domain.crew.dto.response.*; import run.backend.domain.crew.entity.Crew; import run.backend.domain.member.entity.Member; +import run.backend.domain.member.enums.Role; +import java.util.ArrayList; import java.util.List; @Mapper( @@ -26,6 +25,26 @@ public interface CrewMapper { List toCrewRankingResponseList(List crews); + @Mapping(source = "profileImage", target = "image") + CrewMemberProfileResponse toCrewMemberProfile(Member member); + + default CrewMemberResponse toCrewMemberResponse(List crewMembers) { + List managers = new ArrayList<>(); + List members = new ArrayList<>(); + + for (Member member : crewMembers) { + CrewMemberProfileResponse profile = toCrewMemberProfile(member); + + if (member.getRole() == Role.MEMBER) { + members.add(profile); + } else { + managers.add(profile); + } + } + + return new CrewMemberResponse(managers, members); + } + default Crew toEntity(String imageName, String name, String description) { return Crew.builder() .image(imageName) From 9bfdcb3219fec54e0396c1686b064a7c90931d72 Mon Sep 17 00:00:00 2001 From: choiseoji Date: Sat, 2 Aug 2025 09:41:43 +0900 Subject: [PATCH 04/14] =?UTF-8?q?[#28]=20feat:=20crew=20=EA=B2=80=EC=83=89?= =?UTF-8?q?=20API=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/crew/controller/CrewController.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/java/run/backend/domain/crew/controller/CrewController.java b/src/main/java/run/backend/domain/crew/controller/CrewController.java index a2d00ee..bccd8fc 100644 --- a/src/main/java/run/backend/domain/crew/controller/CrewController.java +++ b/src/main/java/run/backend/domain/crew/controller/CrewController.java @@ -154,4 +154,15 @@ public CommonResponse updateCrewMemberRole( crewMemberService.updateCrewMemberRole(memberId, request); return new CommonResponse<>("크루원 역할 변경 성공"); } + + @GetMapping("/search") + @Operation(summary = "크루 검색", description = "크루 이름으로 검색 API 입니다.") + public CommonResponse> searchCrew( + @RequestParam String crewName, + @RequestParam(defaultValue = "0") int page, + @RequestParam(defaultValue = "10") int size + ) { + PageResponse response = crewService.searchCrewsByName(crewName, page, size); + return new CommonResponse<>("크루 검색 성공", response); + } } From 917f4b08d93a387b95dec6a77c64151d94de242c Mon Sep 17 00:00:00 2001 From: choiseoji Date: Sat, 2 Aug 2025 09:42:14 +0900 Subject: [PATCH 05/14] =?UTF-8?q?[#28]=20feat:=20query=20dto=EC=97=90?= =?UTF-8?q?=EC=84=9C=20response=20dto=EB=A1=9C=20=EB=B3=80=ED=99=98?= =?UTF-8?q?=ED=95=98=EB=8A=94=20mapper=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/crew/mapper/CrewMapper.java | 24 +++++-------------- 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/src/main/java/run/backend/domain/crew/mapper/CrewMapper.java b/src/main/java/run/backend/domain/crew/mapper/CrewMapper.java index 4e487f3..2ee9bb9 100644 --- a/src/main/java/run/backend/domain/crew/mapper/CrewMapper.java +++ b/src/main/java/run/backend/domain/crew/mapper/CrewMapper.java @@ -3,12 +3,12 @@ import org.mapstruct.Mapper; import org.mapstruct.Mapping; import org.mapstruct.ReportingPolicy; +import run.backend.domain.crew.dto.query.CrewMemberProfileDto; +import run.backend.domain.crew.dto.query.CrewProfileDto; import run.backend.domain.crew.dto.response.*; import run.backend.domain.crew.entity.Crew; import run.backend.domain.member.entity.Member; -import run.backend.domain.member.enums.Role; -import java.util.ArrayList; import java.util.List; @Mapper( @@ -25,25 +25,13 @@ public interface CrewMapper { List toCrewRankingResponseList(List crews); - @Mapping(source = "profileImage", target = "image") - CrewMemberProfileResponse toCrewMemberProfile(Member member); + CrewMemberProfileResponse toCrewMemberProfileResponse(CrewMemberProfileDto dto); - default CrewMemberResponse toCrewMemberResponse(List crewMembers) { - List managers = new ArrayList<>(); - List members = new ArrayList<>(); + List toCrewMemberProfileResponseList(List dtos); - for (Member member : crewMembers) { - CrewMemberProfileResponse profile = toCrewMemberProfile(member); + CrewSearchResponse toCrewSearchResponse(CrewProfileDto dto); - if (member.getRole() == Role.MEMBER) { - members.add(profile); - } else { - managers.add(profile); - } - } - - return new CrewMemberResponse(managers, members); - } + List toCrewSearchResponseList(List dtos); default Crew toEntity(String imageName, String name, String description) { return Crew.builder() From ac397d334e3684a78e7d370cea3f8f7aaa029410 Mon Sep 17 00:00:00 2001 From: choiseoji Date: Sat, 2 Aug 2025 09:42:37 +0900 Subject: [PATCH 06/14] =?UTF-8?q?[#28]=20feat:=20=EA=B2=80=EC=83=89=20repo?= =?UTF-8?q?sitory=20=EC=BD=94=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 --- .../domain/crew/repository/CrewRepository.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/main/java/run/backend/domain/crew/repository/CrewRepository.java b/src/main/java/run/backend/domain/crew/repository/CrewRepository.java index 6c53f0e..a32d74b 100644 --- a/src/main/java/run/backend/domain/crew/repository/CrewRepository.java +++ b/src/main/java/run/backend/domain/crew/repository/CrewRepository.java @@ -3,6 +3,8 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import run.backend.domain.crew.dto.query.CrewProfileDto; import run.backend.domain.crew.entity.Crew; import java.util.Optional; @@ -13,4 +15,15 @@ public interface CrewRepository extends JpaRepository { Page findAllByOrderByMonthlyScoreTotalDesc(Pageable pageable); + + @Query(""" + SELECT new run.backend.domain.crew.dto.query.CrewProfileDto( + c.image, + c.name, + c.description + ) + FROM Crew c + WHERE LOWER(c.name) LIKE LOWER(CONCAT('%', :name, '%')) + """) + Page findByNameContainingIgnoreCase(String name, Pageable pageable); } From ba879fafbe8ae00cdbbf7b195ff02fec97644c48 Mon Sep 17 00:00:00 2001 From: choiseoji Date: Sat, 2 Aug 2025 09:42:53 +0900 Subject: [PATCH 07/14] =?UTF-8?q?[#28]=20feat:=20=EA=B2=80=EC=83=89=20resp?= =?UTF-8?q?onse=20dto=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/domain/crew/dto/response/CrewSearchResponse.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/run/backend/domain/crew/dto/response/CrewSearchResponse.java b/src/main/java/run/backend/domain/crew/dto/response/CrewSearchResponse.java index 448ea7d..aa2334b 100644 --- a/src/main/java/run/backend/domain/crew/dto/response/CrewSearchResponse.java +++ b/src/main/java/run/backend/domain/crew/dto/response/CrewSearchResponse.java @@ -1,8 +1,9 @@ package run.backend.domain.crew.dto.response; -import java.util.List; public record CrewSearchResponse( - List crewProfiles + String image, + String name, + String description ) { } From adffd969d8ae36bac78c7b09205e0fcba2766d19 Mon Sep 17 00:00:00 2001 From: choiseoji Date: Sat, 2 Aug 2025 09:43:09 +0900 Subject: [PATCH 08/14] =?UTF-8?q?[#28]=20feat:=20=EA=B2=80=EC=83=89=20?= =?UTF-8?q?=EC=84=9C=EB=B9=84=EC=8A=A4=20=EC=BD=94=EB=93=9C=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 --- .../backend/domain/crew/service/CrewService.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main/java/run/backend/domain/crew/service/CrewService.java b/src/main/java/run/backend/domain/crew/service/CrewService.java index 8987602..dc12566 100644 --- a/src/main/java/run/backend/domain/crew/service/CrewService.java +++ b/src/main/java/run/backend/domain/crew/service/CrewService.java @@ -1,10 +1,13 @@ package run.backend.domain.crew.service; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; import run.backend.domain.crew.dto.common.CrewInviteCodeDto; +import run.backend.domain.crew.dto.query.CrewProfileDto; import run.backend.domain.crew.dto.request.CrewInfoRequest; import run.backend.domain.crew.dto.response.*; import run.backend.domain.crew.entity.Crew; @@ -18,6 +21,9 @@ import run.backend.domain.member.entity.Member; import run.backend.domain.member.enums.Role; import run.backend.domain.member.repository.MemberRepository; +import run.backend.global.common.response.PageResponse; + +import java.util.List; @Service @RequiredArgsConstructor @@ -93,4 +99,12 @@ public CrewBaseInfoResponse getCrewBaseInfo(Crew crew) { return crewMapper.toCrewBaseInfo(rank, crew); } + + public PageResponse searchCrewsByName(String crewName, int page, int size) { + + Page crewPage = crewRepository.findByNameContainingIgnoreCase(crewName, PageRequest.of(page, size)); + List content = crewMapper.toCrewSearchResponseList(crewPage.getContent()); + + return PageResponse.toPageResponse(crewPage, content); + } } From eec73050c010f0d57cfe1a1129426fb012338cd6 Mon Sep 17 00:00:00 2001 From: choiseoji Date: Sat, 2 Aug 2025 09:43:45 +0900 Subject: [PATCH 09/14] =?UTF-8?q?[#28]=20feat:=20JoinCrew=EC=97=90?= =?UTF-8?q?=EC=84=9C=20=ED=81=AC=EB=A3=A8=EC=97=90=20=EC=86=8D=ED=95=9C=20?= =?UTF-8?q?=EB=AA=A8=EB=93=A0=20=EB=A9=A4=EB=B2=84=20=EC=A1=B0=ED=9A=8C?= =?UTF-8?q?=ED=95=98=EB=8A=94=20repository=20=EC=BD=94=EB=93=9C=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 --- .../crew/repository/JoinCrewRepository.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main/java/run/backend/domain/crew/repository/JoinCrewRepository.java b/src/main/java/run/backend/domain/crew/repository/JoinCrewRepository.java index fd551ba..ec0a6a7 100644 --- a/src/main/java/run/backend/domain/crew/repository/JoinCrewRepository.java +++ b/src/main/java/run/backend/domain/crew/repository/JoinCrewRepository.java @@ -4,11 +4,14 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; +import run.backend.domain.crew.dto.query.CrewMemberProfileDto; import run.backend.domain.crew.entity.Crew; import run.backend.domain.crew.entity.JoinCrew; import run.backend.domain.crew.enums.JoinStatus; import run.backend.domain.member.entity.Member; import run.backend.domain.member.enums.Role; + +import java.util.List; import java.util.Optional; import run.backend.domain.event.dto.response.EventCreationValidationDto; @@ -60,4 +63,17 @@ Optional findCrewMemberById( @Param("crewId") Long crewId, @Param("status") JoinStatus status ); + + @Query(""" + SELECT new run.backend.domain.crew.dto.query.CrewMemberProfileDto( + m.profileImage, + m.nickname, + m.role + ) + FROM JoinCrew jc + JOIN jc.member m + WHERE jc.crew.id = :crewId + AND jc.joinStatus = :status + """) + List findAllCrewMemberByCrewId(@Param("crewId") Long crewId, @Param("status") JoinStatus status); } From 67bb8f61dc12fc8deeff077477a2557c6f956dbe Mon Sep 17 00:00:00 2001 From: choiseoji Date: Sat, 2 Aug 2025 09:44:08 +0900 Subject: [PATCH 10/14] =?UTF-8?q?[#28]=20feat:=20=ED=95=84=EC=9A=94?= =?UTF-8?q?=ED=95=9C=20dto=EB=93=A4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/crew/dto/query/CrewMemberProfileDto.java | 10 ++++++++++ .../backend/domain/crew/dto/query/CrewProfileDto.java | 8 ++++++++ .../crew/dto/request/MemberRoleChangeRequest.java | 8 ++++++++ .../crew/dto/response/CrewMemberProfileResponse.java | 10 ++++++++++ .../domain/crew/dto/response/CrewMemberResponse.java | 9 +++++++++ 5 files changed, 45 insertions(+) create mode 100644 src/main/java/run/backend/domain/crew/dto/query/CrewMemberProfileDto.java create mode 100644 src/main/java/run/backend/domain/crew/dto/query/CrewProfileDto.java create mode 100644 src/main/java/run/backend/domain/crew/dto/request/MemberRoleChangeRequest.java create mode 100644 src/main/java/run/backend/domain/crew/dto/response/CrewMemberProfileResponse.java create mode 100644 src/main/java/run/backend/domain/crew/dto/response/CrewMemberResponse.java diff --git a/src/main/java/run/backend/domain/crew/dto/query/CrewMemberProfileDto.java b/src/main/java/run/backend/domain/crew/dto/query/CrewMemberProfileDto.java new file mode 100644 index 0000000..8109976 --- /dev/null +++ b/src/main/java/run/backend/domain/crew/dto/query/CrewMemberProfileDto.java @@ -0,0 +1,10 @@ +package run.backend.domain.crew.dto.query; + +import run.backend.domain.member.enums.Role; + +public record CrewMemberProfileDto( + String image, + String nickname, + Role role +) { +} diff --git a/src/main/java/run/backend/domain/crew/dto/query/CrewProfileDto.java b/src/main/java/run/backend/domain/crew/dto/query/CrewProfileDto.java new file mode 100644 index 0000000..1f9b5a8 --- /dev/null +++ b/src/main/java/run/backend/domain/crew/dto/query/CrewProfileDto.java @@ -0,0 +1,8 @@ +package run.backend.domain.crew.dto.query; + +public record CrewProfileDto( + String image, + String name, + String description +) { +} diff --git a/src/main/java/run/backend/domain/crew/dto/request/MemberRoleChangeRequest.java b/src/main/java/run/backend/domain/crew/dto/request/MemberRoleChangeRequest.java new file mode 100644 index 0000000..140f1ad --- /dev/null +++ b/src/main/java/run/backend/domain/crew/dto/request/MemberRoleChangeRequest.java @@ -0,0 +1,8 @@ +package run.backend.domain.crew.dto.request; + +import run.backend.domain.member.enums.Role; + +public record MemberRoleChangeRequest( + Role role +) { +} diff --git a/src/main/java/run/backend/domain/crew/dto/response/CrewMemberProfileResponse.java b/src/main/java/run/backend/domain/crew/dto/response/CrewMemberProfileResponse.java new file mode 100644 index 0000000..79d6cbb --- /dev/null +++ b/src/main/java/run/backend/domain/crew/dto/response/CrewMemberProfileResponse.java @@ -0,0 +1,10 @@ +package run.backend.domain.crew.dto.response; + +import run.backend.domain.member.enums.Role; + +public record CrewMemberProfileResponse( + String image, + String nickname, + Role role +) { +} diff --git a/src/main/java/run/backend/domain/crew/dto/response/CrewMemberResponse.java b/src/main/java/run/backend/domain/crew/dto/response/CrewMemberResponse.java new file mode 100644 index 0000000..439f51b --- /dev/null +++ b/src/main/java/run/backend/domain/crew/dto/response/CrewMemberResponse.java @@ -0,0 +1,9 @@ +package run.backend.domain.crew.dto.response; + +import java.util.List; + +public record CrewMemberResponse( + List managers, + List members +) { +} From 0e2f31540f9adc45a35f2625967675ba1be48d0f Mon Sep 17 00:00:00 2001 From: choiseoji Date: Sat, 2 Aug 2025 09:44:25 +0900 Subject: [PATCH 11/14] =?UTF-8?q?[#28]=20feat:=20=ED=81=AC=EB=A3=A8=20?= =?UTF-8?q?=EB=A9=A4=EB=B2=84=20=EC=A1=B0=ED=9A=8C,=20=EC=97=AD=ED=95=A0?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD=20=EC=84=9C=EB=B9=84=EC=8A=A4=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 --- .../crew/service/CrewMemberService.java | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 src/main/java/run/backend/domain/crew/service/CrewMemberService.java diff --git a/src/main/java/run/backend/domain/crew/service/CrewMemberService.java b/src/main/java/run/backend/domain/crew/service/CrewMemberService.java new file mode 100644 index 0000000..634956f --- /dev/null +++ b/src/main/java/run/backend/domain/crew/service/CrewMemberService.java @@ -0,0 +1,59 @@ +package run.backend.domain.crew.service; + +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import run.backend.domain.crew.dto.query.CrewMemberProfileDto; +import run.backend.domain.crew.dto.request.MemberRoleChangeRequest; +import run.backend.domain.crew.dto.response.CrewMemberProfileResponse; +import run.backend.domain.crew.dto.response.CrewMemberResponse; +import run.backend.domain.crew.entity.Crew; +import run.backend.domain.crew.enums.JoinStatus; +import run.backend.domain.crew.mapper.CrewMapper; +import run.backend.domain.crew.repository.JoinCrewRepository; +import run.backend.domain.member.entity.Member; +import run.backend.domain.member.enums.Role; +import run.backend.domain.member.exception.MemberException; +import run.backend.domain.member.repository.MemberRepository; + +import java.util.ArrayList; +import java.util.List; + +@Service +@RequiredArgsConstructor +@Transactional(readOnly = true) +public class CrewMemberService { + + private final CrewMapper crewMapper; + private final MemberRepository memberRepository; + private final JoinCrewRepository joinCrewRepository; + + public CrewMemberResponse getCrewMembers(Crew crew) { + + List dtos = joinCrewRepository.findAllCrewMemberByCrewId(crew.getId(), JoinStatus.APPROVED); + + List all = crewMapper.toCrewMemberProfileResponseList(dtos); + + List managers = new ArrayList<>(); + List members = new ArrayList<>(); + + for (CrewMemberProfileResponse profile : all) { + + if (profile.role() == Role.MEMBER) + members.add(profile); + else + managers.add(profile); + } + return new CrewMemberResponse(managers, members); + } + + @Transactional + public void updateCrewMemberRole(Long memberId, MemberRoleChangeRequest request) { + + Member member = memberRepository.findById(memberId) + .orElseThrow(MemberException.MemberNotFound::new); + + member.updateRole(request.role()); + memberRepository.save(member); + } +} From 1ab6c766d381b9a34b09c3fee60003f7eaf93b4d Mon Sep 17 00:00:00 2001 From: choiseoji Date: Sat, 2 Aug 2025 11:11:48 +0900 Subject: [PATCH 12/14] =?UTF-8?q?[#28]=20test:=20MemberCrew=20=ED=85=8C?= =?UTF-8?q?=EC=8A=A4=ED=8A=B8=20=EC=BD=94=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 --- .../crew/service/CrewMemberServiceTest.java | 123 ++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 src/test/java/run/backend/domain/crew/service/CrewMemberServiceTest.java diff --git a/src/test/java/run/backend/domain/crew/service/CrewMemberServiceTest.java b/src/test/java/run/backend/domain/crew/service/CrewMemberServiceTest.java new file mode 100644 index 0000000..d4a373b --- /dev/null +++ b/src/test/java/run/backend/domain/crew/service/CrewMemberServiceTest.java @@ -0,0 +1,123 @@ +package run.backend.domain.crew.service; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import run.backend.domain.crew.dto.query.CrewMemberProfileDto; +import run.backend.domain.crew.dto.request.MemberRoleChangeRequest; +import run.backend.domain.crew.dto.response.CrewMemberProfileResponse; +import run.backend.domain.crew.dto.response.CrewMemberResponse; +import run.backend.domain.crew.entity.Crew; +import run.backend.domain.crew.enums.JoinStatus; +import run.backend.domain.crew.mapper.CrewMapper; +import run.backend.domain.crew.repository.JoinCrewRepository; +import run.backend.domain.member.entity.Member; +import run.backend.domain.member.enums.Role; +import run.backend.domain.member.exception.MemberException; +import run.backend.domain.member.repository.MemberRepository; + +import java.util.List; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.junit.jupiter.api.Assertions.assertEquals; + +@DisplayName("CrewMember 서비스 테스트") +@ExtendWith(MockitoExtension.class) +public class CrewMemberServiceTest { + + @InjectMocks + private CrewMemberService crewMemberService; + + @Mock + private CrewMapper crewMapper; + + @Mock + private MemberRepository memberRepository; + + @Mock + private JoinCrewRepository joinCrewRepository; + + @Mock + private Member member; + + @Mock + private Crew crew; + + + @Nested + @DisplayName("getCrewMembers 메서드는 ") + class getCrewMembersTest { + + @Test + @DisplayName("크루원 조회 시 역할에 따라 관리자와 일반 멤버로 구분하여 응답한다.") + void returnsCrewMembersGroupedByRole() { + + // given + List dtos = List.of( + new CrewMemberProfileDto("img1", "user1", Role.MANAGER), + new CrewMemberProfileDto("img2", "user2", Role.MEMBER) + ); + List responses = List.of( + new CrewMemberProfileResponse("img1", "user1", Role.MANAGER), + new CrewMemberProfileResponse("img2", "user2", Role.MEMBER) + ); + when(joinCrewRepository.findAllCrewMemberByCrewId(crew.getId(), JoinStatus.APPROVED)) + .thenReturn(dtos); + when(crewMapper.toCrewMemberProfileResponseList(dtos)) + .thenReturn(responses); + + // when + CrewMemberResponse result = crewMemberService.getCrewMembers(crew); + + // then + assertEquals(1, result.managers().size()); + assertEquals(1, result.members().size()); + assertEquals("user1", result.managers().get(0).nickname()); + assertEquals("user2", result.members().get(0).nickname()); + } + } + + @Nested + @DisplayName("updateCrewMemberRole 메서드는 ") + class updateCrewMemberRoleTest { + + @Test + @DisplayName("회원 역할 변경 시 해당 회원의 역할을 요청된 값으로 변경한다.") + void updatesMemberRole_whenMemberExists() { + + // given + MemberRoleChangeRequest request = new MemberRoleChangeRequest(Role.MANAGER); + when(memberRepository.findById(member.getId())) + .thenReturn(Optional.of(member)); + + // when + crewMemberService.updateCrewMemberRole(member.getId(), request); + + // then + verify(member).updateRole(Role.MANAGER); + verify(memberRepository).save(member); + } + + @Test + @DisplayName("존재하지 않는 회원에게 역할 변경을 시도하면 예외가 발생한다.") + void throwsException_whenMemberNotFound() { + + // given + Long memberId = 999L; + MemberRoleChangeRequest request = new MemberRoleChangeRequest(Role.MANAGER); + + when(memberRepository.findById(memberId)).thenReturn(Optional.empty()); + + // then + assertThrows(MemberException.MemberNotFound.class, + () -> crewMemberService.updateCrewMemberRole(memberId, request)); + } + } +} From 84c546360000aa9c6dbaab3c4b611c87b66cdbc8 Mon Sep 17 00:00:00 2001 From: choiseoji Date: Sat, 2 Aug 2025 11:20:40 +0900 Subject: [PATCH 13/14] =?UTF-8?q?[#28]=20feat:=20Crew,=20JoinCrew=EC=97=90?= =?UTF-8?q?=20soft=20delete=20=EC=84=A4=EC=A0=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/run/backend/domain/crew/entity/Crew.java | 2 ++ src/main/java/run/backend/domain/crew/entity/JoinCrew.java | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/main/java/run/backend/domain/crew/entity/Crew.java b/src/main/java/run/backend/domain/crew/entity/Crew.java index 40ee194..6dbf6f6 100644 --- a/src/main/java/run/backend/domain/crew/entity/Crew.java +++ b/src/main/java/run/backend/domain/crew/entity/Crew.java @@ -2,6 +2,7 @@ import jakarta.persistence.*; import lombok.*; +import org.hibernate.annotations.SQLDelete; import run.backend.global.common.BaseEntity; import java.math.BigDecimal; @@ -12,6 +13,7 @@ @Table(name = "crews") @AllArgsConstructor @NoArgsConstructor(access = AccessLevel.PROTECTED) +@SQLDelete(sql = "UPDATE crews SET deleted_at = NOW() WHERE id = ?") public class Crew extends BaseEntity { @Id diff --git a/src/main/java/run/backend/domain/crew/entity/JoinCrew.java b/src/main/java/run/backend/domain/crew/entity/JoinCrew.java index 5716da9..b23cf62 100644 --- a/src/main/java/run/backend/domain/crew/entity/JoinCrew.java +++ b/src/main/java/run/backend/domain/crew/entity/JoinCrew.java @@ -5,6 +5,7 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import org.hibernate.annotations.SQLDelete; import run.backend.domain.crew.enums.JoinStatus; import run.backend.domain.member.entity.Member; import run.backend.domain.member.enums.Role; @@ -17,6 +18,7 @@ @Getter @Table(name = "join_crews") @NoArgsConstructor(access = AccessLevel.PROTECTED) +@SQLDelete(sql = "UPDATE join_crews SET deleted_at = NOW() WHERE id = ?") public class JoinCrew extends BaseEntity { @Id From f80c35e6b98bf4ff70f78049632a77925d0ca2bc Mon Sep 17 00:00:00 2001 From: choiseoji Date: Sat, 2 Aug 2025 14:05:34 +0900 Subject: [PATCH 14/14] =?UTF-8?q?[#28]=20fix:=20crew=20deleted=5Fat=20?= =?UTF-8?q?=ED=99=95=EC=9D=B8=ED=95=98=EA=B3=A0=20=EC=A1=B0=ED=9A=8C?= =?UTF-8?q?=ED=95=98=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../run/backend/domain/crew/repository/CrewRepository.java | 6 +++--- .../run/backend/domain/crew/service/CrewRankingService.java | 2 +- .../java/run/backend/domain/crew/service/CrewService.java | 2 +- .../backend/domain/crew/service/CrewRankingServiceTest.java | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/run/backend/domain/crew/repository/CrewRepository.java b/src/main/java/run/backend/domain/crew/repository/CrewRepository.java index a32d74b..50b3c93 100644 --- a/src/main/java/run/backend/domain/crew/repository/CrewRepository.java +++ b/src/main/java/run/backend/domain/crew/repository/CrewRepository.java @@ -11,10 +11,9 @@ public interface CrewRepository extends JpaRepository { - Optional findByInviteCode(String inviteCode); + Optional findByInviteCodeAndDeletedAtIsNull(String inviteCode); - - Page findAllByOrderByMonthlyScoreTotalDesc(Pageable pageable); + Page findAllByDeletedAtIsNullOrderByMonthlyScoreTotalDesc(Pageable pageable); @Query(""" SELECT new run.backend.domain.crew.dto.query.CrewProfileDto( @@ -24,6 +23,7 @@ public interface CrewRepository extends JpaRepository { ) FROM Crew c WHERE LOWER(c.name) LIKE LOWER(CONCAT('%', :name, '%')) + AND c.deletedAt IS NULL """) Page findByNameContainingIgnoreCase(String name, Pageable pageable); } diff --git a/src/main/java/run/backend/domain/crew/service/CrewRankingService.java b/src/main/java/run/backend/domain/crew/service/CrewRankingService.java index 8001892..dd5571d 100644 --- a/src/main/java/run/backend/domain/crew/service/CrewRankingService.java +++ b/src/main/java/run/backend/domain/crew/service/CrewRankingService.java @@ -24,7 +24,7 @@ public class CrewRankingService { public PageResponse getCrewRanking(int page, int size) { - Page pageResult = crewRepository.findAllByOrderByMonthlyScoreTotalDesc(PageRequest.of(page, size)); + Page pageResult = crewRepository.findAllByDeletedAtIsNullOrderByMonthlyScoreTotalDesc(PageRequest.of(page, size)); List content = crewMapper.toCrewRankingResponseList(pageResult.getContent()); return PageResponse.toPageResponse(pageResult, content); diff --git a/src/main/java/run/backend/domain/crew/service/CrewService.java b/src/main/java/run/backend/domain/crew/service/CrewService.java index dc12566..31fcb10 100644 --- a/src/main/java/run/backend/domain/crew/service/CrewService.java +++ b/src/main/java/run/backend/domain/crew/service/CrewService.java @@ -74,7 +74,7 @@ public CrewInviteCodeDto getCrewInviteCode(Crew crew) { public CrewProfileResponse getCrewByInviteCode(String inviteCode) { - Crew crew = crewRepository.findByInviteCode(inviteCode) + Crew crew = crewRepository.findByInviteCodeAndDeletedAtIsNull(inviteCode) .orElseThrow(CrewException.NotFoundCrew::new); Member leader = joinCrewRepository.findCrewLeader(Role.LEADER, crew); diff --git a/src/test/java/run/backend/domain/crew/service/CrewRankingServiceTest.java b/src/test/java/run/backend/domain/crew/service/CrewRankingServiceTest.java index 3ef643b..bb0d574 100644 --- a/src/test/java/run/backend/domain/crew/service/CrewRankingServiceTest.java +++ b/src/test/java/run/backend/domain/crew/service/CrewRankingServiceTest.java @@ -84,7 +84,7 @@ void getCrewRanking_whenValidPageRequest_thenReturnsPageResponse() { new CrewRankingResponse(5L, "name5", "image5", 1) ); - when(crewRepository.findAllByOrderByMonthlyScoreTotalDesc(PageRequest.of(page, size))) + when(crewRepository.findAllByDeletedAtIsNullOrderByMonthlyScoreTotalDesc(PageRequest.of(page, size))) .thenReturn(crewPage); when(crewMapper.toCrewRankingResponseList(crewPage.getContent())) .thenReturn(responseList);