From 72ba76d3ff9d80e6ac386251c068a71b29e99d13 Mon Sep 17 00:00:00 2001 From: pparkjs Date: Fri, 25 Jul 2025 23:15:04 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feature:=20=ED=81=AC=EB=A3=A8=EC=B0=B8?= =?UTF-8?q?=EC=97=AC=EC=9A=94=EC=B2=AD=20=EC=A7=88=EB=AC=B8=20=EB=93=B1?= =?UTF-8?q?=EB=A1=9D,=EC=88=98=EC=A0=95,=EC=82=AD=EC=A0=9C,=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EA=B5=AC=ED=98=84=20(#42)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crew/application/in/DemandService.java | 59 ++++++++++++- .../crew/application/in/PostService.java | 7 +- .../in/RecruitmentQuestionService.java | 87 ------------------- .../CreateRecruitmentQuestionRequest.java | 7 +- .../UpdateRecruitmentQuestionRequest.java | 7 +- .../response/RecruitmentQuestionResponse.java | 1 + .../UpdateRecruitmentQuestionResponse.java | 6 +- .../ManageRecruitmentQuestionUseCase.java | 13 ++- .../out/repository/CrewQueryRepository.java | 1 - .../RecruitmentQuestionQueryRepository.java | 2 - .../RecruitmentQuestionRepository.java | 18 ++++ .../com/retrip/crew/domain/entity/Crew.java | 13 ++- .../crew/domain/entity/Recruitment.java | 19 ++-- .../domain/entity/RecruitmentQuestion.java | 25 +++--- .../domain/entity/RecruitmentQuestions.java | 47 ++-------- .../presentation/rest/DemandController.java | 48 ++++++++++ .../mysql/query/CrewQuerydslRepository.java | 11 --- ...RecruitmentQuestionQuerydslRepository.java | 22 +---- 18 files changed, 179 insertions(+), 214 deletions(-) delete mode 100644 src/main/java/com/retrip/crew/application/in/RecruitmentQuestionService.java create mode 100644 src/main/java/com/retrip/crew/application/out/repository/RecruitmentQuestionRepository.java diff --git a/src/main/java/com/retrip/crew/application/in/DemandService.java b/src/main/java/com/retrip/crew/application/in/DemandService.java index 24556f6..31432c2 100644 --- a/src/main/java/com/retrip/crew/application/in/DemandService.java +++ b/src/main/java/com/retrip/crew/application/in/DemandService.java @@ -1,37 +1,54 @@ package com.retrip.crew.application.in; +import com.retrip.crew.application.in.request.CreateRecruitmentQuestionRequest; +import com.retrip.crew.application.in.request.UpdateRecruitmentQuestionRequest; import com.retrip.crew.application.in.request.crew.CrewOrder; import com.retrip.crew.application.in.request.demand.CreateDemandRequest; import com.retrip.crew.application.in.request.demand.DemandOrder; -import com.retrip.crew.application.in.response.demand.*; +import com.retrip.crew.application.in.response.CreateRecruitmentQuestionResponse; +import com.retrip.crew.application.in.response.RecruitmentQuestionResponse; +import com.retrip.crew.application.in.response.UpdateRecruitmentQuestionResponse; +import com.retrip.crew.application.in.response.demand.ApproveDemandResponse; +import com.retrip.crew.application.in.response.demand.ChangeRecruitmentStatusResponse; +import com.retrip.crew.application.in.response.demand.CreateDemandResponse; +import com.retrip.crew.application.in.response.demand.CrewsOfDemandResponse; +import com.retrip.crew.application.in.response.demand.DemandsResponse; +import com.retrip.crew.application.in.response.demand.RejectDemandResponse; import com.retrip.crew.application.in.usecase.ManageDemandUseCase; +import com.retrip.crew.application.in.usecase.ManageRecruitmentQuestionUseCase; import com.retrip.crew.application.in.usecase.UpdateRecruitmentUseCase; import com.retrip.crew.application.out.repository.CrewDemandRepository; import com.retrip.crew.application.out.repository.CrewQueryRepository; import com.retrip.crew.application.out.repository.CrewRepository; +import com.retrip.crew.application.out.repository.RecruitmentQuestionQueryRepository; +import com.retrip.crew.application.out.repository.RecruitmentQuestionRepository; import com.retrip.crew.domain.entity.Crew; import com.retrip.crew.domain.entity.Demand; +import com.retrip.crew.domain.entity.RecruitmentQuestion; import com.retrip.crew.domain.exception.CrewNotFoundException; import com.retrip.crew.domain.exception.NotCrewLeaderException; +import com.retrip.crew.domain.exception.QuestionNotFoundException; import com.retrip.crew.domain.exception.common.BusinessException; import com.retrip.crew.domain.exception.common.EntityNotFoundException; import com.retrip.crew.domain.vo.DemandStatus; import com.retrip.crew.infra.util.PaginationUtils; +import java.util.List; +import java.util.UUID; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.UUID; - @Service @Transactional @RequiredArgsConstructor -public class DemandService implements UpdateRecruitmentUseCase, ManageDemandUseCase { +public class DemandService implements UpdateRecruitmentUseCase, ManageDemandUseCase, ManageRecruitmentQuestionUseCase { private final CrewRepository crewRepository; private final CrewDemandRepository demandRepository; private final CrewQueryRepository crewQueryRepository; + private final RecruitmentQuestionRepository recruitmentQuestionRepository; + private final RecruitmentQuestionQueryRepository recruitmentQuestionQueryRepository; @Override public ChangeRecruitmentStatusResponse startRecruitment(UUID crewId) { @@ -111,4 +128,38 @@ private Crew findById(UUID crewId){ return crewRepository.findById(crewId) .orElseThrow(CrewNotFoundException::new); } + + @Override + public CreateRecruitmentQuestionResponse createRecruitmentQuestion(UUID memberId, UUID crewId, CreateRecruitmentQuestionRequest request) { + Crew crew = findById(crewId); + RecruitmentQuestion question = RecruitmentQuestion.create(request.content(), crew); + crew.addRecruitmentQuestion(memberId, question); + + return CreateRecruitmentQuestionResponse.of(question); + } + + @Override + public UpdateRecruitmentQuestionResponse updateRecruitmentQuestion(UUID memberId, UUID crewId, UUID questionId, UpdateRecruitmentQuestionRequest request) { + RecruitmentQuestion savedQuestion = findRecruitmentQuestionByIdAndCrewId(questionId, crewId); + savedQuestion.update(request.content(), memberId); + return UpdateRecruitmentQuestionResponse.of(savedQuestion); + } + + @Override + public void deleteRecruitmentQuestion(UUID memberId, UUID crewId, UUID questionId) { + Crew crew = findById(crewId); + RecruitmentQuestion savedQuestion = findRecruitmentQuestionByIdAndCrewId(questionId, crewId); + crew.deleteRecruitmentQuestion(memberId, savedQuestion); + } + + @Override + @Transactional(readOnly = true) + public List getRecruitmentQuestions(UUID memberId, UUID crewId) { + return recruitmentQuestionQueryRepository.findRecruitmentQuestions(crewId); + } + + private RecruitmentQuestion findRecruitmentQuestionByIdAndCrewId(UUID questionId, UUID crewId) { + return recruitmentQuestionRepository.findByIdAndCrewId(questionId, crewId) + .orElseThrow(QuestionNotFoundException::new); + } } diff --git a/src/main/java/com/retrip/crew/application/in/PostService.java b/src/main/java/com/retrip/crew/application/in/PostService.java index c56b359..f5807d4 100644 --- a/src/main/java/com/retrip/crew/application/in/PostService.java +++ b/src/main/java/com/retrip/crew/application/in/PostService.java @@ -4,7 +4,6 @@ import com.retrip.crew.application.in.request.PostOrder; import com.retrip.crew.application.in.request.UpdatePostRequest; import com.retrip.crew.application.in.response.CreatePostResponse; -import com.retrip.crew.application.in.response.DeletePostResponse; import com.retrip.crew.application.in.response.PostResponse; import com.retrip.crew.application.in.response.UpdatePostResponse; import com.retrip.crew.application.in.usecase.GetPostUseCase; @@ -16,20 +15,16 @@ import com.retrip.crew.domain.entity.CrewMember; import com.retrip.crew.domain.entity.Post; import com.retrip.crew.domain.exception.CrewMemberNotFoundException; - import com.retrip.crew.domain.exception.CrewNotFoundException; import com.retrip.crew.infra.adapter.in.presentation.rest.common.ScrollPageResponse; import com.retrip.crew.infra.util.PaginationUtils; - +import java.util.UUID; import lombok.RequiredArgsConstructor; - import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import java.util.UUID; - @Service @Transactional @RequiredArgsConstructor diff --git a/src/main/java/com/retrip/crew/application/in/RecruitmentQuestionService.java b/src/main/java/com/retrip/crew/application/in/RecruitmentQuestionService.java deleted file mode 100644 index 91020f9..0000000 --- a/src/main/java/com/retrip/crew/application/in/RecruitmentQuestionService.java +++ /dev/null @@ -1,87 +0,0 @@ -package com.retrip.crew.application.in; - -import com.retrip.crew.application.in.request.CreateRecruitmentQuestionRequest; -import com.retrip.crew.application.in.request.UpdateRecruitmentQuestionRequest; -import com.retrip.crew.application.in.response.CreateRecruitmentQuestionResponse; -import com.retrip.crew.application.in.response.RecruitmentQuestionResponse; -import com.retrip.crew.application.in.response.UpdateRecruitmentQuestionResponse; -import com.retrip.crew.application.in.usecase.GetRecruitmentQuestionUseCase; -import com.retrip.crew.application.in.usecase.ManageRecruitmentQuestionUseCase; -import com.retrip.crew.application.out.repository.CrewMemberQueryRepository; -import com.retrip.crew.application.out.repository.CrewQueryRepository; -import com.retrip.crew.application.out.repository.RecruitmentQuestionQueryRepository; -import com.retrip.crew.domain.entity.Crew; -import com.retrip.crew.domain.entity.CrewMember; -import com.retrip.crew.domain.entity.RecruitmentQuestion; -import com.retrip.crew.domain.exception.CrewMemberNotFoundException; -import com.retrip.crew.domain.exception.CrewNotFoundException; -import com.retrip.crew.infra.adapter.in.presentation.rest.common.ScrollPageResponse; -import com.retrip.crew.infra.util.PaginationUtils; -import lombok.RequiredArgsConstructor; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Slice; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.util.List; -import java.util.UUID; - -@Service -@Transactional -@RequiredArgsConstructor -public class RecruitmentQuestionService implements ManageRecruitmentQuestionUseCase, GetRecruitmentQuestionUseCase { - - private final CrewQueryRepository crewQueryRepository; - private final CrewMemberQueryRepository crewMemberQueryRepository; - private final RecruitmentQuestionQueryRepository recruitmentQuestionQueryRepository; - - @Override - public CreateRecruitmentQuestionResponse createRecruitmentQuestion(UUID crewId, CreateRecruitmentQuestionRequest request) { - Crew crew = crewQueryRepository - .findByIdWithRecruitment(crewId) - .orElseThrow(CrewNotFoundException::new); - - RecruitmentQuestion question = RecruitmentQuestion.create(request.content(), crew); - crew.getRecruitment().addQuestion(question); - - return CreateRecruitmentQuestionResponse.of(question); - } - - @Override - public UpdateRecruitmentQuestionResponse updateRecruitmentQuestion(UUID crewId, UUID questionId, UpdateRecruitmentQuestionRequest request) { - Crew crew = crewQueryRepository - .findByIdWithRecruitment(crewId) - .orElseThrow(CrewNotFoundException::new); - - RecruitmentQuestion question = crew.getRecruitment() - .getRecruitmentQuestions() - .updateQuestion(questionId, request.content(), request.memberId()); - - return UpdateRecruitmentQuestionResponse.of(question); - } - - @Override - public void deleteRecruitmentQuestion(UUID crewId, UUID questionId, UUID memberId) { - Crew crew = crewQueryRepository - .findByIdWithRecruitment(crewId) - .orElseThrow(CrewNotFoundException::new); - - CrewMember crewMember = findCrewMemberByMemberId(crewId, memberId); - -// crew.getRecruitment() -// .getRecruitmentQuestions() -// .deleteQuestion(questionId, crewMember); - } - - private CrewMember findCrewMemberByMemberId(UUID crewId, UUID memberId) { - return crewMemberQueryRepository - .findCrewMemberByMemberId(crewId, memberId) - .orElseThrow(CrewMemberNotFoundException::new); - } - - @Override - @Transactional(readOnly = true) - public List getRecruitmentQuestions(UUID crewId) { - return recruitmentQuestionQueryRepository.findRecruitmentQuestions(crewId); - } -} diff --git a/src/main/java/com/retrip/crew/application/in/request/CreateRecruitmentQuestionRequest.java b/src/main/java/com/retrip/crew/application/in/request/CreateRecruitmentQuestionRequest.java index e043ba5..da33d55 100644 --- a/src/main/java/com/retrip/crew/application/in/request/CreateRecruitmentQuestionRequest.java +++ b/src/main/java/com/retrip/crew/application/in/request/CreateRecruitmentQuestionRequest.java @@ -7,11 +7,8 @@ @Schema(description = "참여요청질문 생성 Request") public record CreateRecruitmentQuestionRequest( + @Schema(description = "질문 내용") @NotNull - @Size(min = 1, max = 100) - String content, - @Schema(description = "작성자") - @NotNull - UUID memberId + String content ) {} diff --git a/src/main/java/com/retrip/crew/application/in/request/UpdateRecruitmentQuestionRequest.java b/src/main/java/com/retrip/crew/application/in/request/UpdateRecruitmentQuestionRequest.java index f87599a..7b38935 100644 --- a/src/main/java/com/retrip/crew/application/in/request/UpdateRecruitmentQuestionRequest.java +++ b/src/main/java/com/retrip/crew/application/in/request/UpdateRecruitmentQuestionRequest.java @@ -7,11 +7,8 @@ @Schema(description = "참여요청질문 수정 Request") public record UpdateRecruitmentQuestionRequest( + @Schema(description = "질문 내용") @NotNull - @Size(min = 1, max = 100) - String content, - @Schema(description = "수정자") - @NotNull - UUID memberId + String content ) {} diff --git a/src/main/java/com/retrip/crew/application/in/response/RecruitmentQuestionResponse.java b/src/main/java/com/retrip/crew/application/in/response/RecruitmentQuestionResponse.java index 4171a56..ef126ec 100644 --- a/src/main/java/com/retrip/crew/application/in/response/RecruitmentQuestionResponse.java +++ b/src/main/java/com/retrip/crew/application/in/response/RecruitmentQuestionResponse.java @@ -1,6 +1,7 @@ package com.retrip.crew.application.in.response; import io.swagger.v3.oas.annotations.media.Schema; +import java.time.LocalDateTime; import java.util.UUID; @Schema(description = "참여요청질문 Response") diff --git a/src/main/java/com/retrip/crew/application/in/response/UpdateRecruitmentQuestionResponse.java b/src/main/java/com/retrip/crew/application/in/response/UpdateRecruitmentQuestionResponse.java index 5d8f9e5..0d5cc5e 100644 --- a/src/main/java/com/retrip/crew/application/in/response/UpdateRecruitmentQuestionResponse.java +++ b/src/main/java/com/retrip/crew/application/in/response/UpdateRecruitmentQuestionResponse.java @@ -7,8 +7,10 @@ @Schema(description = "참여요청질문 수정 Response") public record UpdateRecruitmentQuestionResponse( - @Schema(description = "질문 ID") UUID id, - @Schema(description = "질문 내용") String content + @Schema(description = "질문 ID") + UUID id, + @Schema(description = "질문 내용") + String content ) { public static UpdateRecruitmentQuestionResponse of(RecruitmentQuestion question) { return new UpdateRecruitmentQuestionResponse( diff --git a/src/main/java/com/retrip/crew/application/in/usecase/ManageRecruitmentQuestionUseCase.java b/src/main/java/com/retrip/crew/application/in/usecase/ManageRecruitmentQuestionUseCase.java index 7a74319..cacbdf7 100644 --- a/src/main/java/com/retrip/crew/application/in/usecase/ManageRecruitmentQuestionUseCase.java +++ b/src/main/java/com/retrip/crew/application/in/usecase/ManageRecruitmentQuestionUseCase.java @@ -3,12 +3,17 @@ import com.retrip.crew.application.in.request.CreateRecruitmentQuestionRequest; import com.retrip.crew.application.in.request.UpdateRecruitmentQuestionRequest; import com.retrip.crew.application.in.response.CreateRecruitmentQuestionResponse; +import com.retrip.crew.application.in.response.RecruitmentQuestionResponse; import com.retrip.crew.application.in.response.UpdateRecruitmentQuestionResponse; - +import java.util.List; import java.util.UUID; public interface ManageRecruitmentQuestionUseCase { - CreateRecruitmentQuestionResponse createRecruitmentQuestion(UUID crewId, CreateRecruitmentQuestionRequest request); - UpdateRecruitmentQuestionResponse updateRecruitmentQuestion(UUID crewId, UUID questionId, UpdateRecruitmentQuestionRequest request); - void deleteRecruitmentQuestion(UUID crewId, UUID questionId, UUID memberId); + CreateRecruitmentQuestionResponse createRecruitmentQuestion(UUID memberId, UUID crewId, CreateRecruitmentQuestionRequest request); + + UpdateRecruitmentQuestionResponse updateRecruitmentQuestion(UUID memberId, UUID crewId, UUID questionId, UpdateRecruitmentQuestionRequest request); + + void deleteRecruitmentQuestion(UUID memberId, UUID crewId, UUID questionId); + + List getRecruitmentQuestions(UUID crewId, UUID memberId); } diff --git a/src/main/java/com/retrip/crew/application/out/repository/CrewQueryRepository.java b/src/main/java/com/retrip/crew/application/out/repository/CrewQueryRepository.java index 1945997..bada9a6 100644 --- a/src/main/java/com/retrip/crew/application/out/repository/CrewQueryRepository.java +++ b/src/main/java/com/retrip/crew/application/out/repository/CrewQueryRepository.java @@ -14,6 +14,5 @@ public interface CrewQueryRepository { Slice getCrews(Pageable pageable, String keyword); Long getCrewCount(String keyword); Optional findByIdWithPosts(UUID id); - Optional findByIdWithRecruitment(UUID crewId); Page findAllContainsMember(Pageable pageable, UUID memberId); } diff --git a/src/main/java/com/retrip/crew/application/out/repository/RecruitmentQuestionQueryRepository.java b/src/main/java/com/retrip/crew/application/out/repository/RecruitmentQuestionQueryRepository.java index b559073..7a7581e 100644 --- a/src/main/java/com/retrip/crew/application/out/repository/RecruitmentQuestionQueryRepository.java +++ b/src/main/java/com/retrip/crew/application/out/repository/RecruitmentQuestionQueryRepository.java @@ -1,12 +1,10 @@ package com.retrip.crew.application.out.repository; import com.retrip.crew.application.in.response.RecruitmentQuestionResponse; -import com.retrip.crew.domain.entity.RecruitmentQuestion; import java.util.List; import java.util.UUID; public interface RecruitmentQuestionQueryRepository { List findRecruitmentQuestions(UUID crewId); - RecruitmentQuestion findByIdOrElseThrow(UUID questionId); } diff --git a/src/main/java/com/retrip/crew/application/out/repository/RecruitmentQuestionRepository.java b/src/main/java/com/retrip/crew/application/out/repository/RecruitmentQuestionRepository.java new file mode 100644 index 0000000..536df67 --- /dev/null +++ b/src/main/java/com/retrip/crew/application/out/repository/RecruitmentQuestionRepository.java @@ -0,0 +1,18 @@ +package com.retrip.crew.application.out.repository; + +import com.retrip.crew.domain.entity.CrewMember; +import com.retrip.crew.domain.entity.RecruitmentQuestion; +import java.util.Optional; +import java.util.UUID; +import org.springframework.data.jpa.repository.Query; + +public interface RecruitmentQuestionRepository extends ReadRepository { + + @Query(""" + select rq + from RecruitmentQuestion rq + join fetch rq.crew c + where rq.id = :questionId and c.id = :crewId + """) + Optional findByIdAndCrewId(UUID questionId, UUID crewId); +} 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 8557871..bb2afa7 100644 --- a/src/main/java/com/retrip/crew/domain/entity/Crew.java +++ b/src/main/java/com/retrip/crew/domain/entity/Crew.java @@ -1,7 +1,6 @@ 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; @@ -112,9 +111,19 @@ public void softDelete(UUID loginMemberId) { this.isDeleted = true; } - private void validateCrewLeader(UUID loginMemberId) { + public void validateCrewLeader(UUID loginMemberId) { if(!this.getCrewMembers().isLeader(loginMemberId)){ throw new NotCrewLeaderException(); } } + + public void addRecruitmentQuestion(UUID memberId, RecruitmentQuestion question) { + validateCrewLeader(memberId); + recruitment.addRecruitmentQuestion(question); + } + + public void deleteRecruitmentQuestion(UUID memberId, RecruitmentQuestion savedQuestion) { + validateCrewLeader(memberId); + recruitment.deleteRecruitmentQuestion(savedQuestion); + } } diff --git a/src/main/java/com/retrip/crew/domain/entity/Recruitment.java b/src/main/java/com/retrip/crew/domain/entity/Recruitment.java index 5fb8b27..663efa0 100644 --- a/src/main/java/com/retrip/crew/domain/entity/Recruitment.java +++ b/src/main/java/com/retrip/crew/domain/entity/Recruitment.java @@ -31,10 +31,9 @@ public class Recruitment { @OneToMany(mappedBy = "crew", cascade = CascadeType.ALL, orphanRemoval = true) private List demands = new ArrayList<>(); - @Embedded - private RecruitmentQuestions recruitmentQuestions; + @Embedded private RecruitmentQuestions recruitmentQuestions; - private Recruitment(int maxMembers, List questions, Crew crew) { + public Recruitment(int maxMembers, List questions, Crew crew) { this.maxMembers = maxMembers; this.status = RECRUITING; this.recruitmentQuestions = new RecruitmentQuestions(questions, crew); @@ -64,10 +63,6 @@ public void updateMaxMembers(int maxMembers) { this.maxMembers = maxMembers; } - public void addQuestion(RecruitmentQuestion question) { - this.recruitmentQuestions.add(question); - } - public Demand addDemand(UUID memberId, Crew crew) { if (isDuplicate(memberId)) { throw new DuplicateDemandException(); @@ -117,8 +112,6 @@ public void rejectDemand(Demand demand) { find.reject(); } - - private static void throwIfNotPending(Demand find) { if (find.isNotPending()) { throw new IllegalDemandStateException("참여 요청의 상태가 대기중이 아닙니다."); @@ -131,4 +124,12 @@ private Demand findDemand(Demand demand) { .findFirst() .orElseThrow(() -> new InvalidValueException("참여 요청을 찾을 수 없습니다.")); } + + public void addRecruitmentQuestion(RecruitmentQuestion question) { + this.recruitmentQuestions.add(question); + } + + public void deleteRecruitmentQuestion(RecruitmentQuestion savedQuestion) { + this.recruitmentQuestions.delete(savedQuestion); + } } diff --git a/src/main/java/com/retrip/crew/domain/entity/RecruitmentQuestion.java b/src/main/java/com/retrip/crew/domain/entity/RecruitmentQuestion.java index 6a43645..72cb7ed 100644 --- a/src/main/java/com/retrip/crew/domain/entity/RecruitmentQuestion.java +++ b/src/main/java/com/retrip/crew/domain/entity/RecruitmentQuestion.java @@ -1,14 +1,19 @@ package com.retrip.crew.domain.entity; -import com.retrip.crew.domain.exception.QuestionUpdateFailedException; import com.retrip.crew.domain.vo.QuestionContent; -import jakarta.persistence.*; +import jakarta.persistence.Column; +import jakarta.persistence.Embedded; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.ForeignKey; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import java.util.UUID; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; -import java.util.UUID; - @Entity @NoArgsConstructor(access = AccessLevel.PROTECTED, force = true) @Getter @@ -40,17 +45,7 @@ public static RecruitmentQuestion create(String content, Crew crew) { } public void update(String content, UUID memberId) { -// isUpdatable(this.getCreatedBy(), memberId); + this.crew.validateCrewLeader(memberId); this.content = new QuestionContent(content); } - - private void isUpdatable(UUID createBy, UUID updateBy) { - if (!createBy.equals(updateBy)) { - throw new QuestionUpdateFailedException(); - } - } - -// public boolean isDeletable(CrewMember crewMember) { -// return crewMember.isLeader() || crewMember.isCreatedBy(this.getCreatedBy()); -// } } diff --git a/src/main/java/com/retrip/crew/domain/entity/RecruitmentQuestions.java b/src/main/java/com/retrip/crew/domain/entity/RecruitmentQuestions.java index 840829f..238d466 100644 --- a/src/main/java/com/retrip/crew/domain/entity/RecruitmentQuestions.java +++ b/src/main/java/com/retrip/crew/domain/entity/RecruitmentQuestions.java @@ -1,6 +1,5 @@ package com.retrip.crew.domain.entity; -import com.retrip.crew.domain.exception.QuestionDeleteFailedException; import com.retrip.crew.domain.exception.QuestionNotFoundException; import com.retrip.crew.domain.exception.common.ErrorCode; import com.retrip.crew.domain.exception.common.InvalidValueException; @@ -9,38 +8,25 @@ import jakarta.persistence.OneToMany; import lombok.AccessLevel; import lombok.Getter; -import lombok.NoArgsConstructor; -import org.hibernate.annotations.BatchSize; import java.util.ArrayList; import java.util.List; import java.util.UUID; +import lombok.NoArgsConstructor; @Getter @Embeddable +@NoArgsConstructor(access = AccessLevel.PROTECTED, force = true) public class RecruitmentQuestions { private static final int MAX_QUESTIONS = 10; - @BatchSize(size = 100) @OneToMany(mappedBy = "crew", cascade = CascadeType.ALL, orphanRemoval = true) private List values = new ArrayList<>(); - public RecruitmentQuestions() { - this.values = createEmptyValues(); - } - public RecruitmentQuestions(List questions, Crew crew) { validateQuestions(questions); - this.values = createEmptyValues(); - questions.forEach(questionText -> { - RecruitmentQuestion question = RecruitmentQuestion.create(questionText, crew); - this.values.add(question); - }); - } - - private List createEmptyValues() { - return new ArrayList<>(); + questions.forEach(question -> this.values.add(RecruitmentQuestion.create(question, crew))); } private void validateQuestions(List values) { @@ -49,27 +35,6 @@ private void validateQuestions(List values) { } } - public RecruitmentQuestion updateQuestion(UUID questionId, String content, UUID memberId) { - RecruitmentQuestion question = findQuestion(questionId); - question.update(content, memberId); - return question; - } - -// public void deleteQuestion(UUID questionId, CrewMember crewMember) { -// RecruitmentQuestion question = findQuestion(questionId); -// if (!question.isDeletable(crewMember)) { -// throw new QuestionDeleteFailedException(); -// } -// this.values.remove(question); -// } - - private RecruitmentQuestion findQuestion(UUID questionId) { - return this.values.stream() - .filter(q -> q.getId().equals(questionId)) - .findAny() - .orElseThrow(QuestionNotFoundException::new); - } - public void add(RecruitmentQuestion question) { if (this.values.size() >= MAX_QUESTIONS) { throw new InvalidValueException(ErrorCode.INVALID_QUESTION_COUNT); @@ -77,9 +42,7 @@ public void add(RecruitmentQuestion question) { this.values.add(question); } - public List getContents() { - return values.stream() - .map(q -> q.getContent().getValue()) - .toList(); + public void delete(RecruitmentQuestion savedQuestion) { + this.values.remove(savedQuestion); } } diff --git a/src/main/java/com/retrip/crew/infra/adapter/in/presentation/rest/DemandController.java b/src/main/java/com/retrip/crew/infra/adapter/in/presentation/rest/DemandController.java index 6d16606..f0ac50a 100644 --- a/src/main/java/com/retrip/crew/infra/adapter/in/presentation/rest/DemandController.java +++ b/src/main/java/com/retrip/crew/infra/adapter/in/presentation/rest/DemandController.java @@ -1,14 +1,21 @@ package com.retrip.crew.infra.adapter.in.presentation.rest; +import com.retrip.crew.application.in.request.CreateRecruitmentQuestionRequest; +import com.retrip.crew.application.in.request.UpdateRecruitmentQuestionRequest; import com.retrip.crew.application.in.request.crew.CrewOrder; import com.retrip.crew.application.in.request.demand.CreateDemandRequest; import com.retrip.crew.application.in.request.demand.DemandOrder; +import com.retrip.crew.application.in.response.CreateRecruitmentQuestionResponse; +import com.retrip.crew.application.in.response.RecruitmentQuestionResponse; +import com.retrip.crew.application.in.response.UpdateRecruitmentQuestionResponse; import com.retrip.crew.application.in.response.demand.*; import com.retrip.crew.application.in.usecase.ManageDemandUseCase; +import com.retrip.crew.application.in.usecase.ManageRecruitmentQuestionUseCase; import com.retrip.crew.application.in.usecase.UpdateRecruitmentUseCase; import com.retrip.crew.infra.adapter.in.presentation.rest.common.ApiResponse; import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.tags.Tag; +import java.util.List; import lombok.RequiredArgsConstructor; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -23,6 +30,7 @@ @Tag(name = "Recruitment", description = "크루 참여 모집 서비스") public class DemandController { private final UpdateRecruitmentUseCase updateRecruitmentUseCase; + private final ManageRecruitmentQuestionUseCase manageRecruitmentQuestionUseCase; private final ManageDemandUseCase manageDemandUseCase; @PutMapping("/{crewId}/recruitments/start") @@ -105,4 +113,44 @@ public ApiResponse rejectDemand( RejectDemandResponse demand = manageDemandUseCase.rejectDemand(crewId, demandId, memberId); return ApiResponse.ok(demand); } + + @PostMapping("/{crewId}/demands/question") + @Schema(description = "크루 참여 요청 질문 등록") + public ApiResponse createRecruitmentQuestion( + @PathVariable final UUID crewId, + @RequestParam final UUID memberId, + @RequestBody CreateRecruitmentQuestionRequest request) { + CreateRecruitmentQuestionResponse demand = manageRecruitmentQuestionUseCase.createRecruitmentQuestion(memberId, crewId, request); + return ApiResponse.created(demand); + } + + @PostMapping("/{crewId}/demands/question/{questionId}") + @Schema(description = "크루 참여 요청 질문 수정") + public ApiResponse updateRecruitmentQuestion( + @PathVariable final UUID crewId, + @PathVariable final UUID questionId, + @RequestParam final UUID memberId, + @RequestBody UpdateRecruitmentQuestionRequest request) { + UpdateRecruitmentQuestionResponse demand = manageRecruitmentQuestionUseCase.updateRecruitmentQuestion(memberId, crewId, questionId, request); + return ApiResponse.ok(demand); + } + + @DeleteMapping("/{crewId}/demands/question/{questionId}") + @Schema(description = "크루 참여 요청 질문 삭제") + public ApiResponse deleteRecruitmentQuestion( + @PathVariable final UUID crewId, + @PathVariable final UUID questionId, + @RequestParam final UUID memberId) { + manageRecruitmentQuestionUseCase.deleteRecruitmentQuestion(memberId, crewId, questionId); + return ApiResponse.noContent(); + } + + @GetMapping("/{crewId}/demands/question") + @Schema(description = "크루 참여 요청 질문 조회") + public ApiResponse> getRecruitmentQuestions( + @PathVariable final UUID crewId, + @RequestParam final UUID memberId) { + List response = manageRecruitmentQuestionUseCase.getRecruitmentQuestions(crewId, memberId); + return ApiResponse.ok(response); + } } diff --git a/src/main/java/com/retrip/crew/infra/adapter/out/persistence/mysql/query/CrewQuerydslRepository.java b/src/main/java/com/retrip/crew/infra/adapter/out/persistence/mysql/query/CrewQuerydslRepository.java index 3dc9a6b..22e8696 100644 --- a/src/main/java/com/retrip/crew/infra/adapter/out/persistence/mysql/query/CrewQuerydslRepository.java +++ b/src/main/java/com/retrip/crew/infra/adapter/out/persistence/mysql/query/CrewQuerydslRepository.java @@ -156,15 +156,4 @@ private OrderSpecifier createCrewOrderSpecifier(Pageable pageable) { } return new OrderSpecifier<>(Order.ASC, crew.createdAt); } - - @Override - public Optional findByIdWithRecruitment(UUID crewId) { - return Optional.ofNullable( - query.selectFrom(crew) - .distinct() - .leftJoin(crew.recruitment.recruitmentQuestions.values).fetchJoin() - .where(crew.id.eq(crewId)) - .fetchOne() - ); - } } diff --git a/src/main/java/com/retrip/crew/infra/adapter/out/persistence/mysql/query/RecruitmentQuestionQuerydslRepository.java b/src/main/java/com/retrip/crew/infra/adapter/out/persistence/mysql/query/RecruitmentQuestionQuerydslRepository.java index 6e2dda9..39e813f 100644 --- a/src/main/java/com/retrip/crew/infra/adapter/out/persistence/mysql/query/RecruitmentQuestionQuerydslRepository.java +++ b/src/main/java/com/retrip/crew/infra/adapter/out/persistence/mysql/query/RecruitmentQuestionQuerydslRepository.java @@ -6,8 +6,6 @@ import com.querydsl.jpa.impl.JPAQueryFactory; import com.retrip.crew.application.in.response.RecruitmentQuestionResponse; import com.retrip.crew.application.out.repository.RecruitmentQuestionQueryRepository; -import com.retrip.crew.domain.entity.RecruitmentQuestion; -import com.retrip.crew.domain.exception.QuestionNotFoundException; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Repository; @@ -25,26 +23,12 @@ public List findRecruitmentQuestions(UUID crewId) { return query .select(Projections.constructor( RecruitmentQuestionResponse.class, - recruitmentQuestion.id, - recruitmentQuestion.content.value, - recruitmentQuestion.createdAt)) + recruitmentQuestion.id.as("id"), + recruitmentQuestion.content.value.as("content")) + ) .from(recruitmentQuestion) .where(recruitmentQuestion.crew.id.eq(crewId)) .orderBy(recruitmentQuestion.createdAt.desc()) .fetch(); } - - @Override - public RecruitmentQuestion findByIdOrElseThrow(UUID questionId) { - RecruitmentQuestion question = query - .selectFrom(recruitmentQuestion) - .where(recruitmentQuestion.id.eq(questionId)) - .fetchOne(); - - if (question == null) { - throw new QuestionNotFoundException(); - } - - return question; - } } \ No newline at end of file From bf68c845911f8f3d301d8a4bf13edc95f5bd7c73 Mon Sep 17 00:00:00 2001 From: pparkjs Date: Fri, 25 Jul 2025 23:15:19 +0900 Subject: [PATCH 2/2] =?UTF-8?q?test:=20=ED=81=AC=EB=A3=A8=EC=B0=B8?= =?UTF-8?q?=EC=97=AC=EC=9A=94=EC=B2=AD=20=EC=A7=88=EB=AC=B8=20=EB=93=B1?= =?UTF-8?q?=EB=A1=9D,=EC=88=98=EC=A0=95,=EC=82=AD=EC=A0=9C,=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EB=8B=A8=EC=9C=84=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?(#42)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../crew/application/in/CrewServiceTest.java | 73 ++++----------- .../application/in/DemandServiceTest.java | 88 +++++++++++++++++++ .../crew/application/in/PostServiceTest.java | 12 +-- .../com/retrip/crew/common/ServiceTest.java | 8 +- .../crew/common/config/QuerydslConfig.java | 7 ++ .../retrip/crew/domain/entity/CrewTest.java | 2 +- .../crew/domain/entity/RecruitmentTest.java | 29 +++--- 7 files changed, 144 insertions(+), 75 deletions(-) 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 a0acaff..6b89820 100644 --- a/src/test/java/com/retrip/crew/application/in/CrewServiceTest.java +++ b/src/test/java/com/retrip/crew/application/in/CrewServiceTest.java @@ -1,41 +1,41 @@ package com.retrip.crew.application.in; +import static com.retrip.crew.common.fixture.CrewFixture.LEADER_ID; +import static com.retrip.crew.common.fixture.CrewFixture.MEMBER_ID; +import static com.retrip.crew.common.fixture.CrewFixture.createCrew; +import static com.retrip.crew.common.fixture.CrewFixture.createCrewRequest; +import static com.retrip.crew.common.fixture.CrewFixture.createDefaultQuestions; +import static com.retrip.crew.common.fixture.CrewFixture.createMultipleCrews; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertThrows; + 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.demand.CreateDemandRequest; import com.retrip.crew.application.in.response.IntroductionCreateResponse; import com.retrip.crew.application.in.response.IntroductionDetailResponse; import com.retrip.crew.application.in.response.crew.CrewCreateResponse; import com.retrip.crew.application.in.response.crew.CrewDetailResponse; import com.retrip.crew.application.in.response.crew.CrewListResponse; import com.retrip.crew.application.in.response.crew.CrewUpdateResponse; -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 java.util.List; +import java.util.UUID; import org.junit.jupiter.api.Test; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; -import java.util.List; -import java.util.UUID; - -import static com.retrip.crew.common.fixture.CrewFixture.*; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.junit.jupiter.api.Assertions.assertAll; -import static org.junit.jupiter.api.Assertions.assertThrows; - class CrewServiceTest extends ServiceTest { @Test void 크루를_생성_한다() { @@ -77,45 +77,6 @@ class CrewServiceTest extends ServiceTest { ); } - @Test - void 크루_참여_요청을_생성한다() { - Crew crew = crewRepository.save(Crew.create( - "속초 크루원 구함", - "속초 친구 구합니다! 나이는 20~40.. 많은 가입 부탁드립니다.", - 100, - MEMBER_ID, - createDefaultQuestions() - )); - CreateDemandRequest request = new CreateDemandRequest(MEMBER_ID); - - CreateDemandResponse response = demandService.createDemand(crew.getId(), request); - - List demands = crew.getRecruitment().getDemands(); - assertAll( - () -> assertThat(demands.size()).isEqualTo(1), - () -> assertThat(response.memberId()).isEqualTo(demands.get(0).getMemberId()) - ); - } - - @Test - void 이미_요청한_사용자는_다시_크루에_요청할_수_없다() { - Crew crew = Crew.create( - "속초 크루원 구함", - "속초 친구 구합니다! 나이는 20~40.. 많은 가입 부탁드립니다.", - 100, - MEMBER_ID, - List.of("질문1") - ); - crew.demand(MEMBER_ID); - crew.demand(UUID.randomUUID()); - crew.demand(UUID.randomUUID()); - Crew save = crewRepository.save(crew); - CreateDemandRequest request = new CreateDemandRequest(MEMBER_ID); - - assertThatThrownBy(() -> demandService.createDemand(save.getId(), request)) - .isExactlyInstanceOf(IllegalStateException.class); - } - @Test void 크루를_검색_및_정렬_필터링하여_조회한다(){ //given @@ -125,7 +86,7 @@ class CrewServiceTest extends ServiceTest { "속초 크루원 구함", "속초 친구 구합니다! 나이는 20~40.. 많은 가입 부탁드립니다.", 5, - List.of("질문1") + createDefaultQuestions() ); requests.forEach(request -> { CrewCreateResponse response = crewService.createCrew(request); @@ -155,7 +116,7 @@ class CrewServiceTest extends ServiceTest { "속초 크루원 구함", "속초 친구 구합니다! 나이는 20~40.. 많은 가입 부탁드립니다.", 5, - List.of("질문1") + createDefaultQuestions() ); UUID crewId = crewService.createCrew(request).id(); @@ -310,7 +271,8 @@ class CrewServiceTest extends ServiceTest { "속초 크루원 구함", "속초 친구 구합니다! 나이는 20~40.. 많은 가입 부탁드립니다.", 100, - MEMBER_ID + MEMBER_ID, + createDefaultQuestions() ); Crew savedCrew = crewRepository.save(crew); @@ -329,7 +291,8 @@ class CrewServiceTest extends ServiceTest { "속초 크루원 구함", "속초 친구 구합니다! 나이는 20~40.. 많은 가입 부탁드립니다.", 100, - LEADER_ID + LEADER_ID, + createDefaultQuestions() ); Crew savedCrew = crewRepository.save(crew); Demand demand = savedCrew.demand(MEMBER_ID); diff --git a/src/test/java/com/retrip/crew/application/in/DemandServiceTest.java b/src/test/java/com/retrip/crew/application/in/DemandServiceTest.java index 4ec8692..7b5d17c 100644 --- a/src/test/java/com/retrip/crew/application/in/DemandServiceTest.java +++ b/src/test/java/com/retrip/crew/application/in/DemandServiceTest.java @@ -1,15 +1,22 @@ package com.retrip.crew.application.in; +import com.retrip.crew.application.in.request.CreateRecruitmentQuestionRequest; +import com.retrip.crew.application.in.request.UpdateRecruitmentQuestionRequest; import com.retrip.crew.application.in.request.crew.CrewOrder; import com.retrip.crew.application.in.request.demand.CreateDemandRequest; import com.retrip.crew.application.in.request.demand.DemandOrder; +import com.retrip.crew.application.in.response.CreateRecruitmentQuestionResponse; +import com.retrip.crew.application.in.response.RecruitmentQuestionResponse; +import com.retrip.crew.application.in.response.UpdateRecruitmentQuestionResponse; import com.retrip.crew.application.in.response.demand.CreateDemandResponse; import com.retrip.crew.application.in.response.demand.CrewsOfDemandResponse; import com.retrip.crew.application.in.response.demand.DemandsResponse; import com.retrip.crew.common.ServiceTest; import com.retrip.crew.domain.entity.Crew; import com.retrip.crew.domain.entity.Demand; +import com.retrip.crew.domain.entity.RecruitmentQuestion; import com.retrip.crew.domain.exception.DuplicateDemandException; +import com.retrip.crew.domain.exception.QuestionNotFoundException; import com.retrip.crew.domain.vo.DemandStatus; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -123,4 +130,85 @@ class DemandServiceTest extends ServiceTest { // then assertThat(response.getTotalElements()).isEqualTo(5); } + + @Test + void 크루_참여_요청_질문을_등록한다() { + // given + Crew crew = crewRepository.save(createCrew(LEADER_ID)); + CreateRecruitmentQuestionRequest request = new CreateRecruitmentQuestionRequest("크루 참여 동기를 작성해주세요."); + + // when + CreateRecruitmentQuestionResponse response = + demandService.createRecruitmentQuestion(LEADER_ID, crew.getId(), request); + + // then + + // then + List questions = crew.getRecruitment().getRecruitmentQuestions().getValues(); + assertAll( + () -> assertThat(questions).hasSize(6), + () -> assertThat(questions.get(5).getContent().getValue()).isEqualTo(request.content()), + () -> assertThat(response.content()).isEqualTo(request.content()) + ); + } + + @Test + void 크루_참여_요청_질문을_수정한다() { + // given + Crew crew = crewRepository.save(createCrew(LEADER_ID)); + RecruitmentQuestion question = RecruitmentQuestion.create("크루 참여 동기를 작성해주세요.", crew); + crew.addRecruitmentQuestion(LEADER_ID, question); + + UpdateRecruitmentQuestionRequest request = new UpdateRecruitmentQuestionRequest("크루 참여 동기를 작성해주세요요요요요"); + + // when + UpdateRecruitmentQuestionResponse response = + demandService.updateRecruitmentQuestion(LEADER_ID, crew.getId(), question.getId(), request); + + // then + assertThat(question.getContent().getValue()).isEqualTo(request.content()); + assertThat(response.content()).isEqualTo(request.content()); + } + + @Test + void 크루_참여_요청_질문을_삭제한다() { + // given + Crew crew = crewRepository.save(createCrew(LEADER_ID)); + RecruitmentQuestion question = RecruitmentQuestion.create("크루 참여 동기를 작성해주세요.", crew); + crew.addRecruitmentQuestion(LEADER_ID, question); + + // when + demandService.deleteRecruitmentQuestion(LEADER_ID, crew.getId(), question.getId()); + + // then + assertThat(crew.getRecruitment().getRecruitmentQuestions().getValues().size()).isEqualTo(5); + } + + @Test + void 크루_참여_요청_질문을_조회한다() { + // given + Crew crew = crewRepository.save(createCrew(LEADER_ID)); + RecruitmentQuestion question1 = RecruitmentQuestion.create("크루 참여 동기를 작성해주세요.1", crew); + RecruitmentQuestion question2 = RecruitmentQuestion.create("크루 참여 동기를 작성해주세요.2", crew); + crew.addRecruitmentQuestion(LEADER_ID, question1); + crew.addRecruitmentQuestion(LEADER_ID, question2); + + // when + List responses = + demandService.getRecruitmentQuestions(LEADER_ID, crew.getId()); + + // then + assertThat(responses).hasSize(7); + assertThat(responses) + .extracting(RecruitmentQuestionResponse::content) + .containsExactlyInAnyOrder( + "크루 참여 동기를 작성해주세요.1", + "크루 참여 동기를 작성해주세요.2", + "크루에 지원한 이유는 무엇인가요?", + "어떤 활동을 기대하고 있나요?", + "자신을 한 문장으로 표현한다면?", + "크루에서 어떤 역할을 하고 싶나요?", + "추가로 하고 싶은 말이 있나요?" + ); + } } diff --git a/src/test/java/com/retrip/crew/application/in/PostServiceTest.java b/src/test/java/com/retrip/crew/application/in/PostServiceTest.java index 4b767a6..1d16d4f 100644 --- a/src/test/java/com/retrip/crew/application/in/PostServiceTest.java +++ b/src/test/java/com/retrip/crew/application/in/PostServiceTest.java @@ -1,5 +1,11 @@ package com.retrip.crew.application.in; +import static com.retrip.crew.common.fixture.CrewFixture.createDefaultQuestions; +import static com.retrip.crew.common.fixture.PostFixture.MEMBER_ID; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; + import com.retrip.crew.application.in.factory.BasePostServiceTest; import com.retrip.crew.application.in.request.CreatePostRequest; import com.retrip.crew.application.in.request.PostOrder; @@ -13,12 +19,6 @@ import org.junit.jupiter.api.Test; import org.springframework.data.domain.PageRequest; -import static com.retrip.crew.common.fixture.CrewFixture.createDefaultQuestions; -import static com.retrip.crew.common.fixture.PostFixture.MEMBER_ID; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertAll; -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; - class PostServiceTest extends BasePostServiceTest { @Test diff --git a/src/test/java/com/retrip/crew/common/ServiceTest.java b/src/test/java/com/retrip/crew/common/ServiceTest.java index 65ed4dc..1fb2aa3 100644 --- a/src/test/java/com/retrip/crew/common/ServiceTest.java +++ b/src/test/java/com/retrip/crew/common/ServiceTest.java @@ -34,6 +34,12 @@ public class ServiceTest { @Autowired protected IntroductionQueryRepository introductionQueryRepository; + @Autowired + protected RecruitmentQuestionQueryRepository recruitmentQuestionQueryRepository; + + @Autowired + protected RecruitmentQuestionRepository recruitmentQuestionRepository; + @Autowired protected TestEntityManager entityManager; @@ -44,6 +50,6 @@ public class ServiceTest { @BeforeEach void setUp() { crewService = new CrewService(crewRepository, crewMemberRepository, crewQueryRepository, introductionRepository, introductionQueryRepository); - demandService = new DemandService(crewRepository, demandRepository, crewQueryRepository); + demandService = new DemandService(crewRepository, demandRepository, crewQueryRepository, recruitmentQuestionRepository, recruitmentQuestionQueryRepository); } } diff --git a/src/test/java/com/retrip/crew/common/config/QuerydslConfig.java b/src/test/java/com/retrip/crew/common/config/QuerydslConfig.java index e7877fb..4a7d466 100644 --- a/src/test/java/com/retrip/crew/common/config/QuerydslConfig.java +++ b/src/test/java/com/retrip/crew/common/config/QuerydslConfig.java @@ -2,10 +2,12 @@ import com.querydsl.jpa.impl.JPAQueryFactory; import com.retrip.crew.application.out.repository.CrewMemberQueryRepository; +import com.retrip.crew.application.out.repository.RecruitmentQuestionQueryRepository; import com.retrip.crew.infra.adapter.out.persistence.mysql.query.CrewMemberQuerydslRepository; import com.retrip.crew.infra.adapter.out.persistence.mysql.query.CrewQuerydslRepository; import com.retrip.crew.infra.adapter.out.persistence.mysql.query.IntroductionQuerydslRepository; +import com.retrip.crew.infra.adapter.out.persistence.mysql.query.RecruitmentQuestionQuerydslRepository; import jakarta.persistence.EntityManager; import org.springframework.beans.factory.annotation.Autowired; @@ -34,6 +36,11 @@ public CrewMemberQueryRepository crewMemberQueryRepository(JPAQueryFactory jpaQu return new CrewMemberQuerydslRepository(jpaQueryFactory); } + @Bean + public RecruitmentQuestionQueryRepository recruitmentQuestionQueryRepository(JPAQueryFactory jpaQueryFactory) { + return new RecruitmentQuestionQuerydslRepository(jpaQueryFactory); + } + @Bean public IntroductionQuerydslRepository introductionQuerydslRepository( JPAQueryFactory jpaQueryFactory) { diff --git a/src/test/java/com/retrip/crew/domain/entity/CrewTest.java b/src/test/java/com/retrip/crew/domain/entity/CrewTest.java index 6df95f5..a870f37 100644 --- a/src/test/java/com/retrip/crew/domain/entity/CrewTest.java +++ b/src/test/java/com/retrip/crew/domain/entity/CrewTest.java @@ -17,7 +17,7 @@ class CrewTest { "속초 친구 구합니다! 나이는 20~40.. 많은 가입 부탁드립니다.", 100, LEADER_ID, - List.of("질문1")) + createDefaultQuestions()) ).doesNotThrowAnyException(); } diff --git a/src/test/java/com/retrip/crew/domain/entity/RecruitmentTest.java b/src/test/java/com/retrip/crew/domain/entity/RecruitmentTest.java index 7c99d2c..bef8138 100644 --- a/src/test/java/com/retrip/crew/domain/entity/RecruitmentTest.java +++ b/src/test/java/com/retrip/crew/domain/entity/RecruitmentTest.java @@ -19,7 +19,8 @@ class RecruitmentTest { @Test void 모집을_생성한다() { - assertThatCode(() -> new Recruitment(100,)) + Crew crew = createCrew(LEADER_ID); + assertThatCode(() -> new Recruitment(100,createDefaultQuestions(), crew)) .doesNotThrowAnyException(); } @@ -27,7 +28,7 @@ class RecruitmentTest { void 참여_요청을_취소한다() { // given Crew crew = createCrew(LEADER_ID); - Recruitment recruitment = new Recruitment(100); + Recruitment recruitment = new Recruitment(100,createDefaultQuestions(), crew); Demand demand = new Demand(정수_ID, crew); List demands = List.of( demand, @@ -49,7 +50,7 @@ class RecruitmentTest { void 취소한_참여_요청을_재요청_한다() { // given Crew crew = createCrew(LEADER_ID); - Recruitment recruitment = new Recruitment(100); + Recruitment recruitment = new Recruitment(100,createDefaultQuestions(), crew); Demand demand = new Demand(정수_ID, crew); List demands = List.of( demand, @@ -73,7 +74,7 @@ class RecruitmentTest { void 대기_상태가_아니면_참여_요청을_취소할_수_있다(DemandStatus status) { // given Crew crew = createCrew(LEADER_ID); - Recruitment recruitment = new Recruitment(100); + Recruitment recruitment = new Recruitment(100,createDefaultQuestions(), crew); Demand demand = new Demand(정수_ID, crew); List demands = List.of( demand, @@ -94,7 +95,7 @@ class RecruitmentTest { void 참여_요청을_승인한다() { // given Crew crew = createCrew(LEADER_ID); - Recruitment recruitment = new Recruitment(100); + Recruitment recruitment = new Recruitment(100,createDefaultQuestions(), crew); Demand demand = new Demand(정수_ID, crew); ReflectionTestUtils.setField(recruitment, "demands", List.of(demand)); @@ -111,9 +112,10 @@ class RecruitmentTest { List questions = List.of( "1","2","3","4","5","6","7","8","9","10","11" ); + Crew crew = createCrew(LEADER_ID); // when, then - assertThatThrownBy(() -> new Recruitment(10, questions)) + assertThatThrownBy(() -> new Recruitment(10, questions, crew)) .isInstanceOf(InvalidValueException.class) .hasMessageContaining("질문"); } @@ -122,21 +124,24 @@ class RecruitmentTest { void 질문_내용이_100자를_넘으면_예외가_발생한다() { String longQuestion = "a".repeat(101); List questions = List.of(longQuestion); + Crew crew = createCrew(LEADER_ID); - assertThatThrownBy(() -> new Recruitment(10, questions)) - .isInstanceOf(InvalidValueException.class) - .hasMessageContaining("질문 내용은 100자를 넘을 수 없습니다."); + assertThatThrownBy(() -> new Recruitment(10, questions, crew)) + .isInstanceOf(InvalidValueException.class); } @Test void 질문_목록을_문자열로_조회할_수_있다() { // given - List questions = List.of("가입 이유는?", "이전에 크루 활동을 해본 경험이 있나요?"); - Recruitment recruitment = new Recruitment(10, questions); + Crew crew = createCrew(LEADER_ID); + List questions = List.of("가입 이유는 무엇인가요?", "이전에 크루 활동을 해본 경험이 있나요?"); + Recruitment recruitment = new Recruitment(10, questions, crew); // when - List result = recruitment.getRecruitmentQuestions(); + List result = recruitment.getRecruitmentQuestions().getValues().stream() + .map(question -> question.getContent().getValue()) + .toList(); // then assertThat(result).containsExactlyElementsOf(questions);