diff --git a/src/main/java/com/example/solidconnection/mentor/controller/MentoringForMenteeController.java b/src/main/java/com/example/solidconnection/mentor/controller/MentoringForMenteeController.java new file mode 100644 index 000000000..28683cd37 --- /dev/null +++ b/src/main/java/com/example/solidconnection/mentor/controller/MentoringForMenteeController.java @@ -0,0 +1,76 @@ +package com.example.solidconnection.mentor.controller; + +import com.example.solidconnection.common.VerifyStatus; +import com.example.solidconnection.common.dto.SliceResponse; +import com.example.solidconnection.common.resolver.AuthorizedUser; +import com.example.solidconnection.mentor.dto.CheckMentoringRequest; +import com.example.solidconnection.mentor.dto.CheckedMentoringsResponse; +import com.example.solidconnection.mentor.dto.MentoringApplyRequest; +import com.example.solidconnection.mentor.dto.MentoringApplyResponse; +import com.example.solidconnection.mentor.dto.MentoringForMenteeResponse; +import com.example.solidconnection.mentor.service.MentoringCheckService; +import com.example.solidconnection.mentor.service.MentoringCommandService; +import com.example.solidconnection.mentor.service.MentoringQueryService; +import com.example.solidconnection.security.annotation.RequireRoleAccess; +import com.example.solidconnection.siteuser.domain.Role; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.web.PageableDefault; +import org.springframework.data.web.SortDefault; +import org.springframework.data.web.SortDefault.SortDefaults; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/mentee/mentorings") +public class MentoringForMenteeController { + + private final MentoringCommandService mentoringCommandService; + private final MentoringQueryService mentoringQueryService; + private final MentoringCheckService mentoringCheckService; + + @RequireRoleAccess(roles = Role.MENTEE) + @PostMapping + public ResponseEntity applyMentoring( + @AuthorizedUser long siteUserId, + @Valid @RequestBody MentoringApplyRequest mentoringApplyRequest + ) { + MentoringApplyResponse response = mentoringCommandService.applyMentoring(siteUserId, mentoringApplyRequest); + return ResponseEntity.ok(response); + } + + @RequireRoleAccess(roles = Role.MENTEE) + @GetMapping + public ResponseEntity> getMentorings( + @AuthorizedUser long siteUserId, + @RequestParam("verify-status") VerifyStatus verifyStatus, + @PageableDefault(size = 3) + @SortDefaults({ + @SortDefault(sort = "createdAt", direction = Sort.Direction.DESC), + @SortDefault(sort = "id", direction = Sort.Direction.DESC) + }) + Pageable pageable + ) { + SliceResponse response = mentoringQueryService.getMentoringsForMentee(siteUserId, verifyStatus, pageable); + return ResponseEntity.ok(response); + } + + @RequireRoleAccess(roles = {Role.MENTEE}) + @PatchMapping("/check") + public ResponseEntity checkMentorings( + @AuthorizedUser long siteUserId, + @Valid @RequestBody CheckMentoringRequest checkMentoringRequest + ) { + CheckedMentoringsResponse response = mentoringCheckService.checkMentoringsForMentee(siteUserId, checkMentoringRequest); + return ResponseEntity.ok(response); + } +} diff --git a/src/main/java/com/example/solidconnection/mentor/controller/MentoringController.java b/src/main/java/com/example/solidconnection/mentor/controller/MentoringForMentorController.java similarity index 58% rename from src/main/java/com/example/solidconnection/mentor/controller/MentoringController.java rename to src/main/java/com/example/solidconnection/mentor/controller/MentoringForMentorController.java index 5a347f3fb..b9fb2f63e 100644 --- a/src/main/java/com/example/solidconnection/mentor/controller/MentoringController.java +++ b/src/main/java/com/example/solidconnection/mentor/controller/MentoringForMentorController.java @@ -1,57 +1,59 @@ package com.example.solidconnection.mentor.controller; +import com.example.solidconnection.common.dto.SliceResponse; import com.example.solidconnection.common.resolver.AuthorizedUser; -import com.example.solidconnection.mentor.dto.MentoringApplyRequest; -import com.example.solidconnection.mentor.dto.MentoringApplyResponse; -import com.example.solidconnection.mentor.dto.MentoringCheckResponse; +import com.example.solidconnection.mentor.dto.CheckMentoringRequest; +import com.example.solidconnection.mentor.dto.CheckedMentoringsResponse; import com.example.solidconnection.mentor.dto.MentoringConfirmRequest; import com.example.solidconnection.mentor.dto.MentoringConfirmResponse; import com.example.solidconnection.mentor.dto.MentoringCountResponse; -import com.example.solidconnection.mentor.dto.MentoringListResponse; +import com.example.solidconnection.mentor.dto.MentoringForMentorResponse; +import com.example.solidconnection.mentor.service.MentoringCheckService; import com.example.solidconnection.mentor.service.MentoringCommandService; import com.example.solidconnection.mentor.service.MentoringQueryService; import com.example.solidconnection.security.annotation.RequireRoleAccess; import com.example.solidconnection.siteuser.domain.Role; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.web.PageableDefault; +import org.springframework.data.web.SortDefault; +import org.springframework.data.web.SortDefault.SortDefaults; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequiredArgsConstructor -@RequestMapping("/mentorings") -public class MentoringController { +@RequestMapping("/mentor/mentorings") +public class MentoringForMentorController { private final MentoringCommandService mentoringCommandService; private final MentoringQueryService mentoringQueryService; + private final MentoringCheckService mentoringCheckService; - @RequireRoleAccess(roles = Role.MENTEE) - @PostMapping("/apply") - public ResponseEntity applyMentoring( + @RequireRoleAccess(roles = {Role.ADMIN, Role.MENTOR}) + @GetMapping + public ResponseEntity> getMentorings( @AuthorizedUser long siteUserId, - @Valid @RequestBody MentoringApplyRequest mentoringApplyRequest + @PageableDefault(size = 3) + @SortDefaults({ + @SortDefault(sort = "createdAt", direction = Sort.Direction.DESC), + @SortDefault(sort = "id", direction = Sort.Direction.DESC) + }) + Pageable pageable ) { - MentoringApplyResponse response = mentoringCommandService.applyMentoring(siteUserId, mentoringApplyRequest); + SliceResponse response = mentoringQueryService.getMentoringsForMentor(siteUserId, pageable); return ResponseEntity.ok(response); } @RequireRoleAccess(roles = {Role.ADMIN, Role.MENTOR}) - @GetMapping("/apply") - public ResponseEntity getMentorings( - @AuthorizedUser long siteUserId - ) { - MentoringListResponse responses = mentoringQueryService.getMentorings(siteUserId); - return ResponseEntity.ok(responses); - } - - @RequireRoleAccess(roles = {Role.ADMIN, Role.MENTOR}) - @PatchMapping("/{mentoring-id}/apply") + @PatchMapping("/{mentoring-id}") public ResponseEntity confirmMentoring( @AuthorizedUser long siteUserId, @PathVariable("mentoring-id") Long mentoringId, @@ -62,12 +64,12 @@ public ResponseEntity confirmMentoring( } @RequireRoleAccess(roles = {Role.ADMIN, Role.MENTOR}) - @PatchMapping("/{mentoring-id}/check") - public ResponseEntity checkMentoring( + @PatchMapping("/check") + public ResponseEntity checkMentoring( @AuthorizedUser long siteUserId, - @PathVariable("mentoring-id") Long mentoringId + @RequestBody CheckMentoringRequest mentoringCheckRequest ) { - MentoringCheckResponse response = mentoringCommandService.checkMentoring(siteUserId, mentoringId); + CheckedMentoringsResponse response = mentoringCheckService.checkMentoringsForMentor(siteUserId, mentoringCheckRequest); return ResponseEntity.ok(response); } @@ -76,7 +78,7 @@ public ResponseEntity checkMentoring( public ResponseEntity getUncheckedMentoringsCount( @AuthorizedUser long siteUserId ) { - MentoringCountResponse response = mentoringQueryService.getNewMentoringsCount(siteUserId); + MentoringCountResponse response = mentoringCheckService.getUncheckedMentoringCount(siteUserId); return ResponseEntity.ok(response); } } diff --git a/src/main/java/com/example/solidconnection/mentor/domain/Mentoring.java b/src/main/java/com/example/solidconnection/mentor/domain/Mentoring.java index 47226076d..ead13132b 100644 --- a/src/main/java/com/example/solidconnection/mentor/domain/Mentoring.java +++ b/src/main/java/com/example/solidconnection/mentor/domain/Mentoring.java @@ -40,7 +40,10 @@ public class Mentoring { private ZonedDateTime confirmedAt; @Column - private ZonedDateTime checkedAt; + private ZonedDateTime checkedAtByMentor; + + @Column + private ZonedDateTime checkedAtByMentee; @Column(nullable = false) @Enumerated(EnumType.STRING) @@ -67,12 +70,19 @@ public void confirm(VerifyStatus status) { this.verifyStatus = status; this.confirmedAt = ZonedDateTime.now(UTC).truncatedTo(MICROS); - if (this.checkedAt == null) { - this.checkedAt = this.confirmedAt; + if (this.checkedAtByMentor == null) { + this.checkedAtByMentor = this.confirmedAt; + } + if (this.checkedAtByMentee != null) { + this.checkedAtByMentee = null; } } - public void check() { - this.checkedAt = ZonedDateTime.now(UTC).truncatedTo(MICROS); + public void checkByMentor() { + this.checkedAtByMentor = ZonedDateTime.now(UTC).truncatedTo(MICROS); + } + + public void checkByMentee() { + this.checkedAtByMentee = ZonedDateTime.now(UTC).truncatedTo(MICROS); } } diff --git a/src/main/java/com/example/solidconnection/mentor/dto/CheckMentoringRequest.java b/src/main/java/com/example/solidconnection/mentor/dto/CheckMentoringRequest.java new file mode 100644 index 000000000..ebd3bacf1 --- /dev/null +++ b/src/main/java/com/example/solidconnection/mentor/dto/CheckMentoringRequest.java @@ -0,0 +1,9 @@ +package com.example.solidconnection.mentor.dto; + +import java.util.List; + +public record CheckMentoringRequest( + List checkedMentoringIds +) { + +} diff --git a/src/main/java/com/example/solidconnection/mentor/dto/CheckedMentoringsResponse.java b/src/main/java/com/example/solidconnection/mentor/dto/CheckedMentoringsResponse.java new file mode 100644 index 000000000..2b286543a --- /dev/null +++ b/src/main/java/com/example/solidconnection/mentor/dto/CheckedMentoringsResponse.java @@ -0,0 +1,15 @@ +package com.example.solidconnection.mentor.dto; + +import com.example.solidconnection.mentor.domain.Mentoring; +import java.util.List; + +public record CheckedMentoringsResponse( + List checkedMentoringIds +) { + + public static CheckedMentoringsResponse from(List mentorings) { + return new CheckedMentoringsResponse( + mentorings.stream().map(Mentoring::getId).toList() + ); + } +} diff --git a/src/main/java/com/example/solidconnection/mentor/dto/MentoringResponse.java b/src/main/java/com/example/solidconnection/mentor/dto/MentoringForMenteeResponse.java similarity index 58% rename from src/main/java/com/example/solidconnection/mentor/dto/MentoringResponse.java rename to src/main/java/com/example/solidconnection/mentor/dto/MentoringForMenteeResponse.java index 6b96295ad..7f2591555 100644 --- a/src/main/java/com/example/solidconnection/mentor/dto/MentoringResponse.java +++ b/src/main/java/com/example/solidconnection/mentor/dto/MentoringForMenteeResponse.java @@ -4,7 +4,7 @@ import com.example.solidconnection.siteuser.domain.SiteUser; import java.time.ZonedDateTime; -public record MentoringResponse( +public record MentoringForMenteeResponse( long mentoringId, String profileImageUrl, String nickname, @@ -12,12 +12,12 @@ public record MentoringResponse( ZonedDateTime createdAt ) { - public static MentoringResponse from(Mentoring mentoring, SiteUser mentee) { - return new MentoringResponse( + public static MentoringForMenteeResponse of(Mentoring mentoring, SiteUser partner) { + return new MentoringForMenteeResponse( mentoring.getId(), - mentee.getProfileImageUrl(), - mentee.getNickname(), - mentoring.getCheckedAt() != null, + partner.getProfileImageUrl(), + partner.getNickname(), + mentoring.getCheckedAtByMentee() != null, mentoring.getCreatedAt() ); } diff --git a/src/main/java/com/example/solidconnection/mentor/dto/MentoringForMentorResponse.java b/src/main/java/com/example/solidconnection/mentor/dto/MentoringForMentorResponse.java new file mode 100644 index 000000000..9ee1889f6 --- /dev/null +++ b/src/main/java/com/example/solidconnection/mentor/dto/MentoringForMentorResponse.java @@ -0,0 +1,24 @@ +package com.example.solidconnection.mentor.dto; + +import com.example.solidconnection.mentor.domain.Mentoring; +import com.example.solidconnection.siteuser.domain.SiteUser; +import java.time.ZonedDateTime; + +public record MentoringForMentorResponse( + long mentoringId, + String profileImageUrl, + String nickname, + boolean isChecked, + ZonedDateTime createdAt +) { + + public static MentoringForMentorResponse of(Mentoring mentoring, SiteUser partner) { + return new MentoringForMentorResponse( + mentoring.getId(), + partner.getProfileImageUrl(), + partner.getNickname(), + mentoring.getCheckedAtByMentor() != null, + mentoring.getCreatedAt() + ); + } +} diff --git a/src/main/java/com/example/solidconnection/mentor/dto/MentoringListResponse.java b/src/main/java/com/example/solidconnection/mentor/dto/MentoringListResponse.java deleted file mode 100644 index cca80e06d..000000000 --- a/src/main/java/com/example/solidconnection/mentor/dto/MentoringListResponse.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.example.solidconnection.mentor.dto; - -import java.util.List; - -public record MentoringListResponse( - List requests -) { - - public static MentoringListResponse from(List requests) { - return new MentoringListResponse(requests); - } -} diff --git a/src/main/java/com/example/solidconnection/mentor/repository/MentoringRepository.java b/src/main/java/com/example/solidconnection/mentor/repository/MentoringRepository.java index 8f7cfade3..16caf3318 100644 --- a/src/main/java/com/example/solidconnection/mentor/repository/MentoringRepository.java +++ b/src/main/java/com/example/solidconnection/mentor/repository/MentoringRepository.java @@ -1,18 +1,27 @@ package com.example.solidconnection.mentor.repository; +import com.example.solidconnection.common.VerifyStatus; import com.example.solidconnection.mentor.domain.Mentoring; import java.util.List; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Slice; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; public interface MentoringRepository extends JpaRepository { - int countByMentorIdAndCheckedAtIsNull(long mentorId); + int countByMentorIdAndCheckedAtByMentorIsNull(long mentorId); boolean existsByMentorIdAndMenteeId(long mentorId, long menteeId); - List findAllByMentorId(long mentorId); + Slice findAllByMentorId(long mentorId, Pageable pageable); + + @Query(""" + SELECT m FROM Mentoring m + WHERE m.menteeId = :menteeId AND m.verifyStatus = :verifyStatus + """) + Slice findAllByMenteeIdAndVerifyStatus(@Param("menteeId") long menteeId, @Param("verifyStatus") VerifyStatus verifyStatus, Pageable pageable); @Query(""" SELECT m FROM Mentoring m diff --git a/src/main/java/com/example/solidconnection/mentor/service/MentoringCheckService.java b/src/main/java/com/example/solidconnection/mentor/service/MentoringCheckService.java new file mode 100644 index 000000000..5c73ad00b --- /dev/null +++ b/src/main/java/com/example/solidconnection/mentor/service/MentoringCheckService.java @@ -0,0 +1,74 @@ +package com.example.solidconnection.mentor.service; + +import static com.example.solidconnection.common.exception.ErrorCode.MENTOR_NOT_FOUND; +import static com.example.solidconnection.common.exception.ErrorCode.UNAUTHORIZED_MENTORING; + +import com.example.solidconnection.common.exception.CustomException; +import com.example.solidconnection.mentor.domain.Mentor; +import com.example.solidconnection.mentor.domain.Mentoring; +import com.example.solidconnection.mentor.dto.CheckMentoringRequest; +import com.example.solidconnection.mentor.dto.CheckedMentoringsResponse; +import com.example.solidconnection.mentor.dto.MentoringCountResponse; +import com.example.solidconnection.mentor.repository.MentorRepository; +import com.example.solidconnection.mentor.repository.MentoringRepository; +import java.util.List; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor +public class MentoringCheckService { + + private final MentorRepository mentorRepository; + private final MentoringRepository mentoringRepository; + + @Transactional + public CheckedMentoringsResponse checkMentoringsForMentor(long mentorUserId, CheckMentoringRequest checkMentoringRequest) { + Mentor mentor = mentorRepository.findBySiteUserId(mentorUserId) + .orElseThrow(() -> new CustomException(MENTOR_NOT_FOUND)); + List mentorings = mentoringRepository.findAllById(checkMentoringRequest.checkedMentoringIds()); + List actualMentorIds = mentorings.stream() + .map(Mentoring::getMentorId) + .distinct() + .toList(); + + mentorings.forEach(Mentoring::checkByMentor); + validateMentoringsOwnership(actualMentorIds, mentor.getId()); + + return CheckedMentoringsResponse.from(mentorings); + } + + @Transactional + public CheckedMentoringsResponse checkMentoringsForMentee(long menteeUserId, CheckMentoringRequest checkMentoringRequest) { + List mentorings = mentoringRepository.findAllById(checkMentoringRequest.checkedMentoringIds()); + List actualMenteeIds = mentorings.stream() + .map(Mentoring::getMenteeId) + .distinct() + .toList(); + + validateMentoringsOwnership(actualMenteeIds, menteeUserId); + mentorings.forEach(Mentoring::checkByMentee); + + return CheckedMentoringsResponse.from(mentorings); + } + + private void validateMentoringsOwnership(List actualOwnerIds, long expectedOwnerId) { + actualOwnerIds.stream() + .filter(actualOwnerId -> actualOwnerId != expectedOwnerId) + .findFirst() + .ifPresent(ownerId -> { + throw new CustomException(UNAUTHORIZED_MENTORING); + }); + } + + @Transactional(readOnly = true) + public MentoringCountResponse getUncheckedMentoringCount(long siteUserId) { + Mentor mentor = mentorRepository.findBySiteUserId(siteUserId) + .orElseThrow(() -> new CustomException(MENTOR_NOT_FOUND)); + + int count = mentoringRepository.countByMentorIdAndCheckedAtByMentorIsNull(mentor.getId()); + + return MentoringCountResponse.from(count); + } +} diff --git a/src/main/java/com/example/solidconnection/mentor/service/MentoringCommandService.java b/src/main/java/com/example/solidconnection/mentor/service/MentoringCommandService.java index ca35f6c95..dd4e98936 100644 --- a/src/main/java/com/example/solidconnection/mentor/service/MentoringCommandService.java +++ b/src/main/java/com/example/solidconnection/mentor/service/MentoringCommandService.java @@ -11,7 +11,6 @@ import com.example.solidconnection.mentor.domain.Mentoring; import com.example.solidconnection.mentor.dto.MentoringApplyRequest; import com.example.solidconnection.mentor.dto.MentoringApplyResponse; -import com.example.solidconnection.mentor.dto.MentoringCheckResponse; import com.example.solidconnection.mentor.dto.MentoringConfirmRequest; import com.example.solidconnection.mentor.dto.MentoringConfirmResponse; import com.example.solidconnection.mentor.repository.MentorRepository; @@ -60,21 +59,6 @@ private void validateMentoringNotConfirmed(Mentoring mentoring) { } } - @Transactional - public MentoringCheckResponse checkMentoring(long siteUserId, long mentoringId) { - Mentoring mentoring = mentoringRepository.findById(mentoringId) - .orElseThrow(() -> new CustomException(MENTORING_NOT_FOUND)); - - Mentor mentor = mentorRepository.findBySiteUserId(siteUserId) - .orElseThrow(() -> new CustomException(MENTOR_NOT_FOUND)); - - validateMentoringOwnership(mentor, mentoring); - - mentoring.check(); - - return MentoringCheckResponse.from(mentoring.getId()); - } - // 멘토는 본인의 멘토링에 대해 confirm 및 check해야 한다. private void validateMentoringOwnership(Mentor mentor, Mentoring mentoring) { if (mentoring.getMentorId() != mentor.getId()) { diff --git a/src/main/java/com/example/solidconnection/mentor/service/MentoringQueryService.java b/src/main/java/com/example/solidconnection/mentor/service/MentoringQueryService.java index 2ffa36602..bb9deafe0 100644 --- a/src/main/java/com/example/solidconnection/mentor/service/MentoringQueryService.java +++ b/src/main/java/com/example/solidconnection/mentor/service/MentoringQueryService.java @@ -2,19 +2,27 @@ import static com.example.solidconnection.common.exception.ErrorCode.MENTOR_NOT_FOUND; +import com.example.solidconnection.common.VerifyStatus; +import com.example.solidconnection.common.dto.SliceResponse; import com.example.solidconnection.common.exception.CustomException; import com.example.solidconnection.common.exception.ErrorCode; import com.example.solidconnection.mentor.domain.Mentor; import com.example.solidconnection.mentor.domain.Mentoring; -import com.example.solidconnection.mentor.dto.MentoringCountResponse; -import com.example.solidconnection.mentor.dto.MentoringListResponse; -import com.example.solidconnection.mentor.dto.MentoringResponse; +import com.example.solidconnection.mentor.dto.MentoringForMenteeResponse; +import com.example.solidconnection.mentor.dto.MentoringForMentorResponse; import com.example.solidconnection.mentor.repository.MentorRepository; import com.example.solidconnection.mentor.repository.MentoringRepository; import com.example.solidconnection.siteuser.domain.SiteUser; import com.example.solidconnection.siteuser.repository.SiteUserRepository; +import java.util.ArrayList; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.function.Function; +import java.util.stream.Collectors; 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; @@ -27,30 +35,61 @@ public class MentoringQueryService { private final SiteUserRepository siteUserRepository; @Transactional(readOnly = true) - public MentoringListResponse getMentorings(long siteUserId) { - Mentor mentor = mentorRepository.findBySiteUserId(siteUserId) - .orElseThrow(() -> new CustomException(MENTOR_NOT_FOUND)); + public SliceResponse getMentoringsForMentee( + long siteUserId, VerifyStatus verifyStatus, Pageable pageable + ) { + if (verifyStatus == VerifyStatus.REJECTED) { + throw new CustomException(ErrorCode.UNAUTHORIZED_MENTORING, "거절된 멘토링은 조회할 수 없습니다."); + } + Slice mentoringSlice = mentoringRepository.findAllByMenteeIdAndVerifyStatus(siteUserId, verifyStatus, pageable); + List mentorings = mentoringSlice.toList(); - List mentorings = mentoringRepository.findAllByMentorId(mentor.getId()); - List mentoringResponses = mentorings.stream() - .map(mentoring -> { - SiteUser mentee = siteUserRepository.findById(mentoring.getMenteeId()) - .orElseThrow(() -> new CustomException(ErrorCode.USER_NOT_FOUND)); + Map mentoringToPartnerUser = mapMentoringToPartnerUserWithBatchQuery( + mentorings, Mentoring::getMentorId + ); - return MentoringResponse.from(mentoring, mentee); - }) - .toList(); + List content = new ArrayList<>(); + for (Entry entry : mentoringToPartnerUser.entrySet()) { + content.add(MentoringForMenteeResponse.of(entry.getKey(), entry.getValue())); + } - return MentoringListResponse.from(mentoringResponses); + return SliceResponse.of(content, mentoringSlice); } @Transactional(readOnly = true) - public MentoringCountResponse getNewMentoringsCount(long siteUserId) { + public SliceResponse getMentoringsForMentor(long siteUserId, Pageable pageable) { Mentor mentor = mentorRepository.findBySiteUserId(siteUserId) .orElseThrow(() -> new CustomException(MENTOR_NOT_FOUND)); + Slice mentoringSlice = mentoringRepository.findAllByMentorId(mentor.getId(), pageable); + + Map mentoringToPartnerUser = mapMentoringToPartnerUserWithBatchQuery( + mentoringSlice.toList(), + Mentoring::getMenteeId + ); - int count = mentoringRepository.countByMentorIdAndCheckedAtIsNull(mentor.getId()); + List content = new ArrayList<>(); + for (Entry entry : mentoringToPartnerUser.entrySet()) { + content.add(MentoringForMentorResponse.of(entry.getKey(), entry.getValue())); + } + + return SliceResponse.of(content, mentoringSlice); + } + + // N+1 을 해결하면서 멘토링 상대방의 정보를 조회 + private Map mapMentoringToPartnerUserWithBatchQuery( + List mentorings, Function getPartnerId + ) { + List partnerUserId = mentorings.stream() + .map(getPartnerId) + .distinct() + .toList(); + List partnerUsers = siteUserRepository.findAllById(partnerUserId); + Map partnerIdToPartnerUsermap = partnerUsers.stream() + .collect(Collectors.toMap(SiteUser::getId, Function.identity())); - return MentoringCountResponse.from(count); + return mentorings.stream().collect(Collectors.toMap( + Function.identity(), + mentoring -> partnerIdToPartnerUsermap.get(getPartnerId.apply(mentoring)) + )); } } diff --git a/src/main/resources/db/migration/V27__add_checked_at_by_mentee_column.sql b/src/main/resources/db/migration/V27__add_checked_at_by_mentee_column.sql new file mode 100644 index 000000000..41e1ad637 --- /dev/null +++ b/src/main/resources/db/migration/V27__add_checked_at_by_mentee_column.sql @@ -0,0 +1,5 @@ +ALTER TABLE mentoring + RENAME COLUMN checked_at TO checked_at_by_mentor; + +ALTER TABLE mentoring + ADD COLUMN checked_at_by_mentee DATETIME(6) NULL; diff --git a/src/test/java/com/example/solidconnection/mentor/fixture/MentoringFixture.java b/src/test/java/com/example/solidconnection/mentor/fixture/MentoringFixture.java index 07925628e..4779c643e 100644 --- a/src/test/java/com/example/solidconnection/mentor/fixture/MentoringFixture.java +++ b/src/test/java/com/example/solidconnection/mentor/fixture/MentoringFixture.java @@ -29,7 +29,7 @@ public class MentoringFixture { .menteeId(menteeId) .verifyStatus(VerifyStatus.APPROVED) .confirmedAt(now) - .checkedAt(now) + .checkedAtByMentor(now) .create(); } @@ -40,7 +40,7 @@ public class MentoringFixture { .menteeId(menteeId) .verifyStatus(VerifyStatus.REJECTED) .confirmedAt(now) - .checkedAt(now) + .checkedAtByMentor(now) .create(); } @@ -48,7 +48,7 @@ public class MentoringFixture { return mentoringFixtureBuilder.mentoring() .mentorId(mentorId) .menteeId(menteeId) - .checkedAt(null) + .checkedAtByMentor(null) .create(); } diff --git a/src/test/java/com/example/solidconnection/mentor/fixture/MentoringFixtureBuilder.java b/src/test/java/com/example/solidconnection/mentor/fixture/MentoringFixtureBuilder.java index 857c18ea8..f4e905b3a 100644 --- a/src/test/java/com/example/solidconnection/mentor/fixture/MentoringFixtureBuilder.java +++ b/src/test/java/com/example/solidconnection/mentor/fixture/MentoringFixtureBuilder.java @@ -15,7 +15,8 @@ public class MentoringFixtureBuilder { private ZonedDateTime createdAt; private ZonedDateTime confirmedAt; - private ZonedDateTime checkedAt; + private ZonedDateTime checkedAtByMentor; + private ZonedDateTime checkedAtByMentee; private VerifyStatus verifyStatus = VerifyStatus.PENDING; private long mentorId; private long menteeId; @@ -34,8 +35,13 @@ public MentoringFixtureBuilder confirmedAt(ZonedDateTime confirmedAt) { return this; } - public MentoringFixtureBuilder checkedAt(ZonedDateTime checkedAt) { - this.checkedAt = checkedAt; + public MentoringFixtureBuilder checkedAtByMentor(ZonedDateTime checkedAtByMentor) { + this.checkedAtByMentor = checkedAtByMentor; + return this; + } + + public MentoringFixtureBuilder checkedAtByMentee(ZonedDateTime checkedAtByMentor) { + this.checkedAtByMentor = checkedAtByMentor; return this; } @@ -59,7 +65,8 @@ public Mentoring create() { null, createdAt, confirmedAt, - checkedAt, + checkedAtByMentor, + checkedAtByMentee, verifyStatus, mentorId, menteeId diff --git a/src/test/java/com/example/solidconnection/mentor/service/MentoringCheckServiceTest.java b/src/test/java/com/example/solidconnection/mentor/service/MentoringCheckServiceTest.java new file mode 100644 index 000000000..c5f8a9463 --- /dev/null +++ b/src/test/java/com/example/solidconnection/mentor/service/MentoringCheckServiceTest.java @@ -0,0 +1,171 @@ +package com.example.solidconnection.mentor.service; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.junit.jupiter.api.Assertions.assertAll; + +import com.example.solidconnection.common.exception.CustomException; +import com.example.solidconnection.common.exception.ErrorCode; +import com.example.solidconnection.mentor.domain.Mentor; +import com.example.solidconnection.mentor.domain.Mentoring; +import com.example.solidconnection.mentor.dto.CheckMentoringRequest; +import com.example.solidconnection.mentor.dto.CheckedMentoringsResponse; +import com.example.solidconnection.mentor.dto.MentoringCountResponse; +import com.example.solidconnection.mentor.fixture.MentorFixture; +import com.example.solidconnection.mentor.fixture.MentoringFixture; +import com.example.solidconnection.mentor.repository.MentoringRepository; +import com.example.solidconnection.siteuser.domain.SiteUser; +import com.example.solidconnection.siteuser.fixture.SiteUserFixture; +import com.example.solidconnection.support.TestContainerSpringBootTest; +import java.util.List; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +@TestContainerSpringBootTest +@DisplayName("멘토링 확인 서비스 테스트") +class MentoringCheckServiceTest { + + @Autowired + private MentoringRepository mentoringRepository; + + @Autowired + private MentoringCheckService mentoringCheckService; + + @Autowired + private MentoringFixture mentoringFixture; + + @Autowired + private SiteUserFixture siteUserFixture; + + @Autowired + private MentorFixture mentorFixture; + + + private SiteUser mentorUser1, mentorUser2; + private SiteUser menteeUser1, menteeUser2, menteeUser3; + private Mentor mentor1, mentor2, mentor3; + + @BeforeEach + void setUp() { + mentorUser1 = siteUserFixture.멘토(1, "mentor1"); + mentorUser2 = siteUserFixture.멘토(2, "mentor2"); + SiteUser mentorUser3 = siteUserFixture.멘토(3, "mentor3"); + menteeUser1 = siteUserFixture.사용자(1, "mentee1"); + menteeUser2 = siteUserFixture.사용자(2, "mentee2"); + menteeUser3 = siteUserFixture.사용자(3, "mentee3"); + mentor1 = mentorFixture.멘토(mentorUser1.getId(), 1L); + mentor2 = mentorFixture.멘토(mentorUser2.getId(), 1L); + mentor3 = mentorFixture.멘토(mentorUser3.getId(), 1L); + } + + @Nested + class 멘토의_멘토링_확인_테스트 { + + @Test + void 멘토가_멘토링을_확인한다() { + // given + Mentoring mentoring1 = mentoringFixture.확인되지_않은_멘토링(mentor1.getId(), menteeUser1.getId()); + Mentoring mentoring2 = mentoringFixture.확인되지_않은_멘토링(mentor1.getId(), menteeUser2.getId()); + Mentoring mentoring3 = mentoringFixture.확인되지_않은_멘토링(mentor1.getId(), menteeUser3.getId()); + CheckMentoringRequest request = new CheckMentoringRequest(List.of(mentoring1.getId(), mentoring2.getId())); + + // when + CheckedMentoringsResponse response = mentoringCheckService.checkMentoringsForMentor(mentorUser1.getId(), request); + + // then + assertAll( + () -> assertThat(response.checkedMentoringIds()).containsExactlyInAnyOrder(mentoring1.getId(), mentoring2.getId()), + () -> assertThat(mentoringRepository.findById(mentoring1.getId())) + .hasValueSatisfying(mentoring -> assertThat(mentoring.getCheckedAtByMentor()).isNotNull()), + () -> assertThat(mentoringRepository.findById(mentoring2.getId())) + .hasValueSatisfying(mentoring -> assertThat(mentoring.getCheckedAtByMentor()).isNotNull()), + () -> assertThat(mentoringRepository.findById(mentoring3.getId())) + .hasValueSatisfying(mentoring -> assertThat(mentoring.getCheckedAtByMentor()).isNull()) + ); + } + + @Test + void 다른_멘토의_멘토링은_확인하면_예외가_발생한다() { + // given + Mentoring mentoring2 = mentoringFixture.확인되지_않은_멘토링(mentor2.getId(), menteeUser2.getId()); + CheckMentoringRequest request = new CheckMentoringRequest(List.of(mentoring2.getId())); + + // when, then + assertThatCode(() -> mentoringCheckService.checkMentoringsForMentor(mentorUser1.getId(), request)) + .isInstanceOf(CustomException.class) + .hasMessageContaining(ErrorCode.UNAUTHORIZED_MENTORING.getMessage()); + } + } + + @Nested + class 멘티의_멘토링_확인_테스트 { + + @Test + void 멘티가_멘토링을_확인한다() { + // given + Mentoring mentoring1 = mentoringFixture.확인되지_않은_멘토링(mentor1.getId(), menteeUser1.getId()); + Mentoring mentoring2 = mentoringFixture.확인되지_않은_멘토링(mentor2.getId(), menteeUser1.getId()); + Mentoring mentoring3 = mentoringFixture.확인되지_않은_멘토링(mentor3.getId(), menteeUser1.getId()); + CheckMentoringRequest request = new CheckMentoringRequest(List.of(mentoring1.getId(), mentoring2.getId())); + + // when + CheckedMentoringsResponse response = mentoringCheckService.checkMentoringsForMentee(menteeUser1.getId(), request); + + // then + assertAll( + () -> assertThat(response.checkedMentoringIds()).containsExactlyInAnyOrder(mentoring1.getId(), mentoring2.getId()), + () -> assertThat(mentoringRepository.findById(mentoring1.getId())) + .hasValueSatisfying(mentoring -> assertThat(mentoring.getCheckedAtByMentee()).isNotNull()), + () -> assertThat(mentoringRepository.findById(mentoring2.getId())) + .hasValueSatisfying(mentoring -> assertThat(mentoring.getCheckedAtByMentee()).isNotNull()), + () -> assertThat(mentoringRepository.findById(mentoring3.getId())) + .hasValueSatisfying(mentoring -> assertThat(mentoring.getCheckedAtByMentee()).isNull()) + ); + } + + @Test + void 다른_멘티의_멘토링을_확인하면_예외가_발생한다() { + // given + Mentoring mentoring2 = mentoringFixture.확인되지_않은_멘토링(mentor2.getId(), menteeUser2.getId()); + CheckMentoringRequest request = new CheckMentoringRequest(List.of(mentoring2.getId())); + + // when, then + assertThatCode(() -> mentoringCheckService.checkMentoringsForMentee(menteeUser1.getId(), request)) + .isInstanceOf(CustomException.class) + .hasMessageContaining(ErrorCode.UNAUTHORIZED_MENTORING.getMessage()); + } + + @Nested + class 멘토가_확인하지_않은_멘토링_개수_조회_테스트 { + + @Test + void 멘토가_확인하지_않은_멘토링_개수를_반환한다() { + // given + mentoringFixture.확인되지_않은_멘토링(mentor1.getId(), menteeUser1.getId()); + mentoringFixture.확인되지_않은_멘토링(mentor1.getId(), menteeUser2.getId()); + mentoringFixture.승인된_멘토링(mentor1.getId(), menteeUser3.getId()); + + // when + MentoringCountResponse response = mentoringCheckService.getUncheckedMentoringCount(mentorUser1.getId()); + + // then + assertThat(response.uncheckedCount()).isEqualTo(2); + } + + @Test + void 멘토가_확인하지_않은_멘토링이_없으면_0을_반환한다() { + // given + mentoringFixture.승인된_멘토링(mentor1.getId(), menteeUser1.getId()); + + // when + MentoringCountResponse response = mentoringCheckService.getUncheckedMentoringCount(mentorUser1.getId()); + + // then + assertThat(response.uncheckedCount()).isZero(); + } + } + } +} diff --git a/src/test/java/com/example/solidconnection/mentor/service/MentoringCommandServiceTest.java b/src/test/java/com/example/solidconnection/mentor/service/MentoringCommandServiceTest.java index a7cea53bb..a92925653 100644 --- a/src/test/java/com/example/solidconnection/mentor/service/MentoringCommandServiceTest.java +++ b/src/test/java/com/example/solidconnection/mentor/service/MentoringCommandServiceTest.java @@ -13,7 +13,6 @@ import com.example.solidconnection.mentor.domain.Mentoring; import com.example.solidconnection.mentor.dto.MentoringApplyRequest; import com.example.solidconnection.mentor.dto.MentoringApplyResponse; -import com.example.solidconnection.mentor.dto.MentoringCheckResponse; import com.example.solidconnection.mentor.dto.MentoringConfirmRequest; import com.example.solidconnection.mentor.dto.MentoringConfirmResponse; import com.example.solidconnection.mentor.fixture.MentorFixture; @@ -110,7 +109,8 @@ class 멘토링_승인_거절_테스트 { assertAll( () -> assertThat(confirmedMentoring.getVerifyStatus()).isEqualTo(VerifyStatus.APPROVED), () -> assertThat(confirmedMentoring.getConfirmedAt()).isNotNull(), - () -> assertThat(confirmedMentoring.getCheckedAt()).isNotNull(), + () -> assertThat(confirmedMentoring.getCheckedAtByMentor()).isNotNull(), + () -> assertThat(confirmedMentoring.getCheckedAtByMentee()).isNull(), () -> assertThat(mentor.getMenteeCount()).isEqualTo(beforeMenteeCount + 1) ); } @@ -132,7 +132,7 @@ class 멘토링_승인_거절_테스트 { assertAll( () -> assertThat(confirmedMentoring.getVerifyStatus()).isEqualTo(VerifyStatus.REJECTED), () -> assertThat(confirmedMentoring.getConfirmedAt()).isNotNull(), - () -> assertThat(confirmedMentoring.getCheckedAt()).isNotNull(), + () -> assertThat(confirmedMentoring.getCheckedAtByMentor()).isNotNull(), () -> assertThat(mentor.getMenteeCount()).isEqualTo(beforeMenteeCount) ); } @@ -173,44 +173,4 @@ class 멘토링_승인_거절_테스트 { .hasMessage(MENTORING_NOT_FOUND.getMessage()); } } - - @Nested - class 멘토링_확인_테스트 { - - @Test - void 멘토링을_성공적으로_확인_처리한다() { - // given - Mentoring mentoring = mentoringFixture.확인되지_않은_멘토링(mentor1.getId(), menteeUser.getId()); - - // when - MentoringCheckResponse response = mentoringCommandService.checkMentoring(mentorUser1.getId(), mentoring.getId()); - - // then - Mentoring checked = mentoringRepository.findById(response.mentoringId()).orElseThrow(); - - assertThat(checked.getCheckedAt()).isNotNull(); - } - - @Test - void 다른_멘토의_멘토링은_확인할_수_없다() { - // given - Mentoring mentoring = mentoringFixture.확인되지_않은_멘토링(mentor1.getId(), menteeUser.getId()); - - // when & then - assertThatThrownBy(() -> mentoringCommandService.checkMentoring(mentorUser2.getId(), mentoring.getId())) - .isInstanceOf(CustomException.class) - .hasMessage(UNAUTHORIZED_MENTORING.getMessage()); - } - - @Test - void 존재하지_않는_멘토링_아이디로_요청시_예외가_발생한다() { - // given - long invalidMentoringId = 9999L; - - // when & then - assertThatThrownBy(() -> mentoringCommandService.checkMentoring(mentorUser1.getId(), invalidMentoringId)) - .isInstanceOf(CustomException.class) - .hasMessage(MENTORING_NOT_FOUND.getMessage()); - } - } } diff --git a/src/test/java/com/example/solidconnection/mentor/service/MentoringQueryServiceTest.java b/src/test/java/com/example/solidconnection/mentor/service/MentoringQueryServiceTest.java index 6e61a4a7a..d8146dc51 100644 --- a/src/test/java/com/example/solidconnection/mentor/service/MentoringQueryServiceTest.java +++ b/src/test/java/com/example/solidconnection/mentor/service/MentoringQueryServiceTest.java @@ -1,15 +1,20 @@ package com.example.solidconnection.mentor.service; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertAll; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.assertj.core.api.AssertionsForClassTypes.tuple; +import com.example.solidconnection.common.VerifyStatus; +import com.example.solidconnection.common.dto.SliceResponse; +import com.example.solidconnection.common.exception.CustomException; +import com.example.solidconnection.common.exception.ErrorCode; import com.example.solidconnection.mentor.domain.Mentor; import com.example.solidconnection.mentor.domain.Mentoring; -import com.example.solidconnection.mentor.dto.MentoringCountResponse; -import com.example.solidconnection.mentor.dto.MentoringListResponse; -import com.example.solidconnection.mentor.dto.MentoringResponse; +import com.example.solidconnection.mentor.dto.MentoringForMenteeResponse; +import com.example.solidconnection.mentor.dto.MentoringForMentorResponse; import com.example.solidconnection.mentor.fixture.MentorFixture; import com.example.solidconnection.mentor.fixture.MentoringFixture; +import com.example.solidconnection.mentor.repository.MentoringRepository; import com.example.solidconnection.siteuser.domain.SiteUser; import com.example.solidconnection.siteuser.fixture.SiteUserFixture; import com.example.solidconnection.support.TestContainerSpringBootTest; @@ -18,6 +23,8 @@ import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; @TestContainerSpringBootTest @DisplayName("멘토링 조회 서비스 테스트") @@ -35,79 +42,194 @@ class MentoringQueryServiceTest { @Autowired private MentoringFixture mentoringFixture; - private SiteUser mentorUser; - private SiteUser menteeUser; - private Mentor mentor; + @Autowired + private MentoringRepository mentoringRepository; + + private SiteUser mentorUser1, mentorUser2; + private SiteUser menteeUser1, menteeUser2, menteeUser3; + private Mentor mentor1, mentor2, mentor3; + private Pageable pageable; @BeforeEach void setUp() { - mentorUser = siteUserFixture.멘토(1, "mentor1"); - menteeUser = siteUserFixture.사용자(2, "mentee1"); - mentor = mentorFixture.멘토(mentorUser.getId(), 1L); + mentorUser1 = siteUserFixture.멘토(1, "mentor1"); + mentorUser2 = siteUserFixture.멘토(2, "mentor2"); + SiteUser mentorUser3 = siteUserFixture.멘토(3, "mentor3"); + menteeUser1 = siteUserFixture.사용자(1, "mentee1"); + menteeUser2 = siteUserFixture.사용자(2, "mentee2"); + menteeUser3 = siteUserFixture.사용자(3, "mentee3"); + mentor1 = mentorFixture.멘토(mentorUser1.getId(), 1L); + mentor2 = mentorFixture.멘토(mentorUser2.getId(), 1L); + mentor3 = mentorFixture.멘토(mentorUser3.getId(), 1L); + pageable = PageRequest.of(0, 3); } @Nested - class 멘토링_목록_조회_테스트 { + class 멘토의_멘토링_목록_조회_테스트 { + + @Test + void 모든_상태의_멘토링_목록을_조회한다() { + // given + Mentoring mentoring1 = mentoringFixture.대기중_멘토링(mentor1.getId(), menteeUser1.getId()); + Mentoring mentoring2 = mentoringFixture.승인된_멘토링(mentor1.getId(), menteeUser2.getId()); + Mentoring mentoring3 = mentoringFixture.거절된_멘토링(mentor1.getId(), menteeUser3.getId()); + + // when + SliceResponse response = mentoringQueryService.getMentoringsForMentor(mentorUser1.getId(), pageable); + + // then + assertThat(response.content()).extracting(MentoringForMentorResponse::mentoringId) + .containsExactlyInAnyOrder( + mentoring1.getId(), + mentoring2.getId(), + mentoring3.getId() + ); + } @Test - void 멘토의_모든_멘토링을_조회한다() { + void 멘토링_상대의_정보를_포함한다() { // given - Mentoring mentoring1 = mentoringFixture.대기중_멘토링(mentor.getId(), menteeUser.getId()); - Mentoring mentoring2 = mentoringFixture.승인된_멘토링(mentor.getId(), menteeUser.getId()); - Mentoring mentoring3 = mentoringFixture.거절된_멘토링(mentor.getId(), menteeUser.getId()); + mentoringFixture.대기중_멘토링(mentor1.getId(), menteeUser1.getId()); + mentoringFixture.승인된_멘토링(mentor1.getId(), menteeUser2.getId()); // when - MentoringListResponse responses = mentoringQueryService.getMentorings(mentorUser.getId()); + SliceResponse response = mentoringQueryService.getMentoringsForMentor(mentorUser1.getId(), pageable); // then - assertAll( - () -> assertThat(responses.requests()).hasSize(3), - () -> assertThat(responses.requests()).extracting(MentoringResponse::mentoringId) - .containsExactlyInAnyOrder( - mentoring1.getId(), - mentoring2.getId(), - mentoring3.getId() - ) - ); + assertThat(response.content()).extracting(MentoringForMentorResponse::nickname) + .containsExactlyInAnyOrder( + menteeUser1.getNickname(), + menteeUser2.getNickname() + ); + } + + @Test + void 멘토링_확인_여부를_포함한다() { + // given + Mentoring mentoring1 = mentoringFixture.대기중_멘토링(mentor1.getId(), menteeUser1.getId()); + Mentoring mentoring2 = mentoringFixture.승인된_멘토링(mentor1.getId(), menteeUser2.getId()); + + // when + SliceResponse response = mentoringQueryService.getMentoringsForMentor(mentorUser1.getId(), pageable); + + // then + assertThat(response.content()) + .extracting(MentoringForMentorResponse::mentoringId, MentoringForMentorResponse::isChecked) + .containsExactlyInAnyOrder( + tuple(mentoring1.getId(), false), + tuple(mentoring2.getId(), true) + ); } @Test void 멘토링이_없는_경우_빈_리스트를_반환한다() { // when - MentoringListResponse responses = mentoringQueryService.getMentorings(mentorUser.getId()); + SliceResponse response = mentoringQueryService.getMentoringsForMentor(mentorUser1.getId(), pageable); // then - assertThat(responses.requests()).isEmpty(); + assertThat(response.content()).isEmpty(); } } @Nested - class 새_멘토링_개수_조회_테스트 { + class 멘티의_멘토링_목록_조회_테스트 { + + @Test + void 거절된_멘토링_목록을_조회하면_예외가_발생한다() { + // given + mentoringFixture.거절된_멘토링(mentor1.getId(), menteeUser1.getId()); + + // when & then + assertThatCode(() -> mentoringQueryService.getMentoringsForMentee(menteeUser1.getId(), VerifyStatus.REJECTED, pageable)) + .isInstanceOf(CustomException.class) + .hasMessageContaining(ErrorCode.UNAUTHORIZED_MENTORING.getMessage()); + } @Test - void 확인되지_않은_멘토링_개수를_반환한다() { + void 승인된_멘토링_목록을_조회한다() { // given - mentoringFixture.확인되지_않은_멘토링(mentor.getId(), menteeUser.getId()); - mentoringFixture.확인되지_않은_멘토링(mentor.getId(), menteeUser.getId()); - mentoringFixture.승인된_멘토링(mentor.getId(), menteeUser.getId()); + Mentoring mentoring1 = mentoringFixture.승인된_멘토링(mentor1.getId(), menteeUser1.getId()); + Mentoring mentoring2 = mentoringFixture.승인된_멘토링(mentor2.getId(), menteeUser1.getId()); + mentoringFixture.대기중_멘토링(mentor3.getId(), menteeUser1.getId()); // when - MentoringCountResponse response = mentoringQueryService.getNewMentoringsCount(mentorUser.getId()); + SliceResponse response = mentoringQueryService.getMentoringsForMentee( + menteeUser1.getId(), VerifyStatus.APPROVED, pageable); // then - assertThat(response.uncheckedCount()).isEqualTo(2); + assertThat(response.content()).extracting(MentoringForMenteeResponse::mentoringId) + .containsExactlyInAnyOrder( + mentoring1.getId(), + mentoring2.getId() + ); } @Test - void 확인되지_않은_멘토링이_없으면_0을_반환한다() { + void 대기중인_멘토링_목록을_조회한다() { // given - mentoringFixture.승인된_멘토링(mentor.getId(), menteeUser.getId()); + Mentoring mentoring1 = mentoringFixture.대기중_멘토링(mentor1.getId(), menteeUser1.getId()); + Mentoring mentoring2 = mentoringFixture.대기중_멘토링(mentor2.getId(), menteeUser1.getId()); + mentoringFixture.승인된_멘토링(mentor3.getId(), menteeUser1.getId()); // when - MentoringCountResponse response = mentoringQueryService.getNewMentoringsCount(mentorUser.getId()); + SliceResponse response = mentoringQueryService.getMentoringsForMentee( + menteeUser1.getId(), VerifyStatus.PENDING, pageable); + + // then + assertThat(response.content()).extracting(MentoringForMenteeResponse::mentoringId) + .containsExactlyInAnyOrder( + mentoring1.getId(), + mentoring2.getId() + ); + } + + @Test + void 멘토링_상대의_정보를_포함한다() { + // given + mentoringFixture.승인된_멘토링(mentor1.getId(), menteeUser1.getId()); + mentoringFixture.승인된_멘토링(mentor2.getId(), menteeUser1.getId()); + + // when + SliceResponse response = mentoringQueryService.getMentoringsForMentee( + menteeUser1.getId(), VerifyStatus.APPROVED, pageable); + + // then + assertThat(response.content()).extracting(MentoringForMenteeResponse::nickname) + .containsExactlyInAnyOrder( + mentorUser1.getNickname(), + mentorUser2.getNickname() + ); + } + + @Test + void 멘토링_확인_여부를_포함한다() { + // given + Mentoring mentoring1 = mentoringFixture.대기중_멘토링(mentor1.getId(), menteeUser1.getId()); + Mentoring mentoring2 = mentoringFixture.대기중_멘토링(mentor2.getId(), menteeUser1.getId()); + mentoring1.checkByMentee(); + mentoringRepository.save(mentoring1); + + // when + SliceResponse response = mentoringQueryService.getMentoringsForMentee( + menteeUser1.getId(), VerifyStatus.PENDING, pageable); + + // then + assertThat(response.content()) + .extracting(MentoringForMenteeResponse::mentoringId, MentoringForMenteeResponse::isChecked) + .containsExactlyInAnyOrder( + tuple(mentoring1.getId(), true), + tuple(mentoring2.getId(), false) + ); + } + + @Test + void 멘토링이_없는_경우_빈_리스트를_반환한다() { + // when + SliceResponse response = mentoringQueryService.getMentoringsForMentee( + mentorUser1.getId(), VerifyStatus.APPROVED, pageable); // then - assertThat(response.uncheckedCount()).isZero(); + assertThat(response.content()).isEmpty(); } } }