diff --git a/src/main/java/com/postgraduate/domain/auth/application/dto/req/KakaoLoginRequest.java b/src/main/java/com/postgraduate/domain/auth/application/dto/req/KakaoCodeRequest.java similarity index 52% rename from src/main/java/com/postgraduate/domain/auth/application/dto/req/KakaoLoginRequest.java rename to src/main/java/com/postgraduate/domain/auth/application/dto/req/KakaoCodeRequest.java index 4378ccc5..c14ffcfb 100644 --- a/src/main/java/com/postgraduate/domain/auth/application/dto/req/KakaoLoginRequest.java +++ b/src/main/java/com/postgraduate/domain/auth/application/dto/req/KakaoCodeRequest.java @@ -1,14 +1,12 @@ package com.postgraduate.domain.auth.application.dto.req; import jakarta.validation.constraints.NotNull; -import lombok.AllArgsConstructor; -import lombok.Getter; -import lombok.NoArgsConstructor; +import lombok.*; -@Getter @AllArgsConstructor @NoArgsConstructor -public class KakaoLoginRequest { +@Getter +public class KakaoCodeRequest { @NotNull - private String accessToken; + private String code; } diff --git a/src/main/java/com/postgraduate/domain/auth/application/dto/res/KakaoTokenInfoResponse.java b/src/main/java/com/postgraduate/domain/auth/application/dto/res/KakaoTokenInfoResponse.java new file mode 100644 index 00000000..8636b00e --- /dev/null +++ b/src/main/java/com/postgraduate/domain/auth/application/dto/res/KakaoTokenInfoResponse.java @@ -0,0 +1,20 @@ +package com.postgraduate.domain.auth.application.dto.res; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Builder +@Getter +@AllArgsConstructor +@NoArgsConstructor +public class KakaoTokenInfoResponse { + private String access_token; + private String token_type; + private String refresh_token; + private String id_token; + private int expires_in; + private String cope; + private int refresh_token_expires_in; +} diff --git a/src/main/java/com/postgraduate/domain/auth/application/usecase/kakao/KakaoAccessTokenUseCase.java b/src/main/java/com/postgraduate/domain/auth/application/usecase/kakao/KakaoAccessTokenUseCase.java index 05ac257a..aa826d8b 100644 --- a/src/main/java/com/postgraduate/domain/auth/application/usecase/kakao/KakaoAccessTokenUseCase.java +++ b/src/main/java/com/postgraduate/domain/auth/application/usecase/kakao/KakaoAccessTokenUseCase.java @@ -1,10 +1,14 @@ package com.postgraduate.domain.auth.application.usecase.kakao; import com.postgraduate.domain.auth.application.dto.res.KakaoAccessTokenResponse; +import com.postgraduate.domain.auth.application.dto.res.KakaoTokenInfoResponse; import com.postgraduate.domain.auth.application.dto.res.KakaoUserInfoResponse; import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.MediaType; import org.springframework.stereotype.Service; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; import org.springframework.web.reactive.function.client.WebClient; @RequiredArgsConstructor @@ -13,13 +17,38 @@ public class KakaoAccessTokenUseCase { @Value("${app-id.kakao}") private String APP_ID; + @Value("${kakao.redirect-uri}") + private String REDRECT_URI; + @Value("${kakao.authorization-grant-type}") + private String AUTHORIZATION_GRANT_TYPE; private final WebClient webClient; + + private static final String KAKAO_TOKEN_URI = "https://kauth.kakao.com/oauth/token"; private static final String USER_INFO_URI = "https://kapi.kakao.com/v2/user/me"; private static final String VALIDATE_TOKEN_URI = "https://kapi.kakao.com/v1/user/access_token_info"; + public KakaoUserInfoResponse getKakaoToken(String code) { + MultiValueMap requestBody = getRequestBody(code); + KakaoTokenInfoResponse tokenInfoResponse = webClient.post() + .uri(KAKAO_TOKEN_URI) + .headers(h -> h.setContentType(MediaType.APPLICATION_FORM_URLENCODED)) + .bodyValue(requestBody) + .retrieve() + .bodyToMono(KakaoTokenInfoResponse.class) + .block(); + return getUserInfo(tokenInfoResponse.getAccess_token()); + } - public KakaoUserInfoResponse getUserInfo(String accessToken) { + private MultiValueMap getRequestBody(String code) { + MultiValueMap requestBody = new LinkedMultiValueMap<>(); + requestBody.add("grant_type", AUTHORIZATION_GRANT_TYPE); + requestBody.add("client_id", APP_ID); + requestBody.add("redirect_uri", REDRECT_URI); + requestBody.add("code", code); + return requestBody; + } + private KakaoUserInfoResponse getUserInfo(String accessToken) { verifyAccessToken(accessToken); return webClient.get() diff --git a/src/main/java/com/postgraduate/domain/auth/application/usecase/kakao/KakaoSignInUseCase.java b/src/main/java/com/postgraduate/domain/auth/application/usecase/kakao/KakaoSignInUseCase.java index e8e4f548..f70772d5 100644 --- a/src/main/java/com/postgraduate/domain/auth/application/usecase/kakao/KakaoSignInUseCase.java +++ b/src/main/java/com/postgraduate/domain/auth/application/usecase/kakao/KakaoSignInUseCase.java @@ -1,5 +1,6 @@ package com.postgraduate.domain.auth.application.usecase.kakao; +import com.postgraduate.domain.auth.application.dto.req.KakaoCodeRequest; import com.postgraduate.domain.auth.application.dto.res.AuthUserResponse; import com.postgraduate.domain.auth.application.dto.res.KakaoUserInfoResponse; import com.postgraduate.domain.auth.application.dto.req.SignUpRequest; @@ -22,8 +23,8 @@ public class KakaoSignInUseCase { private final UserGetService userGetService; @Transactional - public AuthUserResponse getUser(String token) { - KakaoUserInfoResponse userInfo = kakaoTokenUseCase.getUserInfo(token); + public AuthUserResponse getUser(KakaoCodeRequest codeRequest) { + KakaoUserInfoResponse userInfo = kakaoTokenUseCase.getKakaoToken(codeRequest.getCode()); Long socialId = userInfo.getId(); Optional user = userGetService.bySocialId(socialId); return AuthMapper.mapToAuthUser(user, socialId); diff --git a/src/main/java/com/postgraduate/domain/auth/exception/AuthException.java b/src/main/java/com/postgraduate/domain/auth/exception/AuthException.java new file mode 100644 index 00000000..4cea29c2 --- /dev/null +++ b/src/main/java/com/postgraduate/domain/auth/exception/AuthException.java @@ -0,0 +1,9 @@ +package com.postgraduate.domain.auth.exception; + +import com.postgraduate.global.exception.ApplicationException; + +public class AuthException extends ApplicationException { + protected AuthException(String message, String errorCode) { + super(message, errorCode); + } +} diff --git a/src/main/java/com/postgraduate/domain/auth/exception/PermissionDeniedException.java b/src/main/java/com/postgraduate/domain/auth/exception/PermissionDeniedException.java new file mode 100644 index 00000000..330088f3 --- /dev/null +++ b/src/main/java/com/postgraduate/domain/auth/exception/PermissionDeniedException.java @@ -0,0 +1,12 @@ +package com.postgraduate.domain.auth.exception; + +import static com.postgraduate.domain.auth.presentation.contant.AuthResponseCode.AUTH_NONE; +import static com.postgraduate.domain.auth.presentation.contant.AuthResponseMessage.PERMISSION_DENIED_MESSAGE; + + +public class PermissionDeniedException extends AuthException { + + public PermissionDeniedException() { + super(PERMISSION_DENIED_MESSAGE.getMessage(), AUTH_NONE.getCode()); + } +} diff --git a/src/main/java/com/postgraduate/domain/auth/presentation/AuthController.java b/src/main/java/com/postgraduate/domain/auth/presentation/AuthController.java index ed62a293..74eb0a7a 100644 --- a/src/main/java/com/postgraduate/domain/auth/presentation/AuthController.java +++ b/src/main/java/com/postgraduate/domain/auth/presentation/AuthController.java @@ -1,6 +1,6 @@ package com.postgraduate.domain.auth.presentation; -import com.postgraduate.domain.auth.application.dto.req.KakaoLoginRequest; +import com.postgraduate.domain.auth.application.dto.req.KakaoCodeRequest; import com.postgraduate.domain.auth.application.dto.req.SignUpRequest; import com.postgraduate.domain.auth.application.dto.res.AuthUserResponse; import com.postgraduate.domain.auth.application.dto.res.JwtTokenResponse; @@ -32,11 +32,10 @@ public class AuthController { @PostMapping("/login") @Operation(summary = "카카오 로그인", description = "회원인 경우 JWT를, 회원이 아닌 경우 socialId를 반환합니다(회원가입은 진행하지 않습니다).") - public ResponseDto authLogin(@RequestBody KakaoLoginRequest request) { - AuthUserResponse authUser = kakaoSignInUseCase.getUser(request.getAccessToken()); + public ResponseDto authLogin(@RequestBody KakaoCodeRequest tokenRequest) { + AuthUserResponse authUser = kakaoSignInUseCase.getUser(tokenRequest); if (authUser.getUser().isEmpty()) return ResponseDto.create(AUTH_NONE.getCode(), NOT_REGISTERED_USER_MESSAGE.getMessage(), authUser); - JwtTokenResponse jwtToken = jwtUseCase.signIn(authUser.getUser().get()); return ResponseDto.create(AUTH_ALREADY.getCode(), SUCCESS_AUTH_MESSAGE.getMessage(), jwtToken); } diff --git a/src/main/java/com/postgraduate/domain/auth/presentation/contant/AuthResponseMessage.java b/src/main/java/com/postgraduate/domain/auth/presentation/contant/AuthResponseMessage.java index b73f7894..bb6f8186 100644 --- a/src/main/java/com/postgraduate/domain/auth/presentation/contant/AuthResponseMessage.java +++ b/src/main/java/com/postgraduate/domain/auth/presentation/contant/AuthResponseMessage.java @@ -8,6 +8,8 @@ public enum AuthResponseMessage { SUCCESS_AUTH_MESSAGE("사용자 인증에 성공하였습니다."), NOT_REGISTERED_USER_MESSAGE("가입하지 않은 유저입니다."), - SUCCESS_REGENERATE_TOKEN_MESSAGE("토큰 재발급에 성공하였습니다."); + SUCCESS_REGENERATE_TOKEN_MESSAGE("토큰 재발급에 성공하였습니다."), + + PERMISSION_DENIED_MESSAGE("권한이 없습니다."); private final String message; } diff --git a/src/main/java/com/postgraduate/domain/mentoring/application/dto/req/MentoringApplyRequest.java b/src/main/java/com/postgraduate/domain/mentoring/application/dto/req/MentoringApplyRequest.java new file mode 100644 index 00000000..686c3ec2 --- /dev/null +++ b/src/main/java/com/postgraduate/domain/mentoring/application/dto/req/MentoringApplyRequest.java @@ -0,0 +1,20 @@ +package com.postgraduate.domain.mentoring.application.dto.req; + +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@AllArgsConstructor +@NoArgsConstructor +public class MentoringApplyRequest { + @NotNull + private Long seniorId; + @NotNull + private String topic; + @NotNull + private String question; + @NotNull + private String date; +} diff --git a/src/main/java/com/postgraduate/domain/mentoring/application/dto/req/MentoringStatusRequest.java b/src/main/java/com/postgraduate/domain/mentoring/application/dto/req/MentoringStatusRequest.java new file mode 100644 index 00000000..a2c6e5d3 --- /dev/null +++ b/src/main/java/com/postgraduate/domain/mentoring/application/dto/req/MentoringStatusRequest.java @@ -0,0 +1,15 @@ +package com.postgraduate.domain.mentoring.application.dto.req; + +import com.postgraduate.domain.mentoring.domain.entity.constant.Status; +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@AllArgsConstructor +@NoArgsConstructor +public class MentoringStatusRequest { + @NotNull + private Status status; +} diff --git a/src/main/java/com/postgraduate/domain/mentoring/application/dto/AppliedMentoringDetailResponse.java b/src/main/java/com/postgraduate/domain/mentoring/application/dto/res/AppliedMentoringDetailResponse.java similarity index 85% rename from src/main/java/com/postgraduate/domain/mentoring/application/dto/AppliedMentoringDetailResponse.java rename to src/main/java/com/postgraduate/domain/mentoring/application/dto/res/AppliedMentoringDetailResponse.java index 9c09ff81..8c4c712a 100644 --- a/src/main/java/com/postgraduate/domain/mentoring/application/dto/AppliedMentoringDetailResponse.java +++ b/src/main/java/com/postgraduate/domain/mentoring/application/dto/res/AppliedMentoringDetailResponse.java @@ -1,4 +1,4 @@ -package com.postgraduate.domain.mentoring.application.dto; +package com.postgraduate.domain.mentoring.application.dto.res; import lombok.AllArgsConstructor; import lombok.Builder; diff --git a/src/main/java/com/postgraduate/domain/mentoring/application/dto/AppliedMentoringResponse.java b/src/main/java/com/postgraduate/domain/mentoring/application/dto/res/AppliedMentoringResponse.java similarity index 62% rename from src/main/java/com/postgraduate/domain/mentoring/application/dto/AppliedMentoringResponse.java rename to src/main/java/com/postgraduate/domain/mentoring/application/dto/res/AppliedMentoringResponse.java index 7d1982cf..fed717fd 100644 --- a/src/main/java/com/postgraduate/domain/mentoring/application/dto/AppliedMentoringResponse.java +++ b/src/main/java/com/postgraduate/domain/mentoring/application/dto/res/AppliedMentoringResponse.java @@ -1,5 +1,6 @@ -package com.postgraduate.domain.mentoring.application.dto; +package com.postgraduate.domain.mentoring.application.dto.res; +import com.postgraduate.domain.mentoring.application.dto.AppliedMentoringInfo; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Getter; diff --git a/src/main/java/com/postgraduate/domain/mentoring/application/mapper/MentoringMapper.java b/src/main/java/com/postgraduate/domain/mentoring/application/mapper/MentoringMapper.java index 01deb768..dfd688d5 100644 --- a/src/main/java/com/postgraduate/domain/mentoring/application/mapper/MentoringMapper.java +++ b/src/main/java/com/postgraduate/domain/mentoring/application/mapper/MentoringMapper.java @@ -1,9 +1,11 @@ package com.postgraduate.domain.mentoring.application.mapper; -import com.postgraduate.domain.mentoring.application.dto.AppliedMentoringDetailResponse; import com.postgraduate.domain.mentoring.application.dto.AppliedMentoringInfo; +import com.postgraduate.domain.mentoring.application.dto.req.MentoringApplyRequest; +import com.postgraduate.domain.mentoring.application.dto.res.AppliedMentoringDetailResponse; import com.postgraduate.domain.mentoring.domain.entity.Mentoring; import com.postgraduate.domain.senior.domain.entity.Senior; +import com.postgraduate.domain.user.domain.entity.User; import java.util.List; import java.util.stream.Stream; @@ -51,4 +53,14 @@ public static AppliedMentoringDetailResponse mapToAppliedDetailInfo(Mentoring me .dates(dates) .build(); } + + public static Mentoring mapToMentoring(User user, Senior senior, MentoringApplyRequest request) { + return Mentoring.builder() + .user(user) + .senior(senior) + .topic(request.getTopic()) + .question(request.getQuestion()) + .date(request.getDate()) + .build(); + } } diff --git a/src/main/java/com/postgraduate/domain/mentoring/application/usecase/CheckIsMyMentoringUseCase.java b/src/main/java/com/postgraduate/domain/mentoring/application/usecase/CheckIsMyMentoringUseCase.java new file mode 100644 index 00000000..671c8729 --- /dev/null +++ b/src/main/java/com/postgraduate/domain/mentoring/application/usecase/CheckIsMyMentoringUseCase.java @@ -0,0 +1,33 @@ +package com.postgraduate.domain.mentoring.application.usecase; + +import com.postgraduate.domain.auth.exception.PermissionDeniedException; +import com.postgraduate.domain.mentoring.domain.entity.Mentoring; +import com.postgraduate.domain.mentoring.domain.service.MentoringGetService; +import com.postgraduate.domain.senior.domain.entity.Senior; +import com.postgraduate.domain.user.domain.entity.User; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional +@RequiredArgsConstructor +public class CheckIsMyMentoringUseCase { + private final MentoringGetService mentoringGetService; + public Mentoring checkByRole(User user, Long mentoringId) { + Mentoring mentoring = mentoringGetService.byMentoringId(mentoringId); + if (mentoring.getUser() != user) { + throw new PermissionDeniedException(); + } + return mentoring; + } + + public Mentoring checkByRole(Senior senior, Long mentoringId) { + Mentoring mentoring = mentoringGetService.byMentoringId(mentoringId); + if (mentoring.getSenior() != senior) { + throw new PermissionDeniedException(); + } + return mentoring; + } +} + diff --git a/src/main/java/com/postgraduate/domain/mentoring/application/usecase/MentoringApplyUseCase.java b/src/main/java/com/postgraduate/domain/mentoring/application/usecase/MentoringApplyUseCase.java new file mode 100644 index 00000000..cb6bb8e9 --- /dev/null +++ b/src/main/java/com/postgraduate/domain/mentoring/application/usecase/MentoringApplyUseCase.java @@ -0,0 +1,30 @@ +package com.postgraduate.domain.mentoring.application.usecase; + +import com.postgraduate.domain.mentoring.application.dto.req.MentoringApplyRequest; +import com.postgraduate.domain.mentoring.application.mapper.MentoringMapper; +import com.postgraduate.domain.mentoring.domain.entity.Mentoring; +import com.postgraduate.domain.mentoring.domain.service.MentoringSaveService; +import com.postgraduate.domain.senior.domain.entity.Senior; +import com.postgraduate.domain.senior.domain.service.SeniorGetService; +import com.postgraduate.domain.user.domain.entity.User; +import com.postgraduate.global.auth.AuthDetails; +import com.postgraduate.global.config.security.util.SecurityUtils; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional +@RequiredArgsConstructor +public class MentoringApplyUseCase { + private final SecurityUtils securityUtils; + private final MentoringSaveService mentoringSaveService; + private final SeniorGetService seniorGetService; + + public void applyMentoring(AuthDetails authDetails, MentoringApplyRequest request) { + User user = securityUtils.getLoggedInUser(authDetails); + Senior senior = seniorGetService.bySeniorId(request.getSeniorId()); + Mentoring mentoring = MentoringMapper.mapToMentoring(user, senior, request); + mentoringSaveService.save(mentoring); + } +} diff --git a/src/main/java/com/postgraduate/domain/mentoring/application/usecase/MentoringInfoUseCase.java b/src/main/java/com/postgraduate/domain/mentoring/application/usecase/MentoringInfoUseCase.java index fa59aa12..9d0e457d 100644 --- a/src/main/java/com/postgraduate/domain/mentoring/application/usecase/MentoringInfoUseCase.java +++ b/src/main/java/com/postgraduate/domain/mentoring/application/usecase/MentoringInfoUseCase.java @@ -1,7 +1,7 @@ package com.postgraduate.domain.mentoring.application.usecase; -import com.postgraduate.domain.mentoring.application.dto.AppliedMentoringDetailResponse; -import com.postgraduate.domain.mentoring.application.dto.AppliedMentoringResponse; +import com.postgraduate.domain.mentoring.application.dto.res.AppliedMentoringDetailResponse; +import com.postgraduate.domain.mentoring.application.dto.res.AppliedMentoringResponse; import com.postgraduate.domain.mentoring.application.dto.AppliedMentoringInfo; import com.postgraduate.domain.mentoring.application.mapper.MentoringMapper; import com.postgraduate.domain.mentoring.domain.entity.Mentoring; @@ -22,11 +22,11 @@ @RequiredArgsConstructor public class MentoringInfoUseCase { private final MentoringGetService mentoringGetService; - + private final CheckIsMyMentoringUseCase checkIsMyMentoringUseCase; + private final SecurityUtils securityUtils; /** * securityUtils 이후 수정 */ - private final SecurityUtils securityUtils; public AppliedMentoringResponse getMentorings(Status status, AuthDetails authDetails) { User user = securityUtils.getLoggedInUser(authDetails); @@ -55,9 +55,9 @@ private AppliedMentoringResponse getCategories(Status status, List me } } - public AppliedMentoringDetailResponse getMentoringDetail(Long mentoringId) { - Mentoring mentoring = mentoringGetService.mentoringDetail(mentoringId); - AppliedMentoringDetailResponse appliedMentoringDetailResponse = MentoringMapper.mapToAppliedDetailInfo(mentoring); - return appliedMentoringDetailResponse; + public AppliedMentoringDetailResponse getMentoringDetail(AuthDetails authDetails, Long mentoringId) { + User user = securityUtils.getLoggedInUser(authDetails); + Mentoring mentoring = checkIsMyMentoringUseCase.checkByRole(user, mentoringId); + return MentoringMapper.mapToAppliedDetailInfo(mentoring); } } diff --git a/src/main/java/com/postgraduate/domain/mentoring/application/usecase/MentoringManageUseCase.java b/src/main/java/com/postgraduate/domain/mentoring/application/usecase/MentoringManageUseCase.java new file mode 100644 index 00000000..ac2383ec --- /dev/null +++ b/src/main/java/com/postgraduate/domain/mentoring/application/usecase/MentoringManageUseCase.java @@ -0,0 +1,26 @@ +package com.postgraduate.domain.mentoring.application.usecase; + +import com.postgraduate.domain.mentoring.application.dto.req.MentoringStatusRequest; +import com.postgraduate.domain.mentoring.domain.entity.Mentoring; +import com.postgraduate.domain.mentoring.domain.service.MentoringUpdateService; +import com.postgraduate.domain.user.domain.entity.User; +import com.postgraduate.global.auth.AuthDetails; +import com.postgraduate.global.config.security.util.SecurityUtils; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional +@RequiredArgsConstructor +public class MentoringManageUseCase { + private final SecurityUtils securityUtils; + private final MentoringUpdateService mentoringUpdateService; + private final CheckIsMyMentoringUseCase checkIsMyMentoringUseCase; + + public void updateStatus(AuthDetails authDetails, Long mentoringId, MentoringStatusRequest request) { + User user = securityUtils.getLoggedInUser(authDetails); + Mentoring mentoring = checkIsMyMentoringUseCase.checkByRole(user, mentoringId); + mentoringUpdateService.updateStatus(mentoring, request.getStatus()); + } +} diff --git a/src/main/java/com/postgraduate/domain/mentoring/domain/entity/Mentoring.java b/src/main/java/com/postgraduate/domain/mentoring/domain/entity/Mentoring.java index da6c978c..28a795f6 100644 --- a/src/main/java/com/postgraduate/domain/mentoring/domain/entity/Mentoring.java +++ b/src/main/java/com/postgraduate/domain/mentoring/domain/entity/Mentoring.java @@ -8,6 +8,7 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import org.hibernate.annotations.ColumnDefault; import org.hibernate.annotations.CreationTimestamp; import java.time.LocalDate; @@ -38,13 +39,23 @@ public class Mentoring { private String date; @Column(nullable = false) - private int pay; + @Builder.Default + private int pay = 20000; @Enumerated(EnumType.STRING) - private Status status; + @Builder.Default + private Status status = Status.WAITING; @CreationTimestamp private LocalDate createdAt; private LocalDate deletedAt; + + public void updateStatus(Status status) { + this.status = status; + } + + public void updateDeletedAt() { + this.deletedAt = LocalDate.now(); + } } diff --git a/src/main/java/com/postgraduate/domain/mentoring/domain/repository/MentoringRepository.java b/src/main/java/com/postgraduate/domain/mentoring/domain/repository/MentoringRepository.java index b5f2bfb8..dc839f7a 100644 --- a/src/main/java/com/postgraduate/domain/mentoring/domain/repository/MentoringRepository.java +++ b/src/main/java/com/postgraduate/domain/mentoring/domain/repository/MentoringRepository.java @@ -9,5 +9,6 @@ import java.util.Optional; public interface MentoringRepository extends JpaRepository { - Optional> findAllByUserAndStatus(User user, Status status); + Optional findByMentoringIdAndDeletedAtIsNull(Long mentoringId); + Optional> findAllByUserAndStatusAndDeletedAtIsNull(User user, Status status); } diff --git a/src/main/java/com/postgraduate/domain/mentoring/domain/service/MentoringGetService.java b/src/main/java/com/postgraduate/domain/mentoring/domain/service/MentoringGetService.java index ff96c290..efabf8c0 100644 --- a/src/main/java/com/postgraduate/domain/mentoring/domain/service/MentoringGetService.java +++ b/src/main/java/com/postgraduate/domain/mentoring/domain/service/MentoringGetService.java @@ -3,6 +3,7 @@ import com.postgraduate.domain.mentoring.domain.entity.Mentoring; import com.postgraduate.domain.mentoring.domain.entity.constant.Status; import com.postgraduate.domain.mentoring.domain.repository.MentoringRepository; +import com.postgraduate.domain.mentoring.exception.MentoringNotFoundException; import com.postgraduate.domain.user.domain.entity.User; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -16,12 +17,10 @@ public class MentoringGetService { private final MentoringRepository mentoringRepository; public List mentoringByUser(User user, Status status) { - List mentorings = - mentoringRepository.findAllByUserAndStatus(user, status).orElse(new ArrayList<>()); - return mentorings; + return mentoringRepository.findAllByUserAndStatusAndDeletedAtIsNull(user, status).orElse(new ArrayList<>()); } - public Mentoring mentoringDetail(Long mentoringId) { - return mentoringRepository.findById(mentoringId).orElseThrow(); + public Mentoring byMentoringId(Long mentoringId) { + return mentoringRepository.findByMentoringIdAndDeletedAtIsNull(mentoringId).orElseThrow(MentoringNotFoundException::new); } } diff --git a/src/main/java/com/postgraduate/domain/mentoring/domain/service/MentoringSaveService.java b/src/main/java/com/postgraduate/domain/mentoring/domain/service/MentoringSaveService.java new file mode 100644 index 00000000..b8ac6ad0 --- /dev/null +++ b/src/main/java/com/postgraduate/domain/mentoring/domain/service/MentoringSaveService.java @@ -0,0 +1,16 @@ +package com.postgraduate.domain.mentoring.domain.service; + +import com.postgraduate.domain.mentoring.domain.entity.Mentoring; +import com.postgraduate.domain.mentoring.domain.repository.MentoringRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class MentoringSaveService { + private final MentoringRepository mentoringRepository; + + public Mentoring save(Mentoring mentoring) { + return mentoringRepository.save(mentoring); + } +} diff --git a/src/main/java/com/postgraduate/domain/mentoring/domain/service/MentoringUpdateService.java b/src/main/java/com/postgraduate/domain/mentoring/domain/service/MentoringUpdateService.java new file mode 100644 index 00000000..2574b069 --- /dev/null +++ b/src/main/java/com/postgraduate/domain/mentoring/domain/service/MentoringUpdateService.java @@ -0,0 +1,18 @@ +package com.postgraduate.domain.mentoring.domain.service; + +import com.postgraduate.domain.mentoring.domain.entity.Mentoring; +import com.postgraduate.domain.mentoring.domain.entity.constant.Status; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +@Service +@RequiredArgsConstructor +public class MentoringUpdateService { + + public void updateStatus(Mentoring mentoring, Status status) { + if (status.equals(Status.CANCEL)) { + mentoring.updateDeletedAt(); + } + mentoring.updateStatus(status); + } +} diff --git a/src/main/java/com/postgraduate/domain/mentoring/exception/MentoringException.java b/src/main/java/com/postgraduate/domain/mentoring/exception/MentoringException.java new file mode 100644 index 00000000..416e89e3 --- /dev/null +++ b/src/main/java/com/postgraduate/domain/mentoring/exception/MentoringException.java @@ -0,0 +1,9 @@ +package com.postgraduate.domain.mentoring.exception; + +import com.postgraduate.global.exception.ApplicationException; + +public class MentoringException extends ApplicationException { + protected MentoringException(String message, String errorCode) { + super(message, errorCode); + } +} diff --git a/src/main/java/com/postgraduate/domain/mentoring/exception/MentoringNotFoundException.java b/src/main/java/com/postgraduate/domain/mentoring/exception/MentoringNotFoundException.java new file mode 100644 index 00000000..d5e08bf7 --- /dev/null +++ b/src/main/java/com/postgraduate/domain/mentoring/exception/MentoringNotFoundException.java @@ -0,0 +1,12 @@ +package com.postgraduate.domain.mentoring.exception; + +import static com.postgraduate.domain.mentoring.presentation.constant.MentoringResponseCode.MENTORING_NOT_FOUND; +import static com.postgraduate.domain.mentoring.presentation.constant.MentoringResponseMessage.NOT_FOUND_MENTORING; + + +public class MentoringNotFoundException extends MentoringException { + + public MentoringNotFoundException() { + super(NOT_FOUND_MENTORING.getMessage(), MENTORING_NOT_FOUND.getCode()); + } +} diff --git a/src/main/java/com/postgraduate/domain/mentoring/presentation/MentoringController.java b/src/main/java/com/postgraduate/domain/mentoring/presentation/MentoringController.java index 6a814102..8587b4c7 100644 --- a/src/main/java/com/postgraduate/domain/mentoring/presentation/MentoringController.java +++ b/src/main/java/com/postgraduate/domain/mentoring/presentation/MentoringController.java @@ -1,10 +1,13 @@ package com.postgraduate.domain.mentoring.presentation; -import com.postgraduate.domain.mentoring.application.dto.AppliedMentoringDetailResponse; -import com.postgraduate.domain.mentoring.application.dto.AppliedMentoringResponse; +import com.postgraduate.domain.mentoring.application.dto.req.MentoringApplyRequest; +import com.postgraduate.domain.mentoring.application.dto.req.MentoringStatusRequest; +import com.postgraduate.domain.mentoring.application.dto.res.AppliedMentoringDetailResponse; +import com.postgraduate.domain.mentoring.application.dto.res.AppliedMentoringResponse; +import com.postgraduate.domain.mentoring.application.usecase.MentoringApplyUseCase; import com.postgraduate.domain.mentoring.application.usecase.MentoringInfoUseCase; +import com.postgraduate.domain.mentoring.application.usecase.MentoringManageUseCase; import com.postgraduate.domain.mentoring.domain.entity.constant.Status; -import com.postgraduate.domain.mentoring.presentation.constant.MentoringResponseCode; import com.postgraduate.global.auth.AuthDetails; import com.postgraduate.global.dto.ResponseDto; import io.swagger.v3.oas.annotations.Operation; @@ -13,10 +16,8 @@ import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; -import static com.postgraduate.domain.mentoring.presentation.constant.MentoringResponseCode.MENTORING_FIND; -import static com.postgraduate.domain.mentoring.presentation.constant.MentoringResponseMessage.GET_MENTORING_DETAIL_INFO; -import static com.postgraduate.domain.mentoring.presentation.constant.MentoringResponseMessage.GET_MENTORING_LIST_INFO; -import static org.springframework.http.HttpStatus.OK; +import static com.postgraduate.domain.mentoring.presentation.constant.MentoringResponseCode.*; +import static com.postgraduate.domain.mentoring.presentation.constant.MentoringResponseMessage.*; @RestController @RequiredArgsConstructor @@ -24,18 +25,36 @@ @Tag(name = "MENTORING Controller") public class MentoringController { private final MentoringInfoUseCase infoUsecase; + private final MentoringApplyUseCase applyUseCase; + private final MentoringManageUseCase updateUseCase; @GetMapping("/me") - @Operation(description = "대학생 신청 멘토링 조회") + @Operation(summary = "[대학생] 신청한 멘토링 목록 조회", description = "대학생이 신청한 멘토링 목록을 조회합니다.") public ResponseDto getMentoringInfos(@RequestParam Status status, @AuthenticationPrincipal AuthDetails authDetails) { AppliedMentoringResponse mentoringResponse = infoUsecase.getMentorings(status, authDetails); return ResponseDto.create(MENTORING_FIND.getCode(), GET_MENTORING_LIST_INFO.getMessage(), mentoringResponse); } @GetMapping("/me/{mentoringId}") - @Operation(description = "대학생 신청 멘토링 상세조회") - public ResponseDto getMentoringDetail(@PathVariable Long mentoringId) { - AppliedMentoringDetailResponse mentoringDetail = infoUsecase.getMentoringDetail(mentoringId); + @Operation(summary = "[대학생] 신청한 멘토링 상세조회", description = "대학생이 신청한 멘토링을 상세조회합니다.") + public ResponseDto getMentoringDetail(@AuthenticationPrincipal AuthDetails authDetails, @PathVariable Long mentoringId) { + AppliedMentoringDetailResponse mentoringDetail = infoUsecase.getMentoringDetail(authDetails, mentoringId); return ResponseDto.create(MENTORING_FIND.getCode(), GET_MENTORING_DETAIL_INFO.getMessage(), mentoringDetail); } + + @PostMapping() + @Operation(summary = "[대학생] 멘토링 신청", description = "대학생이 멘토링을 신청합니다.") + public ResponseDto applyMentoring(@AuthenticationPrincipal AuthDetails authDetails, @RequestBody MentoringApplyRequest request) { + applyUseCase.applyMentoring(authDetails, request); + return ResponseDto.create(MENTORING_CREATE.getCode(), CREATE_MENTORING.getMessage()); + } + + @PatchMapping("/me/{mentoringId}") + @Operation(summary = "[대학생] 멘토링 상태 업데이트", description = "대학생이 멘토링 상태를 변경합니다.") + public ResponseDto updateMentoringStatus(@AuthenticationPrincipal AuthDetails authDetails, + @PathVariable Long mentoringId, + @RequestBody MentoringStatusRequest request) { + updateUseCase.updateStatus(authDetails, mentoringId, request); + return ResponseDto.create(MENTORING_UPDATE.getCode(), UPDATE_MENTORING.getMessage()); + } } diff --git a/src/main/java/com/postgraduate/domain/mentoring/presentation/constant/MentoringResponseCode.java b/src/main/java/com/postgraduate/domain/mentoring/presentation/constant/MentoringResponseCode.java index d845fabf..87f176d7 100644 --- a/src/main/java/com/postgraduate/domain/mentoring/presentation/constant/MentoringResponseCode.java +++ b/src/main/java/com/postgraduate/domain/mentoring/presentation/constant/MentoringResponseCode.java @@ -9,6 +9,9 @@ public enum MentoringResponseCode { MENTORING_FIND("MT200"), MENTORING_UPDATE("MT201"), MENTORING_CREATE("MT202"), - MENTORING_DELETE("MT203"); + MENTORING_DELETE("MT203"), + + MENTORING_NOT_FOUND("MT400") + ; private final String code; } \ No newline at end of file diff --git a/src/main/java/com/postgraduate/domain/mentoring/presentation/constant/MentoringResponseMessage.java b/src/main/java/com/postgraduate/domain/mentoring/presentation/constant/MentoringResponseMessage.java index de7cbf73..034b83ff 100644 --- a/src/main/java/com/postgraduate/domain/mentoring/presentation/constant/MentoringResponseMessage.java +++ b/src/main/java/com/postgraduate/domain/mentoring/presentation/constant/MentoringResponseMessage.java @@ -7,7 +7,11 @@ @RequiredArgsConstructor public enum MentoringResponseMessage { GET_MENTORING_LIST_INFO("멘토링 리스트 조회에 성공하였습니다."), - GET_MENTORING_DETAIL_INFO("멘토링 상세 조회에 성공하였습니다."); + GET_MENTORING_DETAIL_INFO("멘토링 상세 조회에 성공하였습니다."), + CREATE_MENTORING("멘토링 신청에 성공하였습니다."), + UPDATE_MENTORING("멘토링 상태 갱신에 성공하였습니다."), + + NOT_FOUND_MENTORING("멘토링이 존재하지 않습니다."); private final String message; } diff --git a/src/main/java/com/postgraduate/domain/senior/domain/service/SeniorGetService.java b/src/main/java/com/postgraduate/domain/senior/domain/service/SeniorGetService.java index bce902bf..6c83b6e2 100644 --- a/src/main/java/com/postgraduate/domain/senior/domain/service/SeniorGetService.java +++ b/src/main/java/com/postgraduate/domain/senior/domain/service/SeniorGetService.java @@ -14,4 +14,8 @@ public class SeniorGetService { public Senior byUser(User user) { return seniorRepository.findByUser(user).orElseThrow(/**예외 처리**/); } + + public Senior bySeniorId(Long seniorId) { + return seniorRepository.findById(seniorId).orElseThrow(/**예외 처리**/); + } } diff --git a/src/main/java/com/postgraduate/global/exception/ApplicationException.java b/src/main/java/com/postgraduate/global/exception/ApplicationException.java index 3c7f34ba..d61895ac 100644 --- a/src/main/java/com/postgraduate/global/exception/ApplicationException.java +++ b/src/main/java/com/postgraduate/global/exception/ApplicationException.java @@ -1,16 +1,13 @@ package com.postgraduate.global.exception; import lombok.Getter; -import org.springframework.http.HttpStatus; @Getter public abstract class ApplicationException extends RuntimeException{ private final String errorCode; - private final HttpStatus httpStatus; - protected ApplicationException(String message, String errorCode, HttpStatus httpStatus) { + protected ApplicationException(String message, String errorCode) { super(message); this.errorCode = errorCode; - this.httpStatus = httpStatus; } } \ No newline at end of file diff --git a/src/main/java/com/postgraduate/global/exception/GlobalExceptionHandler.java b/src/main/java/com/postgraduate/global/exception/GlobalExceptionHandler.java index caa92edf..5d7a8ba5 100644 --- a/src/main/java/com/postgraduate/global/exception/GlobalExceptionHandler.java +++ b/src/main/java/com/postgraduate/global/exception/GlobalExceptionHandler.java @@ -1,11 +1,20 @@ package com.postgraduate.global.exception; +import com.postgraduate.global.dto.ErrorResponse; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; @Slf4j @RestControllerAdvice @RequiredArgsConstructor public class GlobalExceptionHandler { + private static final String LOG_FORMAT = "Class : {}, Code : {}, Message : {}"; + @ExceptionHandler(ApplicationException.class) + public ResponseEntity handleApplicationException(ApplicationException ex) { + log.error(LOG_FORMAT, ex.getClass().getSimpleName(), ex.getErrorCode(), ex.getMessage()); + return ResponseEntity.ok(new ErrorResponse(ex.getErrorCode(), ex.getMessage())); + } } diff --git a/src/test/java/com/postgraduate/domain/auth/application/usecase/kakao/KakaoSignInUseCaseTest.java b/src/test/java/com/postgraduate/domain/auth/application/usecase/kakao/KakaoSignInUseCaseTest.java index 720a77c1..cdce4070 100644 --- a/src/test/java/com/postgraduate/domain/auth/application/usecase/kakao/KakaoSignInUseCaseTest.java +++ b/src/test/java/com/postgraduate/domain/auth/application/usecase/kakao/KakaoSignInUseCaseTest.java @@ -1,5 +1,6 @@ package com.postgraduate.domain.auth.application.usecase.kakao; +import com.postgraduate.domain.auth.application.dto.req.KakaoCodeRequest; import com.postgraduate.domain.auth.application.dto.res.AuthUserResponse; import com.postgraduate.domain.auth.application.dto.res.KakaoUserInfoResponse; import com.postgraduate.domain.auth.application.dto.res.KakaoUserInfoResponse.KakaoAccount; @@ -26,20 +27,22 @@ class KakaoSignInUseCaseTest { KakaoSignInUseCase kakaoSignInUseCase; @Test void 첫_로그인_socialId_반환() { - String token = "abcd"; - given(kakaoAccessTokenUseCase.getUserInfo(token)).willReturn(new KakaoUserInfoResponse(10000L, new KakaoAccount())); + String code = "abcdefg"; + KakaoCodeRequest kakaoCodeRequest = new KakaoCodeRequest(code); + given(kakaoAccessTokenUseCase.getKakaoToken(code)).willReturn(new KakaoUserInfoResponse(10000L, new KakaoAccount())); given(userGetService.bySocialId(10000L)).willReturn(Optional.ofNullable(null)); - AuthUserResponse authUserResponse = kakaoSignInUseCase.getUser(token); + AuthUserResponse authUserResponse = kakaoSignInUseCase.getUser(kakaoCodeRequest); Assertions.assertThat(authUserResponse.getSocialId()).isEqualTo(10000L); Assertions.assertThat(authUserResponse.getUser().isEmpty()).isTrue(); } @Test void 기존_유저_로그인_user반환() { - String token = "abcd"; - given(kakaoAccessTokenUseCase.getUserInfo(token)).willReturn(new KakaoUserInfoResponse(10000L, new KakaoAccount())); + String code = "abcdefg"; + KakaoCodeRequest kakaoCodeRequest = new KakaoCodeRequest(code); + given(kakaoAccessTokenUseCase.getKakaoToken(code)).willReturn(new KakaoUserInfoResponse(10000L, new KakaoAccount())); given(userGetService.bySocialId(10000L)).willReturn(Optional.ofNullable(new User())); - AuthUserResponse authUserResponse = kakaoSignInUseCase.getUser(token); + AuthUserResponse authUserResponse = kakaoSignInUseCase.getUser(kakaoCodeRequest); Assertions.assertThat(authUserResponse.getSocialId()).isEqualTo(10000L); Assertions.assertThat(authUserResponse.getUser().isEmpty()).isFalse(); } diff --git a/src/test/java/com/postgraduate/domain/mentoring/application/usecase/CheckIsMyMentoringUseCaseTest.java b/src/test/java/com/postgraduate/domain/mentoring/application/usecase/CheckIsMyMentoringUseCaseTest.java new file mode 100644 index 00000000..717cca05 --- /dev/null +++ b/src/test/java/com/postgraduate/domain/mentoring/application/usecase/CheckIsMyMentoringUseCaseTest.java @@ -0,0 +1,38 @@ +package com.postgraduate.domain.mentoring.application.usecase; + +import com.postgraduate.domain.mentoring.domain.entity.Mentoring; +import com.postgraduate.domain.mentoring.domain.service.MentoringGetService; +import com.postgraduate.domain.user.domain.entity.User; +import com.postgraduate.global.exception.ApplicationException; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class CheckIsMyMentoringUseCaseTest { + @Mock + private MentoringGetService mentoringGetService; + + @InjectMocks + private CheckIsMyMentoringUseCase checkIsMyMentoringUseCase; + + @Test + public void testCheckByRoleInvalid() { + User user = new User(); + Long mentoringId = 1L; + Mentoring mentoring = mock(); + + when(mentoring.getUser()).thenReturn(new User()); + when(mentoringGetService.byMentoringId(mentoringId)).thenReturn(mentoring); + + assertThrows(ApplicationException.class, () -> { + checkIsMyMentoringUseCase.checkByRole(user, mentoringId); + }); + } +} \ No newline at end of file