From dfcd7287201aab64570aafeda3b9f6ac6758fc23 Mon Sep 17 00:00:00 2001 From: pparkjs Date: Sat, 14 Jun 2025 19:50:24 +0900 Subject: [PATCH 1/2] =?UTF-8?q?[feat]=20=EB=A6=AC=EB=8D=94=20=ED=81=AC?= =?UTF-8?q?=EB=A3=A8=20=EC=82=AD=EC=A0=9C=20API=20=EA=B5=AC=ED=98=84=20(#6?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crew/application/in/CrewService.java | 9 ++++++++ .../in/usecase/ManageCrewUseCase.java | 4 ++-- .../com/retrip/crew/domain/entity/Crew.java | 22 ++++++++++++++++++- .../in/presentation/rest/CrewController.java | 12 ++++++++++ 4 files changed, 44 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/retrip/crew/application/in/CrewService.java b/src/main/java/com/retrip/crew/application/in/CrewService.java index 68e0885..f8e6610 100644 --- a/src/main/java/com/retrip/crew/application/in/CrewService.java +++ b/src/main/java/com/retrip/crew/application/in/CrewService.java @@ -3,6 +3,9 @@ import com.retrip.crew.application.in.request.IntroductionCreateRequest; import com.retrip.crew.application.in.request.IntroductionDeleteRequest; import com.retrip.crew.application.in.request.IntroductionUpdateRequest; +import com.retrip.crew.application.in.request.crew.CrewCreateRequest; +import com.retrip.crew.application.in.request.crew.CrewOrder; +import com.retrip.crew.application.in.request.crew.CrewUpdateRequest; import com.retrip.crew.application.in.request.crew.*; import com.retrip.crew.application.in.response.IntroductionCreateResponse; import com.retrip.crew.application.in.response.IntroductionDetailResponse; @@ -145,4 +148,10 @@ public CrewLeaderDelegateResponse delegateCrewLeader(UUID crewId, CrewLeaderDele CrewMember newLeader = crewMembers.delegateLeader(request.leaderId(), request.newLeaderId()); return CrewLeaderDelegateResponse.of(newLeader); } + + @Override + public void deleteCrew(UUID crewId, UUID loginMemberId) { + Crew crew = findCrewById(crewId); + crew.softDelete(loginMemberId); + } } diff --git a/src/main/java/com/retrip/crew/application/in/usecase/ManageCrewUseCase.java b/src/main/java/com/retrip/crew/application/in/usecase/ManageCrewUseCase.java index cf34c5c..dfbcc2d 100644 --- a/src/main/java/com/retrip/crew/application/in/usecase/ManageCrewUseCase.java +++ b/src/main/java/com/retrip/crew/application/in/usecase/ManageCrewUseCase.java @@ -8,8 +8,6 @@ import com.retrip.crew.application.in.response.crew.CrewLeaderDelegateResponse; import com.retrip.crew.application.in.response.crew.CrewUpdateResponse; -import com.retrip.crew.domain.entity.Crew; - import java.util.UUID; public interface ManageCrewUseCase { @@ -20,4 +18,6 @@ public interface ManageCrewUseCase { void withdrawCrew(UUID crewId, CrewWithdrawalRequest request); CrewLeaderDelegateResponse delegateCrewLeader(UUID crewId, CrewLeaderDelegateRequest request); + + void deleteCrew(UUID crewId, UUID loginMemberId); } diff --git a/src/main/java/com/retrip/crew/domain/entity/Crew.java b/src/main/java/com/retrip/crew/domain/entity/Crew.java index dca0285..b6bd252 100644 --- a/src/main/java/com/retrip/crew/domain/entity/Crew.java +++ b/src/main/java/com/retrip/crew/domain/entity/Crew.java @@ -1,5 +1,7 @@ package com.retrip.crew.domain.entity; +import com.retrip.crew.domain.exception.NotCrewLeaderException; +import com.retrip.crew.domain.exception.common.BusinessException; import com.retrip.crew.domain.vo.CrewDescription; import com.retrip.crew.domain.vo.CrewTitle; @@ -14,10 +16,14 @@ import lombok.NoArgsConstructor; import java.util.UUID; +import org.hibernate.annotations.SQLDelete; +import org.hibernate.annotations.SQLRestriction; @Entity -@NoArgsConstructor(access = AccessLevel.PROTECTED) @Getter +@SQLRestriction("is_deleted = false") +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@SQLDelete(sql = "UPDATE crew SET is_deleted = true WHERE id = ?") public class Crew extends BaseEntity { @Id @Column(columnDefinition = "varbinary(16)") @@ -39,6 +45,9 @@ public class Crew extends BaseEntity { @Embedded private Recruitment recruitment; + @Column(name = "is_deleted", nullable = false) + private boolean isDeleted = false; + private Crew(String name, String description, int maxMembers, UUID leader) { this.id = UUID.randomUUID(); this.title = new CrewTitle(name); @@ -96,4 +105,15 @@ public void approveDemand(Demand demand) { recruitment.approveDemand(demand); crewMembers.addMember(demand, this); } + + public void softDelete(UUID loginMemberId) { + validateCrewLeader(loginMemberId); + this.isDeleted = true; + } + + private void validateCrewLeader(UUID loginMemberId) { + if(!this.getCrewMembers().isLeader(loginMemberId)){ + throw new NotCrewLeaderException(); + } + } } diff --git a/src/main/java/com/retrip/crew/infra/adapter/in/presentation/rest/CrewController.java b/src/main/java/com/retrip/crew/infra/adapter/in/presentation/rest/CrewController.java index 3da6303..029a470 100644 --- a/src/main/java/com/retrip/crew/infra/adapter/in/presentation/rest/CrewController.java +++ b/src/main/java/com/retrip/crew/infra/adapter/in/presentation/rest/CrewController.java @@ -3,6 +3,9 @@ import com.retrip.crew.application.in.request.IntroductionCreateRequest; import com.retrip.crew.application.in.request.IntroductionDeleteRequest; import com.retrip.crew.application.in.request.IntroductionUpdateRequest; +import com.retrip.crew.application.in.request.crew.CrewCreateRequest; +import com.retrip.crew.application.in.request.crew.CrewOrder; +import com.retrip.crew.application.in.request.crew.CrewUpdateRequest; import com.retrip.crew.application.in.request.crew.*; import com.retrip.crew.application.in.response.IntroductionCreateResponse; import com.retrip.crew.application.in.response.IntroductionDetailResponse; @@ -135,4 +138,13 @@ public ApiResponse delegateCrewLeader( CrewLeaderDelegateResponse response = manageCrewUseCase.delegateCrewLeader(crewId, request); return ApiResponse.ok(response); } + + @Schema(description = "크루 삭제") + @DeleteMapping("/{crewId}") + public ApiResponse deleteCrew( + @PathVariable("crewId") final UUID crewId, + @RequestParam("loginMemberId") UUID loginMemberId) { //TODO: 로그인 구현 될 시 해당 부분 교체 해야함 임시방편으로 쿼리 파라미터에 넣음 + manageCrewUseCase.deleteCrew(crewId, loginMemberId); + return ApiResponse.noContent(); + } } From f743a9a9f61ce72905e93c3262e407fc71724db7 Mon Sep 17 00:00:00 2001 From: pparkjs Date: Sat, 14 Jun 2025 19:50:42 +0900 Subject: [PATCH 2/2] =?UTF-8?q?[test]=20=EB=A6=AC=EB=8D=94=20=ED=81=AC?= =?UTF-8?q?=EB=A3=A8=20=EC=82=AD=EC=A0=9C=20=EB=8B=A8=EC=9C=84=20test=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EA=B5=AC=ED=98=84=20(#6)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crew/application/in/CrewServiceTest.java | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/test/java/com/retrip/crew/application/in/CrewServiceTest.java b/src/test/java/com/retrip/crew/application/in/CrewServiceTest.java index 8f47f06..5d38992 100644 --- a/src/test/java/com/retrip/crew/application/in/CrewServiceTest.java +++ b/src/test/java/com/retrip/crew/application/in/CrewServiceTest.java @@ -14,8 +14,11 @@ import com.retrip.crew.application.in.response.crew.CrewUpdateResponse; import com.retrip.crew.common.ServiceTest; import com.retrip.crew.domain.entity.Crew; +import com.retrip.crew.domain.entity.CrewMember; import com.retrip.crew.domain.entity.CrewMemberRole; +import com.retrip.crew.domain.entity.Demand; import com.retrip.crew.domain.entity.Introduction; +import com.retrip.crew.domain.exception.NotCrewLeaderException; import com.retrip.crew.domain.exception.common.InvalidAccessException; import com.retrip.crew.infra.adapter.in.presentation.rest.common.ScrollPageResponse; import org.junit.jupiter.api.Test; @@ -248,4 +251,40 @@ class CrewServiceTest extends ServiceTest { assertThat(response.content()).isEqualTo("안녕하세요!"); assertThat(response.title()).isEqualTo("정수의 자기소개!"); } + + @Test + void 리더가_크루를_탈퇴한다() { + // given + Crew crew = Crew.create( + "속초 크루원 구함", + "속초 친구 구합니다! 나이는 20~40.. 많은 가입 부탁드립니다.", + 100, + MEMBER_ID + ); + Crew savedCrew = crewRepository.save(crew); + + // when + crewService.deleteCrew(savedCrew.getId(), MEMBER_ID); + Crew deletedCrew = crewRepository.findById(savedCrew.getId()).get(); + + // then + assertThat(deletedCrew.isDeleted()).isTrue(); + } + + @Test + void 리더가_아니면_크루를_탈퇴할_수_없다() { + // given + Crew crew = Crew.create( + "속초 크루원 구함", + "속초 친구 구합니다! 나이는 20~40.. 많은 가입 부탁드립니다.", + 100, + LEADER_ID + ); + Crew savedCrew = crewRepository.save(crew); + Demand demand = savedCrew.demand(MEMBER_ID); + savedCrew.approveDemand(demand); + + // when && then + assertThrows(NotCrewLeaderException.class, () -> crewService.deleteCrew(savedCrew.getId(), MEMBER_ID)); + } }