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 c7c7bc4..8557871 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; @@ -15,10 +17,14 @@ import java.util.List; 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)") @@ -40,6 +46,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, List questions) { this.id = UUID.randomUUID(); this.title = new CrewTitle(name); @@ -97,4 +106,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(); + } } 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 df96586..a0acaff 100644 --- a/src/test/java/com/retrip/crew/application/in/CrewServiceTest.java +++ b/src/test/java/com/retrip/crew/application/in/CrewServiceTest.java @@ -16,9 +16,11 @@ import com.retrip.crew.application.in.response.demand.CreateDemandResponse; 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; @@ -300,4 +302,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)); + } }