-
Notifications
You must be signed in to change notification settings - Fork 8
feat: 멘토링 관련 도메인 추가 #362
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: 멘토링 관련 도메인 추가 #362
Changes from all commits
8e1431c
8877521
6e299a3
03c79e3
e30dd3b
37c7bf6
95df8a3
11d1b32
77896f1
e049bbb
564135a
c0c96b2
c4de140
21198fd
b8c9e9c
52f21d0
a897b0e
b4a2cc5
36723f7
91a1784
f88a75d
045bd50
ceac93e
d7e81e4
6783242
020f1cb
adc7121
deb9ff2
04a3288
a8be7a6
10f44bc
d059e93
0cf6c20
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| package com.example.solidconnection.mentor.controller; | ||
|
|
||
| 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.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.service.MentoringCommandService; | ||
| import com.example.solidconnection.mentor.service.MentoringQueryService; | ||
| import com.example.solidconnection.security.annotation.RequireRoleAccess; | ||
| import com.example.solidconnection.siteuser.domain.Role; | ||
| import com.example.solidconnection.siteuser.domain.SiteUser; | ||
| import jakarta.validation.Valid; | ||
| import lombok.RequiredArgsConstructor; | ||
| 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 { | ||
|
|
||
| private final MentoringCommandService mentoringCommandService; | ||
| private final MentoringQueryService mentoringQueryService; | ||
|
|
||
| @RequireRoleAccess(roles = Role.MENTEE) | ||
| @PostMapping("/apply") | ||
| public ResponseEntity<MentoringApplyResponse> applyMentoring( | ||
| @AuthorizedUser SiteUser siteUser, | ||
| @Valid @RequestBody MentoringApplyRequest mentoringApplyRequest | ||
| ) { | ||
| MentoringApplyResponse response = mentoringCommandService.applyMentoring(siteUser.getId(), mentoringApplyRequest); | ||
| return ResponseEntity.ok(response); | ||
| } | ||
|
|
||
| @RequireRoleAccess(roles = {Role.ADMIN, Role.MENTOR}) | ||
| @GetMapping("/apply") | ||
| public ResponseEntity<MentoringListResponse> getMentorings( | ||
| @AuthorizedUser SiteUser siteUser | ||
| ) { | ||
| MentoringListResponse responses = mentoringQueryService.getMentorings(siteUser.getId()); | ||
| return ResponseEntity.ok(responses); | ||
| } | ||
|
|
||
| @RequireRoleAccess(roles = {Role.ADMIN, Role.MENTOR}) | ||
| @PatchMapping("/{mentoring-id}/apply") | ||
| public ResponseEntity<MentoringConfirmResponse> confirmMentoring( | ||
| @AuthorizedUser SiteUser siteUser, | ||
| @PathVariable("mentoring-id") Long mentoringId, | ||
| @Valid @RequestBody MentoringConfirmRequest mentoringConfirmRequest | ||
| ) { | ||
| MentoringConfirmResponse response = mentoringCommandService.confirmMentoring(siteUser.getId(), mentoringId, mentoringConfirmRequest); | ||
| return ResponseEntity.ok(response); | ||
| } | ||
|
|
||
| @RequireRoleAccess(roles = {Role.ADMIN, Role.MENTOR}) | ||
| @PatchMapping("/{mentoring-id}/check") | ||
| public ResponseEntity<MentoringCheckResponse> checkMentoring( | ||
| @AuthorizedUser SiteUser siteUser, | ||
| @PathVariable("mentoring-id") Long mentoringId | ||
| ) { | ||
| MentoringCheckResponse response = mentoringCommandService.checkMentoring(siteUser.getId(), mentoringId); | ||
| return ResponseEntity.ok(response); | ||
| } | ||
|
|
||
| @RequireRoleAccess(roles = {Role.ADMIN, Role.MENTOR}) | ||
| @GetMapping("/check") | ||
| public ResponseEntity<MentoringCountResponse> getUncheckedMentoringsCount( | ||
| @AuthorizedUser SiteUser siteUser | ||
| ) { | ||
| MentoringCountResponse response = mentoringQueryService.getNewMentoringsCount(siteUser.getId()); | ||
| return ResponseEntity.ok(response); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| package com.example.solidconnection.mentor.dto; | ||
|
|
||
| import jakarta.validation.constraints.NotNull; | ||
|
|
||
| public record MentoringApplyRequest( | ||
| @NotNull(message = "멘토 id를 입력해주세요.") | ||
| Long mentorId | ||
| ) { | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| package com.example.solidconnection.mentor.dto; | ||
|
|
||
| import com.example.solidconnection.mentor.domain.Mentoring; | ||
|
|
||
| public record MentoringApplyResponse( | ||
| long mentoringId | ||
| ) { | ||
|
|
||
whqtker marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| public static MentoringApplyResponse from(Mentoring mentoring) { | ||
| return new MentoringApplyResponse(mentoring.getId()); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| package com.example.solidconnection.mentor.dto; | ||
|
|
||
| public record MentoringCheckResponse( | ||
| long mentoringId | ||
| ) { | ||
|
|
||
| public static MentoringCheckResponse from(long mentoringId) { | ||
| return new MentoringCheckResponse(mentoringId); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| package com.example.solidconnection.mentor.dto; | ||
|
|
||
| import com.example.solidconnection.common.VerifyStatus; | ||
| import jakarta.validation.constraints.NotNull; | ||
|
|
||
| public record MentoringConfirmRequest( | ||
| @NotNull(message = "승인 상태를 설정해주세요.") | ||
| VerifyStatus status, | ||
|
|
||
| String rejectedReason | ||
whqtker marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ) { | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| package com.example.solidconnection.mentor.dto; | ||
|
|
||
| import com.example.solidconnection.mentor.domain.Mentoring; | ||
|
|
||
| public record MentoringConfirmResponse( | ||
| long mentoringId | ||
| ) { | ||
| public static MentoringConfirmResponse from(Mentoring mentoring) { | ||
whqtker marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return new MentoringConfirmResponse(mentoring.getId()); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| package com.example.solidconnection.mentor.dto; | ||
|
|
||
| public record MentoringCountResponse( | ||
| int uncheckedCount | ||
| ) { | ||
|
|
||
| public static MentoringCountResponse from(int uncheckedCount) { | ||
| return new MentoringCountResponse(uncheckedCount); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| package com.example.solidconnection.mentor.dto; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| public record MentoringListResponse( | ||
| List<MentoringResponse> requests | ||
| ) { | ||
| public static MentoringListResponse from(List<MentoringResponse> requests) { | ||
| return new MentoringListResponse(requests); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 MentoringResponse( | ||
| long mentoringId, | ||
| String profileImageUrl, | ||
| String nickname, | ||
| boolean isChecked, | ||
| ZonedDateTime createdAt | ||
| ) { | ||
| public static MentoringResponse from(Mentoring mentoring, SiteUser mentee) { | ||
| return new MentoringResponse( | ||
| mentoring.getId(), | ||
| mentee.getProfileImageUrl(), | ||
| mentee.getNickname(), | ||
| mentoring.getCheckedAt() != null, | ||
| mentoring.getCreatedAt() | ||
| ); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| package com.example.solidconnection.mentor.repository; | ||
|
|
||
| import com.example.solidconnection.mentor.domain.Mentor; | ||
| import org.springframework.data.jpa.repository.JpaRepository; | ||
|
|
||
| import java.util.Optional; | ||
|
|
||
| public interface MentorRepository extends JpaRepository<Mentor, Long> { | ||
|
|
||
| Optional<Mentor> findBySiteUserId(long siteUserId); | ||
|
|
||
| boolean existsBySiteUserId(long siteUserId); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| package com.example.solidconnection.mentor.repository; | ||
|
|
||
| import com.example.solidconnection.mentor.domain.Mentoring; | ||
| import org.springframework.data.jpa.repository.JpaRepository; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| public interface MentoringRepository extends JpaRepository<Mentoring, Long> { | ||
|
|
||
| List<Mentoring> findAllByMentorId(long mentorId); | ||
|
|
||
| int countByMentorIdAndCheckedAtIsNull(long mentorId); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| package com.example.solidconnection.mentor.service; | ||
|
|
||
| import com.example.solidconnection.common.VerifyStatus; | ||
| 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.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; | ||
| import com.example.solidconnection.mentor.repository.MentoringRepository; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.springframework.stereotype.Service; | ||
| import org.springframework.transaction.annotation.Transactional; | ||
|
|
||
| import static com.example.solidconnection.common.exception.ErrorCode.MENTORING_ALREADY_CONFIRMED; | ||
| import static com.example.solidconnection.common.exception.ErrorCode.MENTORING_NOT_FOUND; | ||
| import static com.example.solidconnection.common.exception.ErrorCode.MENTOR_NOT_FOUND; | ||
| import static com.example.solidconnection.common.exception.ErrorCode.REJECTED_REASON_REQUIRED; | ||
| import static com.example.solidconnection.common.exception.ErrorCode.UNAUTHORIZED_MENTORING; | ||
|
|
||
| @Service | ||
| @RequiredArgsConstructor | ||
| public class MentoringCommandService { | ||
|
|
||
| private final MentoringRepository mentoringRepository; | ||
| private final MentorRepository mentorRepository; | ||
|
|
||
| @Transactional | ||
| public MentoringApplyResponse applyMentoring(long siteUserId, MentoringApplyRequest mentoringApplyRequest) { | ||
| Mentoring mentoring = new Mentoring(mentoringApplyRequest.mentorId(), siteUserId, VerifyStatus.PENDING); | ||
|
|
||
| return MentoringApplyResponse.from(mentoringRepository.save(mentoring)); | ||
| } | ||
|
|
||
| @Transactional | ||
| public MentoringConfirmResponse confirmMentoring(long siteUserId, long mentoringId, MentoringConfirmRequest mentoringConfirmRequest) { | ||
| 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); | ||
| validateMentoringNotConfirmed(mentoring); | ||
|
|
||
| if (mentoringConfirmRequest.status() == VerifyStatus.REJECTED | ||
| && (mentoringConfirmRequest.rejectedReason() == null || mentoringConfirmRequest.rejectedReason().isBlank())) { | ||
| throw new CustomException(REJECTED_REASON_REQUIRED); | ||
| } | ||
|
Comment on lines
+49
to
+52
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이건 도메인 생성자에서 검증하기로 하지 않았나요?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 논의되기 전에 작성한 내용이라 남아 있는 것 같습니다 ㅠㅠ 음 .. 그냥 이 PR에서 적용시킬까요 ?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 다른 곳도 고쳐야하니 새 pr에서 해도 좋은 거 같아요 전! |
||
|
|
||
| mentoring.confirm(mentoringConfirmRequest.status(), mentoringConfirmRequest.rejectedReason()); | ||
|
|
||
| if (mentoringConfirmRequest.status() == VerifyStatus.APPROVED) { | ||
| mentor.increaseMenteeCount(); | ||
| } | ||
|
|
||
| return MentoringConfirmResponse.from(mentoring); | ||
| } | ||
|
|
||
| private void validateMentoringNotConfirmed(Mentoring mentoring) { | ||
| if (mentoring.getVerifyStatus() != VerifyStatus.PENDING) { | ||
| throw new CustomException(MENTORING_ALREADY_CONFIRMED); | ||
| } | ||
| } | ||
|
|
||
| @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()) { | ||
| throw new CustomException(UNAUTHORIZED_MENTORING); | ||
| } | ||
| } | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.