diff --git a/src/main/java/com/petmatz/api/user/controller/AuthController.java b/src/main/java/com/petmatz/api/user/controller/AuthController.java new file mode 100644 index 0000000..4d855e6 --- /dev/null +++ b/src/main/java/com/petmatz/api/user/controller/AuthController.java @@ -0,0 +1,59 @@ +package com.petmatz.api.user.controller; + +import com.petmatz.api.global.dto.Response; +import com.petmatz.api.user.request.CheckCertificationRequestDto; +import com.petmatz.api.user.request.DeleteIdRequestDto; +import com.petmatz.api.user.request.SignInRequestDto; +import com.petmatz.api.user.request.SignUpRequestDto; +import com.petmatz.domain.user.entity.User; +import com.petmatz.domain.user.response.CheckCertificationResponseDto; +import com.petmatz.domain.user.response.DeleteIdResponseDto; +import com.petmatz.domain.user.response.SignInResponseDto; +import com.petmatz.domain.user.response.SignUpResponseDto; +import com.petmatz.domain.user.service.AuthService; +import com.petmatz.domain.user.service.UserService; +import com.petmatz.user.common.LogInResponseDto; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +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; + +import javax.naming.AuthenticationException; +import java.net.MalformedURLException; +import java.security.cert.CertificateException; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/auth") +public class AuthController { + + private final AuthService authService; + + @PostMapping("/sign-in") + public Response signIn(@RequestBody @Valid SignInRequestDto requestBody, HttpServletResponse response) throws AuthenticationException { + SignInResponseDto result = authService.signIn(SignInRequestDto.of(requestBody), response); + return Response.success(result); + } + + @PostMapping("/logout") + public Response logout(HttpServletResponse res) { + authService.logout(res); + return Response.success(); + } + + @PostMapping("/sign-up") + public Response signUp(@RequestBody @Valid SignUpRequestDto requestBody) throws MalformedURLException { + SignUpResponseDto responseDto = authService.signUp(SignUpRequestDto.of(requestBody)); + return Response.success(responseDto); + } + + @PostMapping("/check-certification") + public Response checkCertification(@RequestBody @Valid CheckCertificationRequestDto requestBody) throws CertificateException { + authService.checkCertification(CheckCertificationRequestDto.of(requestBody)); + return Response.success(); + } +} diff --git a/src/main/java/com/petmatz/api/user/controller/EmailController.java b/src/main/java/com/petmatz/api/user/controller/EmailController.java new file mode 100644 index 0000000..eec20c7 --- /dev/null +++ b/src/main/java/com/petmatz/api/user/controller/EmailController.java @@ -0,0 +1,28 @@ +package com.petmatz.api.user.controller; + +import com.petmatz.api.global.dto.Response; +import com.petmatz.api.user.request.EmailCertificationRequestDto; +import com.petmatz.domain.user.response.EmailCertificationResponseDto; +import com.petmatz.domain.user.service.EmailService; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +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("/api/auth") +public class EmailController { + + private final EmailService emailService; + + @PostMapping("/email-certification") + public Response emailCertification(@RequestBody @Valid EmailCertificationRequestDto requestBody) { + emailService.emailCertification(requestBody); + return Response.success(); + } + +} diff --git a/src/main/java/com/petmatz/api/user/controller/HeartController.java b/src/main/java/com/petmatz/api/user/controller/HeartController.java new file mode 100644 index 0000000..6434288 --- /dev/null +++ b/src/main/java/com/petmatz/api/user/controller/HeartController.java @@ -0,0 +1,33 @@ +package com.petmatz.api.user.controller; + +import com.petmatz.api.global.dto.Response; +import com.petmatz.api.user.request.HeartedUserDto; +import com.petmatz.api.user.request.HeartingRequestDto; +import com.petmatz.domain.user.service.HeartService; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RestController +@RequiredArgsConstructor +public class HeartController { + + private final HeartService heartService; + + @PostMapping("/hearting") + public Response hearting(@RequestBody @Valid HeartingRequestDto requestBody) { + heartService.hearting(requestBody); + return Response.success(); + } + + @GetMapping("/get-heartlist") // 이거 테스트 필요 + public Response> getHeartedList() { + List heartedList = heartService.getHeartedList(); + return Response.success(heartedList); + } +} diff --git a/src/main/java/com/petmatz/api/user/controller/LocationController.java b/src/main/java/com/petmatz/api/user/controller/LocationController.java new file mode 100644 index 0000000..e5148e3 --- /dev/null +++ b/src/main/java/com/petmatz/api/user/controller/LocationController.java @@ -0,0 +1,25 @@ +package com.petmatz.api.user.controller; + +import com.petmatz.api.global.dto.Response; +import com.petmatz.api.user.request.UpdateLocationRequestDto; +import com.petmatz.domain.user.response.UpdateLocationResponseDto; +import com.petmatz.domain.user.service.LocationService; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +public class LocationController { + + private final LocationService locationService; + + @PostMapping("/update-location") + public Response updateLocation(@RequestBody @Valid UpdateLocationRequestDto requestBody) { + UpdateLocationResponseDto updateLocationResponseDto = locationService.updateLocation(UpdateLocationRequestDto.of(requestBody)); + return Response.success(updateLocationResponseDto); + } +} diff --git a/src/main/java/com/petmatz/api/user/controller/PageController.java b/src/main/java/com/petmatz/api/user/controller/PageController.java new file mode 100644 index 0000000..8f7255b --- /dev/null +++ b/src/main/java/com/petmatz/api/user/controller/PageController.java @@ -0,0 +1,39 @@ +package com.petmatz.api.user.controller; + +import com.petmatz.api.global.dto.Response; +import com.petmatz.api.user.request.EditMyProfileRequestDto; +import com.petmatz.domain.user.service.PageService; +import com.petmatz.domain.user.response.EditMyProfileResponseDto; +import com.petmatz.domain.user.response.GetMyProfileResponseDto; +import com.petmatz.domain.user.response.GetOtherProfileResponseDto; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.web.bind.annotation.*; + +import java.net.MalformedURLException; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/auth") +public class PageController { + + private final PageService pageService; + + @GetMapping("/get-myprofile") + public Response getMypage() { + GetMyProfileResponseDto myPage = pageService.getMypage(); + return Response.success(myPage); + } + + @GetMapping("/get-otherprofile") + public Response getOtherMypage(@RequestParam @Valid Long userId) { + GetOtherProfileResponseDto otherMypage = pageService.getOtherMypage(userId); + return Response.success(otherMypage); + } + + @PostMapping("/edit-myprofile") + public Response editMyProfile(@RequestBody @Valid EditMyProfileRequestDto requestBody) throws MalformedURLException { + EditMyProfileResponseDto editMyProfileResponseDto = pageService.editMyProfile(EditMyProfileRequestDto.of(requestBody)); + return Response.success(editMyProfileResponseDto); + } +} diff --git a/src/main/java/com/petmatz/api/user/controller/PasswordController.java b/src/main/java/com/petmatz/api/user/controller/PasswordController.java new file mode 100644 index 0000000..d02a359 --- /dev/null +++ b/src/main/java/com/petmatz/api/user/controller/PasswordController.java @@ -0,0 +1,34 @@ +package com.petmatz.api.user.controller; + +import com.petmatz.api.global.dto.Response; +import com.petmatz.api.user.request.RepasswordRequestDto; +import com.petmatz.api.user.request.SendRepasswordRequestDto; +import com.petmatz.domain.user.component.PasswordService; +import com.petmatz.domain.user.response.RepasswordResponseDto; +import com.petmatz.domain.user.response.SendRepasswordResponseDto; +import com.petmatz.domain.user.service.PasswordService; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +public class PasswordController { + + private final PasswordService passwordService; + + @PostMapping("/send-repassword") + public Response sendRepassword(@RequestBody @Valid SendRepasswordRequestDto requestBody) { + SendRepasswordResponseDto sendRepasswordResponseDto = passwordService.sendRepassword(requestBody); + return Response.success(sendRepasswordResponseDto); + } + + @PostMapping("/repassword") + public Response repassword(@RequestBody @Valid RepasswordRequestDto requestBody) { + passwordService.repassword(RepasswordRequestDto.of(requestBody)); + return Response.success(); + } +} diff --git a/src/main/java/com/petmatz/api/user/controller/PastUserController.java b/src/main/java/com/petmatz/api/user/controller/PastUserController.java new file mode 100644 index 0000000..f0cd8ad --- /dev/null +++ b/src/main/java/com/petmatz/api/user/controller/PastUserController.java @@ -0,0 +1,149 @@ +//package com.petmatz.api.user.controller; +// +//import com.petmatz.api.user.request.*; +//import com.petmatz.domain.user.service.AuthService; +//import com.petmatz.domain.user.response.*; +//import com.petmatz.domain.user.service.UserService; +//import com.petmatz.user.common.LogInResponseDto; +//import jakarta.servlet.http.HttpServletResponse; +//import jakarta.validation.Valid; +//import lombok.RequiredArgsConstructor; +//import lombok.extern.slf4j.Slf4j; +//import org.springframework.http.ResponseEntity; +//import org.springframework.web.bind.annotation.*; +// +//import java.net.MalformedURLException; +// +//@Slf4j +//@RestController +//@RequiredArgsConstructor +//@RequestMapping("/api/auth") +//public class PastUserController { +// private final UserService userService; +// private final AuthService authService; +// +// @PostMapping("/email-certification") +// public ResponseEntity emailCertification(@RequestBody @Valid EmailCertificationRequestDto requestBody) { +// ResponseEntity response = userService.emailCertification(requestBody); +// log.info("[emailCertification]: { accountId: " + requestBody.getAccountId() + "}"); +// return response; +// } // 하나 했음 +// +// @PostMapping("/check-certification") +// public ResponseEntity checkCertification(@RequestBody @Valid CheckCertificationRequestDto requestBody) { +// ResponseEntity response = userService.checkCertification(CheckCertificationRequestDto.of(requestBody)); +// log.info("[checkCertification]: {accountId: " + requestBody.getAccountId() + ", certificationNumber: " + requestBody.getCertificationNumber() + "}"); +// return response; +// } // 했음 +// +// @PostMapping("/sign-up") +// public ResponseEntity signUp(@RequestBody @Valid SignUpRequestDto requestBody) throws MalformedURLException { +// SignUpResponseDto responseDto = authService.signUp(SignUpRequestDto.of(requestBody)); +// log.info("[signUp]: { accountId: " + requestBody.getAccountId() + ", password: " + requestBody.getPassword()); +// return ResponseEntity.ok(responseDto); +// } // o +// +// @PostMapping("/sign-in") +// public ResponseEntity signIn( +// @RequestBody @Valid SignInRequestDto requestBody, +// HttpServletResponse response) { +// +// ResponseEntity result = userService.signIn(SignInRequestDto.of(requestBody), response); +// log.info("[signIn]: { accountId: " + requestBody.getAccountId() + ", result: " + result.getStatusCode() + " }"); +// return result; +// } // o +// +// @PostMapping("/delete-user") +// public ResponseEntity deleteUser(@RequestBody @Valid DeleteIdRequestDto requestBody) { +// ResponseEntity response = userService.deleteId(requestBody); +// log.info("[deleteUser]:{password: " + requestBody.getPassword() + "}"); +// return response; +// } // o +// +// //---------------------------------------------------------------------------------------------------------------------------------// +// @GetMapping("/get-myprofile") +// public ResponseEntity getMypage() { +// ResponseEntity response = userService.getMypage(); +// log.info("[getMypage]"); +// return response; +// } // o +// +// @GetMapping("/get-otherprofile") +// public ResponseEntity getOtherMypage(@RequestParam @Valid Long userId) { +// ResponseEntity response = userService.getOtherMypage(userId); +// log.info("[getOtherMypage]"); +// return response; +// } // o +// +// @PostMapping("/edit-myprofile") +// public ResponseEntity editMyProfile(@RequestBody @Valid EditMyProfileRequestDto requestBody) { +// ResponseEntity response = userService.editMyProfile(EditMyProfileRequestDto.of(requestBody)); +// log.info("[editMyProfile]"); +// return response; +// } // o +// +// @PostMapping("/send-repassword") +// public ResponseEntity sendRepassword(@RequestBody @Valid SendRepasswordRequestDto requestBody) { +// ResponseEntity response = userService.sendRepassword(requestBody); +// log.info("[sendRepassword]: {accountId: " + requestBody.getAccountId() + "}"); +// return response; +// } // o +// +// @PostMapping("/repassword") +// public ResponseEntity repassword(@RequestBody @Valid RepasswordRequestDto requestBody) { +// ResponseEntity response = userService.repassword(RepasswordRequestDto.of(requestBody)); +// log.info("[repassword]: {currentPassword: " + requestBody.getCurrentPassword() + ", newPassword: " + requestBody.getNewPassword() + "}"); +// return response; +// } // o +// +// //--------------------------------------------------------------------------------------------------------------------------------------------------------------- +// @PostMapping("/hearting") +// public ResponseEntity hearting(@RequestBody @Valid HeartingRequestDto requestBody) { +// ResponseEntity response = userService.hearting(requestBody); +// log.info("[hearting]: {heartedId: " + requestBody.getHeartedId() + "}"); +// return response; +// } // o +// +// @GetMapping("/get-heartlist") +// public ResponseEntity getHeartedList() { +// ResponseEntity response = userService.getHeartedList(); +// log.info("[getHeartedList]"); +// return response; +// } // o +// +// @PostMapping("/update-location") +// public ResponseEntity updateLocation(@RequestBody @Valid UpdateLocationRequestDto requestBody) { +// ResponseEntity response = userService.updateLocation(UpdateLocationRequestDto.of(requestBody)); +// log.info("[updateLocation]"); +// return response; +// } // o +// +// @PostMapping("/update-recommendation") +// public ResponseEntity updateRecommend(@RequestBody @Valid UpdateRecommendationRequestDto requestBody) { +// ResponseEntity response = userService.updateRecommend(requestBody); +// log.info("[updateRecommend]"); +// return response; +// } +// +// @GetMapping("/get-recommended") +// public ResponseEntity getRecommend(@RequestBody @Valid UpdateRecommendationRequestDto requestBody) { +// ResponseEntity response = userService.getRecommend(requestBody); +// log.info("[getRecommend]"); +// return response; +// } +// +// @PostMapping("/logout") +// public ResponseEntity logout(HttpServletResponse res) { +// ResponseEntity response = userService.logout(res); +// log.info("[logout]"); +// return response; +// } +// +// @PostMapping("/edit-kakaoprofile") +// public ResponseEntity editKakaoProfile(@RequestBody @Valid EditKakaoProfileRequestDto requestBody) { +// ResponseEntity response = userService.editKakaoProfile(EditKakaoProfileRequestDto.of(requestBody)); +// log.info("[editKakaoProfile]"); +// return response; +// } +//} +// diff --git a/src/main/java/com/petmatz/api/user/controller/RecommendController.java b/src/main/java/com/petmatz/api/user/controller/RecommendController.java new file mode 100644 index 0000000..628c556 --- /dev/null +++ b/src/main/java/com/petmatz/api/user/controller/RecommendController.java @@ -0,0 +1,33 @@ +package com.petmatz.api.user.controller; + +import com.petmatz.api.global.dto.Response; +import com.petmatz.api.user.request.UpdateRecommendationRequestDto; +import com.petmatz.domain.user.response.GetRecommendationResponseDto; +import com.petmatz.domain.user.response.UpdateRecommendationResponseDto; +import com.petmatz.domain.user.service.RecommendService; +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.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequiredArgsConstructor +public class RecommendController { + + private final RecommendService recommendService; + + @PostMapping("/update-recommendation") + public Response updateRecommend(@RequestBody @Valid UpdateRecommendationRequestDto requestBody) { + recommendService.updateRecommend(requestBody); + return Response.success(); + } + + @GetMapping("/get-recommended") + public Response getRecommend(@RequestBody @Valid UpdateRecommendationRequestDto requestBody) { + GetRecommendationResponseDto recommend = recommendService.getRecommend(requestBody); + return Response.success(recommend); + } +} diff --git a/src/main/java/com/petmatz/api/user/controller/UserController.java b/src/main/java/com/petmatz/api/user/controller/UserController.java index b9086bb..2c35b30 100644 --- a/src/main/java/com/petmatz/api/user/controller/UserController.java +++ b/src/main/java/com/petmatz/api/user/controller/UserController.java @@ -1,146 +1,33 @@ package com.petmatz.api.user.controller; -import com.petmatz.api.user.request.*; -import com.petmatz.domain.user.response.*; -import com.petmatz.domain.user.service.UserService; -import com.petmatz.user.common.LogInResponseDto; -import jakarta.servlet.http.HttpServletResponse; +import com.petmatz.api.global.dto.Response; +import com.petmatz.api.user.request.DeleteIdRequestDto; +import com.petmatz.api.user.request.EditKakaoProfileRequestDto; +import com.petmatz.domain.user.service.KakaoUserService; +import com.petmatz.domain.user.component.UserService; +import com.petmatz.domain.user.response.EditKakaoProfileResponseDto; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -@Slf4j @RestController @RequiredArgsConstructor @RequestMapping("/api/auth") public class UserController { - private final UserService userService; - - @PostMapping("/email-certification") - public ResponseEntity emailCertification(@RequestBody @Valid EmailCertificationRequestDto requestBody) { - ResponseEntity response = userService.emailCertification(requestBody); - log.info("[emailCertification]: { accountId: " + requestBody.getAccountId() + "}"); - return response; - } - - @PostMapping("/check-certification") - public ResponseEntity checkCertification(@RequestBody @Valid CheckCertificationRequestDto requestBody) { - ResponseEntity response = userService.checkCertification(CheckCertificationRequestDto.of(requestBody)); - log.info("[checkCertification]: {accountId: " + requestBody.getAccountId() + ", certificationNumber: " + requestBody.getCertificationNumber() + "}"); - return response; - } - - @PostMapping("/sign-up") - public ResponseEntity signUp(@RequestBody @Valid SignUpRequestDto requestBody) { - ResponseEntity response = userService.signUp(SignUpRequestDto.of(requestBody)); - log.info("[signUp]: { accountId: " + requestBody.getAccountId() + ", password: " + requestBody.getPassword()); - return response; - } - - @PostMapping("/sign-in") - public ResponseEntity signIn( - @RequestBody @Valid SignInRequestDto requestBody, - HttpServletResponse response) { - - ResponseEntity result = userService.signIn(SignInRequestDto.of(requestBody), response); - log.info("[signIn]: { accountId: " + requestBody.getAccountId() + ", result: " + result.getStatusCode() + " }"); - return result; - } - - @PostMapping("/delete-user") - public ResponseEntity deleteUser(@RequestBody @Valid DeleteIdRequestDto requestBody) { - ResponseEntity response = userService.deleteId(requestBody); - log.info("[deleteUser]:{password: " + requestBody.getPassword() + "}"); - return response; - } - - //---------------------------------------------------------------------------------------------------------------------------------// - @GetMapping("/get-myprofile") - public ResponseEntity getMypage() { - ResponseEntity response = userService.getMypage(); - log.info("[getMypage]"); - return response; - } - - @GetMapping("/get-otherprofile") - public ResponseEntity getOtherMypage(@RequestParam @Valid Long userId) { - ResponseEntity response = userService.getOtherMypage(userId); - log.info("[getOtherMypage]"); - return response; - } - - @PostMapping("/edit-myprofile") - public ResponseEntity editMyProfile(@RequestBody @Valid EditMyProfileRequestDto requestBody) { - ResponseEntity response = userService.editMyProfile(EditMyProfileRequestDto.of(requestBody)); - log.info("[editMyProfile]"); - return response; - } - - @PostMapping("/send-repassword") - public ResponseEntity sendRepassword(@RequestBody @Valid SendRepasswordRequestDto requestBody) { - ResponseEntity response = userService.sendRepassword(requestBody); - log.info("[sendRepassword]: {accountId: " + requestBody.getAccountId() + "}"); - return response; - } - - @PostMapping("/repassword") - public ResponseEntity repassword(@RequestBody @Valid RepasswordRequestDto requestBody) { - ResponseEntity response = userService.repassword(RepasswordRequestDto.of(requestBody)); - log.info("[repassword]: {currentPassword: " + requestBody.getCurrentPassword() + ", newPassword: " + requestBody.getNewPassword() + "}"); - return response; - } - - //--------------------------------------------------------------------------------------------------------------------------------------------------------------- - @PostMapping("/hearting") - public ResponseEntity hearting(@RequestBody @Valid HeartingRequestDto requestBody) { - ResponseEntity response = userService.hearting(requestBody); - log.info("[hearting]: {heartedId: " + requestBody.getHeartedId() + "}"); - return response; - } - - @GetMapping("/get-heartlist") - public ResponseEntity getHeartedList() { - ResponseEntity response = userService.getHeartedList(); - log.info("[getHeartedList]"); - return response; - } - @PostMapping("/update-location") - public ResponseEntity updateLocation(@RequestBody @Valid UpdateLocationRequestDto requestBody) { - ResponseEntity response = userService.updateLocation(UpdateLocationRequestDto.of(requestBody)); - log.info("[updateLocation]"); - return response; - } - - @PostMapping("/update-recommendation") - public ResponseEntity updateRecommend(@RequestBody @Valid UpdateRecommendationRequestDto requestBody) { - ResponseEntity response = userService.updateRecommend(requestBody); - log.info("[updateRecommend]"); - return response; - } - - @GetMapping("/get-recommended") - public ResponseEntity getRecommend(@RequestBody @Valid UpdateRecommendationRequestDto requestBody) { - ResponseEntity response = userService.getRecommend(requestBody); - log.info("[getRecommend]"); - return response; - } + private final UserService userService; + private final KakaoUserService kakaoUserService; - @PostMapping("/logout") - public ResponseEntity logout(HttpServletResponse res) { - ResponseEntity response = userService.logout(res); - log.info("[logout]"); - return response; + @DeleteMapping("/delete-user") + public Response deleteUser(@RequestBody @Valid DeleteIdRequestDto requestBody) { + userService.deleteId(requestBody); + return Response.success(); } @PostMapping("/edit-kakaoprofile") - public ResponseEntity editKakaoProfile(@RequestBody @Valid EditKakaoProfileRequestDto requestBody) { - ResponseEntity response = userService.editKakaoProfile(EditKakaoProfileRequestDto.of(requestBody)); - log.info("[editKakaoProfile]"); - return response; + public Response editKakaoProfile(@RequestBody @Valid EditKakaoProfileRequestDto requestBody) { + kakaoUserService.editKakaoProfile(EditKakaoProfileRequestDto.of(requestBody)); + return Response.success(); } - } - diff --git a/src/main/java/com/petmatz/domain/user/component/AuthenticationComponent.java b/src/main/java/com/petmatz/domain/user/component/AuthenticationComponent.java new file mode 100644 index 0000000..b55f55a --- /dev/null +++ b/src/main/java/com/petmatz/domain/user/component/AuthenticationComponent.java @@ -0,0 +1,105 @@ +package com.petmatz.domain.user.component; + +import com.petmatz.common.security.utils.JwtProvider; +import com.petmatz.domain.user.entity.Certification; +import com.petmatz.domain.user.entity.User; +import com.petmatz.domain.user.exception.UserException; +import com.petmatz.domain.user.info.CheckCertificationInfo; +import com.petmatz.domain.user.info.SignInInfo; +import com.petmatz.domain.user.repository.CertificationRepository; +import com.petmatz.domain.user.repository.UserRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Component; + +import javax.naming.AuthenticationException; +import java.security.cert.CertificateException; +import java.time.LocalDateTime; + +import static com.petmatz.domain.user.exception.MatchErrorCode.CERTIFICATION_EXPIRED; +import static com.petmatz.domain.user.exception.MatchErrorCode.MISS_MATCH_CODE; + +@Component +@RequiredArgsConstructor +public class AuthenticationComponent { + + private final CertificationRepository certificationRepository; + private final UserRepository userRepository; + private final JwtProvider jwtProvider; + private final UserUtils userUtils; + private PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); + + public User validateSignInCredentials(SignInInfo info) throws AuthenticationException { + String accountId = info.getAccountId(); + String password = info.getPassword(); + + User user = userUtils.findUser(accountId); + + String encodedPassword = user.getPassword(); + if (!passwordEncoder.matches(password, encodedPassword)) { + throw new AuthenticationException("비밀번호 불일치"); + } + return user; + } + + public String createJwtToken(User user) { + return jwtProvider.create(user.getId(), user.getAccountId()); + } + + /** + * 필수 정보 누락 확인 + */ + public void validateRequiredFields(String accountId, String certificationNumber, String password) { + if (accountId == null || certificationNumber == null || password == null) { + throw new IllegalArgumentException("필수 정보가 누락되었습니다."); + } + } + + /** + * 인증 번호 확인 + */ + public void validateCertification(String accountId) { + Certification certification = certificationRepository.findTopByAccountIdOrderByCreatedAtDesc(accountId); + if (certification == null || !certification.getIsVerified()) { + throw new IllegalStateException("인증 번호가 유효하지 않거나 인증되지 않았습니다."); + } + } + + /** + * 중복된 ID 확인 + */ + public void validateDuplicateAccountId(String accountId) { + if (userRepository.existsByAccountId(accountId)) { + throw new IllegalArgumentException("중복된 ID가 존재합니다."); + } + } + + /** + * 예외는 추후에 수정 (일단은 임시로 userEx 사용) + */ + public Certification validateCertification(CheckCertificationInfo info) throws CertificateException { + Certification certification = certificationRepository.findTopByAccountIdOrderByCreatedAtDesc(info.getAccountId()); + if (certification == null) { + throw new CertificateException("인증 정보가 없습니다."); + } + // 인증 번호와 계정 ID 일치 여부 확인 + boolean isMatch = certification.getAccountId().equals(info.getAccountId()) + && certification.getCertificationNumber().equals(info.getCertificationNumber()); + + if (!isMatch) { + throw new UserException(MISS_MATCH_CODE); + } + + // 인증 시간 확인 + if (certification.getCreatedAt().isBefore(LocalDateTime.now().minusMinutes(5))) { + throw new UserException(CERTIFICATION_EXPIRED); + } + return certification; + } + + public void updateCertificationStatus(Certification certification) { + certification.markAsVerified(); + certificationRepository.save(certification); + } +} diff --git a/src/main/java/com/petmatz/domain/user/component/EmailComponent.java b/src/main/java/com/petmatz/domain/user/component/EmailComponent.java new file mode 100644 index 0000000..04a250c --- /dev/null +++ b/src/main/java/com/petmatz/domain/user/component/EmailComponent.java @@ -0,0 +1,28 @@ +package com.petmatz.domain.user.component; + +import com.petmatz.domain.user.entity.Certification; +import com.petmatz.domain.user.exception.UserException; +import com.petmatz.domain.user.repository.CertificationRepository; +import com.petmatz.domain.user.repository.UserRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +import static com.petmatz.domain.user.exception.MatchErrorCode.USER_DUPLICATE; + +@Component +@RequiredArgsConstructor +public class EmailComponent { + + private final UserRepository userRepository; + private final CertificationRepository certificationRepository; + + public void saveCertification(String accountId, String certificationNumber) { + Certification certification = Certification.builder() + .accountId(accountId) + .certificationNumber(certificationNumber) + .isVerified(false) + .build(); + certificationRepository.save(certification); + } + +} diff --git a/src/main/java/com/petmatz/domain/user/service/GeocodingService.java b/src/main/java/com/petmatz/domain/user/component/GeocodingComponent.java similarity index 56% rename from src/main/java/com/petmatz/domain/user/service/GeocodingService.java rename to src/main/java/com/petmatz/domain/user/component/GeocodingComponent.java index e7b1259..6fc3304 100644 --- a/src/main/java/com/petmatz/domain/user/service/GeocodingService.java +++ b/src/main/java/com/petmatz/domain/user/component/GeocodingComponent.java @@ -1,19 +1,25 @@ -package com.petmatz.domain.user.service; +package com.petmatz.domain.user.component; import com.fasterxml.jackson.annotation.JsonProperty; +import com.petmatz.domain.user.entity.KakaoRegion; +import com.petmatz.domain.user.exception.UserException; +import com.petmatz.domain.user.response.KakaoGeocodingResponse; import lombok.Data; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.*; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; +import com.petmatz.domain.user.entity.KakaoRegion; -import java.util.List; -@Service -public class GeocodingService { +import java.util.List; - private final String KAKAO_API_URL = "https://dapi.kakao.com/v2/local/geo/coord2regioncode.json"; +import static com.petmatz.domain.user.exception.MatchErrorCode.INSUFFICIENT_LOCATION_DATA; +@Service +public class GeocodingComponent { + @Value("${kakao-api-url}") + private String KAKAO_API_URL; @Value("${kakao-api-key}") private String KAKAO_API_KEY; @@ -57,41 +63,15 @@ private void logInfo(KakaoRegion region) { System.out.println("Region Code: " + region.getCode()); } - @Data - static class KakaoGeocodingResponse { - private List documents; - } - - @Data - static class KakaoRegion { - @JsonProperty("region_1depth_name") - private String region1; // 예: 서울 - @JsonProperty("region_2depth_name") - private String region2; // 예: 강남구 역삼동 - @JsonProperty("region_3depth_name") - private String region3; // 예: 역삼동 - @JsonProperty("code") - private String code; // 행정구역 코드 (String 타입) - - /** - * '구'까지만 반환하는 메서드 - * - * @return "서울 강남구"와 같은 형식 - */ - public String getRegionName() { - // '구'까지만 표시되도록 region2를 공백 기준으로 split 후 첫 번째 단어 반환 - String region2Trimmed = region2.contains(" ") ? region2.split(" ")[0] : region2; - return region1 + " " + region2Trimmed; - } - - public Integer getCodeAsInteger() { - try { - String trimmedCode = code.length() > 6 ? code.substring(0, 6) : code; - return Integer.parseInt(trimmedCode); - } catch (NumberFormatException e) { - System.err.println("Failed to parse region code: " + code); - return null; - } + /** + * 좌표를 기반으로 지역 정보를 가져오고 유효성을 검증 + */ + public KakaoRegion getValidRegion(double latitude, double longitude) { + KakaoRegion kakaoRegion = getRegionFromCoordinates(latitude, longitude); + // 지역 정보 검증 + if (kakaoRegion == null || kakaoRegion.getCodeAsInteger() == null) { + throw new UserException(INSUFFICIENT_LOCATION_DATA); } + return kakaoRegion; } } \ No newline at end of file diff --git a/src/main/java/com/petmatz/domain/user/component/HeartComponent.java b/src/main/java/com/petmatz/domain/user/component/HeartComponent.java new file mode 100644 index 0000000..90e9c71 --- /dev/null +++ b/src/main/java/com/petmatz/domain/user/component/HeartComponent.java @@ -0,0 +1,68 @@ +package com.petmatz.domain.user.component; + +import com.petmatz.api.user.request.HeartedUserDto; +import com.petmatz.domain.user.entity.Heart; +import com.petmatz.domain.user.entity.User; +import com.petmatz.domain.user.entity.UserFactory; +import com.petmatz.domain.user.exception.UserException; +import com.petmatz.domain.user.repository.HeartRepository; +import com.petmatz.domain.user.repository.UserRepository; +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +import java.util.List; +import java.util.Optional; + +import static com.petmatz.domain.user.exception.MatchErrorCode.*; + +@RequiredArgsConstructor +@Component +public class HeartComponent { + + private final UserRepository userRepository; + private final HeartRepository heartRepository; + + @Transactional + public void validateHeartUser(Long heartId) { + if (!userRepository.existsById(heartId)) { + throw new UserException(HEART_USER_NOT_FOUND); + } + } + + @Transactional + public boolean toggleHeart(Long myId, Long heartId) { + Optional existingHeart = heartRepository.findByMyIdAndHeartedId(myId, heartId); + + if (existingHeart.isPresent()) { + heartRepository.delete(existingHeart.get()); + return false; // 혜제 + } + + Heart heart = UserFactory.createHeart(myId, heartId); + heartRepository.save(heart); + return true; + } + + @Transactional + public List getHeartedUsers(Long myId) { + + List heartList = heartRepository.findAllByMyId(myId); + + return heartList.stream() + .map(heart -> { + User heartedUser = userRepository.findById(heart.getHeartedId()) + .orElseThrow(() -> new UserException(HEART_USER_NOT_FOUND)); + + return new HeartedUserDto( + heart.getMyId(), + heart.getHeartedId(), + heartedUser.getNickname(), + heartedUser.getProfileImg(), + heartedUser.getCareAvailable(), + heartedUser.getPreferredSizes() + ); + }) + .toList(); + } +} diff --git a/src/main/java/com/petmatz/domain/user/component/KakaoComponent.java b/src/main/java/com/petmatz/domain/user/component/KakaoComponent.java new file mode 100644 index 0000000..2571dd9 --- /dev/null +++ b/src/main/java/com/petmatz/domain/user/component/KakaoComponent.java @@ -0,0 +1,62 @@ +package com.petmatz.domain.user.component; + +import com.petmatz.domain.user.entity.CustomOAuthUser; +import com.petmatz.domain.user.entity.User; +import com.petmatz.domain.user.repository.UserRepository; +import com.petmatz.domain.user.service.KakaoUserService; +import lombok.RequiredArgsConstructor; +import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService; +import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; +import org.springframework.security.oauth2.core.OAuth2AuthenticationException; +import org.springframework.security.oauth2.core.user.OAuth2User; +import org.springframework.stereotype.Component; + +import java.util.Map; + +@Component +@RequiredArgsConstructor +public class KakaoComponent extends DefaultOAuth2UserService implements OAuth2UserLoader { + + private final UserRepository userRepository; + private final KakaoUserService kaKaoUserService; + @Override + public boolean supports(String registrationId) { + return "kakao".equalsIgnoreCase(registrationId); + } + + @Override + public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException { + OAuth2User oAuth2User = super.loadUser(userRequest); + Map attributes = oAuth2User.getAttributes(); + + // RegistrationId 체크 + String registrationId = userRequest.getClientRegistration().getRegistrationId(); + if (!"kakao".equals(registrationId)) { + throw new OAuth2AuthenticationException("Unsupported registrationId: " + registrationId); + } + + // id 추출 + String kakaoAccountId = attributes.get("id").toString(); // 고유 ID + Map kakaoAccount = (Map) attributes.get("kakao_account"); + + // 이메일 추출 + String email = (String) kakaoAccount.get("email"); + if (email == null || email.isEmpty()) { + throw new OAuth2AuthenticationException("Email is required for Kakao login."); + } + + // 닉네임 추출 + Map profile = (Map) kakaoAccount.get("profile"); + String nickname = (String) profile.getOrDefault("nickname", "Unknown User"); + + // 이미지 추출 (선택) + String profileImage = (String) profile.getOrDefault("profile_image_url", ""); + + User user = userRepository.findByAccountId(email); + if (user == null) { + user = kaKaoUserService.createNewKakaoUser(kakaoAccountId, email, nickname, profileImage); + } + + return new CustomOAuthUser(user.getId(), user.getAccountId(), attributes, oAuth2User.getAuthorities()); + } +} diff --git a/src/main/java/com/petmatz/domain/user/component/OAuth2UserLoader.java b/src/main/java/com/petmatz/domain/user/component/OAuth2UserLoader.java new file mode 100644 index 0000000..bdb187a --- /dev/null +++ b/src/main/java/com/petmatz/domain/user/component/OAuth2UserLoader.java @@ -0,0 +1,11 @@ +package com.petmatz.domain.user.component; + + +import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; +import org.springframework.security.oauth2.core.OAuth2AuthenticationException; +import org.springframework.security.oauth2.core.user.OAuth2User; + +public interface OAuth2UserLoader { + boolean supports(String registrationId); + OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException; +} diff --git a/src/main/java/com/petmatz/domain/user/component/PasswordComponent.java b/src/main/java/com/petmatz/domain/user/component/PasswordComponent.java new file mode 100644 index 0000000..bd743c9 --- /dev/null +++ b/src/main/java/com/petmatz/domain/user/component/PasswordComponent.java @@ -0,0 +1,27 @@ +package com.petmatz.domain.user.component; + +import com.petmatz.domain.user.exception.UserException; +import lombok.RequiredArgsConstructor; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Component; + +import static com.petmatz.domain.user.exception.MatchErrorCode.PASSWORD_MISMATCH; + +@Component +@RequiredArgsConstructor +public class PasswordComponent { + + private final PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); + + public String encodePassword(String repasswordNum) { + passwordEncoder.encode(repasswordNum); + return repasswordNum; + } + + public void validatePassword(String currentPassword, String userPassword) { + if (!passwordEncoder.matches(currentPassword, userPassword)) { + throw new UserException(PASSWORD_MISMATCH); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/petmatz/domain/user/component/RecommendComponent.java b/src/main/java/com/petmatz/domain/user/component/RecommendComponent.java new file mode 100644 index 0000000..d72f451 --- /dev/null +++ b/src/main/java/com/petmatz/domain/user/component/RecommendComponent.java @@ -0,0 +1,20 @@ +package com.petmatz.domain.user.component; + +import com.petmatz.domain.user.repository.RecommendationRepository; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class RecommendComponent { + + private final RecommendationRepository recommendationRepository; + + public boolean validateRecommendUser(Long myId, Long recommendUserId) { + boolean exists = recommendationRepository.existsByMyIdAndRecommendedId(myId, recommendUserId); + if (exists) { + return true; + } + return false; + } +} diff --git a/src/main/java/com/petmatz/domain/user/component/UserReader.java b/src/main/java/com/petmatz/domain/user/component/UserReader.java index 603f6fc..8e54c8d 100644 --- a/src/main/java/com/petmatz/domain/user/component/UserReader.java +++ b/src/main/java/com/petmatz/domain/user/component/UserReader.java @@ -1,19 +1,25 @@ package com.petmatz.domain.user.component; import com.petmatz.domain.user.entity.User; +import com.petmatz.domain.user.exception.UserException; import com.petmatz.domain.user.repository.UserRepository; +import jakarta.transaction.Transactional; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; +import static com.petmatz.domain.user.exception.MatchErrorCode.USER_NOT_FOUND; + @Component @RequiredArgsConstructor public class UserReader { + /** + * 이것도 utils를 만들어서 곧 지울듯 + */ private final UserRepository userRepository; public User getAuthenticatedUser(Long userId) { return userRepository.findById(userId) .orElseThrow(() -> new IllegalArgumentException("User not found :" + userId)); } - } diff --git a/src/main/java/com/petmatz/domain/user/component/UserService.java b/src/main/java/com/petmatz/domain/user/component/UserService.java new file mode 100644 index 0000000..41fe880 --- /dev/null +++ b/src/main/java/com/petmatz/domain/user/component/UserService.java @@ -0,0 +1,67 @@ +package com.petmatz.domain.user.component; + +import com.petmatz.api.user.request.DeleteIdRequestDto; +import com.petmatz.common.security.utils.JwtExtractProvider; +import com.petmatz.domain.pet.entity.Pet; +import com.petmatz.domain.pet.repository.PetRepository; +import com.petmatz.domain.user.entity.User; +import com.petmatz.domain.user.info.UserInfo; +import com.petmatz.domain.user.repository.CertificationRepository; +import com.petmatz.domain.user.repository.UserRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Component +@RequiredArgsConstructor +@Slf4j +public class UserService { + + /** + * 여기 종원님이랑 머지하고 펫레포 최신버전 받아오고 수정 예정 25.01.14 + */ + + private final UserRepository userRepository; + private final PetRepository petRepository; + + + private final CertificationRepository certificationRepository; + private final JwtExtractProvider jwtExtractProvider; + private final UserUtils userUtils; + private final PasswordComponent passwordComponent; + + + @Transactional + public void deleteId(DeleteIdRequestDto dto) { + Long userId = jwtExtractProvider.findIdFromJwt(); + User user = userUtils.findIdUser(userId); + + String password = dto.getPassword(); + String encodedPassword = user.getPassword(); + + passwordComponent.validatePassword(password, encodedPassword); + certificationRepository.deleteById(userId); + // 사용자 삭제 + List pets = petRepository.findAllByUserId(user.getId()); // Pet 엔티티에서 User를 참조하는 기준으로 조회 + // 명시적으로 Pet 삭제 + petRepository.deleteAll(pets); + userRepository.delete(user); + } + + + public UserInfo selectUserInfo(String receiverEmail) { + User otherUser = userRepository.findByAccountId(receiverEmail); + return otherUser.of(); + } + + public String findByUserEmail(Long userId) { + return userRepository.findById(userId).get().getAccountId(); + } + + public void deleteUser(Long userUUID) { + userRepository.deleteUserById(userUUID); + } +} diff --git a/src/main/java/com/petmatz/domain/user/component/UserUtils.java b/src/main/java/com/petmatz/domain/user/component/UserUtils.java new file mode 100644 index 0000000..42df080 --- /dev/null +++ b/src/main/java/com/petmatz/domain/user/component/UserUtils.java @@ -0,0 +1,65 @@ +package com.petmatz.domain.user.component; + +import com.petmatz.common.security.utils.JwtExtractProvider; +import com.petmatz.domain.user.entity.User; +import com.petmatz.domain.user.exception.UserException; +import com.petmatz.domain.user.repository.HeartRepository; +import com.petmatz.domain.user.repository.UserRepository; +import jakarta.transaction.Transactional; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Component; + +import static com.petmatz.domain.user.exception.MatchErrorCode.*; + +@Component +@RequiredArgsConstructor +public class UserUtils { + + private final UserRepository userRepository; + private final HeartRepository heartRepository; + + public void checkDuplicateAccountId(String accountId) { + if (userRepository.existsByAccountId(accountId)) { + throw new UserException(USER_DUPLICATE); + } + } + + public void checkDuplicateId(Long userId) { + if (userRepository.existsById(userId)) { + throw new UserException(USER_DUPLICATE); + } + } + public User findUser(String accountId) { + User user = userRepository.findByAccountId(accountId); + if (user == null) { + throw new UserException(USER_NOT_FOUND); + } + return user; + } + + public User findIdUser(Long userId) { + User user = userRepository.findById(userId) + .orElseThrow(() -> new UserException(USER_NOT_FOUND)); + return user; + } + + + @Transactional + public User getCurrentUser(Long userId) { + return userRepository.findById(userId) + .orElseThrow(() -> new UserException(USER_NOT_FOUND)); + } + + public void findJwtUser(Long userId) { + if (userId == null) { + throw new UserException(JWT_USER_NOT_FOUND); + } + } + + public boolean checkHeart(Long myId, Long userId) { + if (heartRepository.existsByMyIdAndHeartedId(myId, userId)) { + return false; + } + return true; + } +} diff --git a/src/main/java/com/petmatz/domain/user/entity/KakaoRegion.java b/src/main/java/com/petmatz/domain/user/entity/KakaoRegion.java new file mode 100644 index 0000000..4603b33 --- /dev/null +++ b/src/main/java/com/petmatz/domain/user/entity/KakaoRegion.java @@ -0,0 +1,37 @@ +package com.petmatz.domain.user.entity; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class KakaoRegion { + @JsonProperty("region_1depth_name") + private String region1; // 예: 서울 + @JsonProperty("region_2depth_name") + private String region2; // 예: 강남구 역삼동 + @JsonProperty("region_3depth_name") + private String region3; // 예: 역삼동 + @JsonProperty("code") + private String code; // 행정구역 코드 (String 타입) + + /** + * '구'까지만 반환하는 메서드 + * + * @return "서울 강남구"와 같은 형식 + */ + public String getRegionName() { + // '구'까지만 표시되도록 region2를 공백 기준으로 split 후 첫 번째 단어 반환 + String region2Trimmed = region2.contains(" ") ? region2.split(" ")[0] : region2; + return region1 + " " + region2Trimmed; + } + + public Integer getCodeAsInteger() { + try { + String trimmedCode = code.length() > 6 ? code.substring(0, 6) : code; + return Integer.parseInt(trimmedCode); + } catch (NumberFormatException e) { + System.err.println("Failed to parse region code: " + code); + return null; + } + } +} diff --git a/src/main/java/com/petmatz/domain/user/entity/User.java b/src/main/java/com/petmatz/domain/user/entity/User.java index 88e35be..dbb16a8 100644 --- a/src/main/java/com/petmatz/domain/user/entity/User.java +++ b/src/main/java/com/petmatz/domain/user/entity/User.java @@ -42,6 +42,9 @@ public class User extends BaseEntity { @Column(name = "account_id",unique = true) private String accountId; + @Column(name = "registrationId") + private String registrationId; + @Column(name = "password") private String password; @@ -154,7 +157,7 @@ public UserInfo of() { .build(); } - public void checkLatitudeLongitude() { // (희수 : 예외나 위도 경도 범위 추후에 변경 예정입니다!) + public void checkLatitudeLongitude() { if (latitude <= 0) { throw new MatchException(INSUFFICIENT_LATITUDE_DATA); } diff --git a/src/main/java/com/petmatz/domain/user/exception/MatchErrorCode.java b/src/main/java/com/petmatz/domain/user/exception/MatchErrorCode.java index f1245aa..c0f7184 100644 --- a/src/main/java/com/petmatz/domain/user/exception/MatchErrorCode.java +++ b/src/main/java/com/petmatz/domain/user/exception/MatchErrorCode.java @@ -6,18 +6,21 @@ @RequiredArgsConstructor public enum MatchErrorCode implements BaseErrorCode { - INSUFFICIENT_CARE_DATA(400, "INSUFFICIENT_CARE_DATA", "돌봄 여부가 없습니다."), - INSUFFICIENT_MBTI_DATA(400, "INSUFFICIENT_MBTI_DATA", "MBTI 별 점수를 찾을 수 없습니다."), + + INSUFFICIENT_LOCATION_DATA(404, "INSUFFICIENT_LOCATION_DATA", "유요한 위치 정보를 가져올 수 없습니다."), + MISS_KAKAO_LOACTION(400, "MISS_KAKAO_LOACTION", "카카오 지역 api를 호출 할 수 없습니다."), INSUFFICIENT_LATITUDE_DATA(400, "INSUFFICIENT_LATITUDE_DATA", "위도가 없습니다."), INSUFFICIENT_LONGITUDE_DATA(400, "INSUFFICIENT_LONGITUDE_DATA", "경도가 없습니다."), - INSUFFICIENT_TARGET_LATITUDE_DATA(400, "INSUFFICIENT_TARGET_LATITUDE_DATA", "타켓 유저의 위도가 없습니다."), - INSUFFICIENT_TARGET_LONGITUDE_DATA(400, "INSUFFICIENT_TARGET_LONGITUDE_DATA", "타켓 유저의 경도가 없습니다."), INVALID_MATCH_DATA(400, "INVALID_MATCH_DATA", "위도 또는 경도가 누락되었습니다."), - NULL_PREFERRED_SIZES(400, "NULL_PREFERRED_SIZES", "선호 크기 목록이 없습니다."), - NULL_TARGET_SIZE(400, "NULL_TARGET_SIZE", "타겟 크기가 없습니다."), - NULL_MATCH_DATA(204, "NULL_MATCH_DATA", "매칭 데이터가 없습니다."), - INVALID_REDIS_DATA(404, "INVALID_REDIS_DATA", "redis 데이터를 불러올 수 없습니다."), - TARGET_MBTI_EMPTY(400, "TARGET_MBTI_EMPTY", "상대방의 mbti가 없습니다."); + USER_NOT_FOUND(404, "USER_NOT_FOUND", "사용자가 존재하지 않습니다."), + JWT_USER_NOT_FOUND(404, "JWT_USER_NOT_FOUND", "토큰에서 추출한 사용자가 존재하지 않습니다."), + CERTIFICATION_EXPIRED(400, "CERTIFICATION_EXPIRED", "인증 시간이 만료되었습니다."), + MISS_MATCH_CODE(400, "MISS_MATCH_CODE", "인증 번호가 일치하지 않습니다."), + USER_DUPLICATE(400, "USER_DUPLICATE", "중복된 사용자가 있습니다."), + HEART_USER_NOT_FOUND(404, "HEART_USER_NOT_FOUND", "찜한 사용자를 찾을 수 없습니다."), + FAIL_MAIL_SEND(400, "FAIL_MAIL_SEND", "메일 전송에 실패하였습니다."), + PASSWORD_MISMATCH(403, "PASSWORD_MISMATCH", "비밀번호가 일치하지 않습니다."), + HEART_USER_DUPLICATE(400, "HEART_USER_DUPLICATE", "찜한 사용자가 이미 존재합니다."); diff --git a/src/main/java/com/petmatz/domain/user/exception/MatchException.java b/src/main/java/com/petmatz/domain/user/exception/UserException.java similarity index 56% rename from src/main/java/com/petmatz/domain/user/exception/MatchException.java rename to src/main/java/com/petmatz/domain/user/exception/UserException.java index 30b8af0..cf4bfb9 100644 --- a/src/main/java/com/petmatz/domain/user/exception/MatchException.java +++ b/src/main/java/com/petmatz/domain/user/exception/UserException.java @@ -3,12 +3,12 @@ import com.petmatz.common.exception.BaseErrorCode; import com.petmatz.common.exception.DomainException; -public class MatchException extends DomainException { - public MatchException(BaseErrorCode errorCode, String message) { +public class UserException extends DomainException { + public UserException(BaseErrorCode errorCode, String message) { super(errorCode, message); } - public MatchException(BaseErrorCode errorCode) { + public UserException(BaseErrorCode errorCode) { super(errorCode); } } diff --git a/src/main/java/com/petmatz/domain/user/response/EditKakaoProfileResponseDto.java b/src/main/java/com/petmatz/domain/user/response/EditKakaoProfileResponseDto.java index b869f65..59cda5a 100644 --- a/src/main/java/com/petmatz/domain/user/response/EditKakaoProfileResponseDto.java +++ b/src/main/java/com/petmatz/domain/user/response/EditKakaoProfileResponseDto.java @@ -7,8 +7,7 @@ import org.springframework.http.ResponseEntity; public class EditKakaoProfileResponseDto extends LogInResponseDto { - private EditKakaoProfileResponseDto(){ - super(); + public EditKakaoProfileResponseDto(){ } public static ResponseEntity idNotFound(){ diff --git a/src/main/java/com/petmatz/domain/user/response/EmailCertificationResponseDto.java b/src/main/java/com/petmatz/domain/user/response/EmailCertificationResponseDto.java index 176d9eb..b75196b 100644 --- a/src/main/java/com/petmatz/domain/user/response/EmailCertificationResponseDto.java +++ b/src/main/java/com/petmatz/domain/user/response/EmailCertificationResponseDto.java @@ -11,8 +11,7 @@ @Getter public class EmailCertificationResponseDto extends LogInResponseDto { - private EmailCertificationResponseDto(){ - super(); + public EmailCertificationResponseDto(){ } diff --git a/src/main/java/com/petmatz/domain/user/response/GetMyProfileResponseDto.java b/src/main/java/com/petmatz/domain/user/response/GetMyProfileResponseDto.java index fcdee72..babccbe 100644 --- a/src/main/java/com/petmatz/domain/user/response/GetMyProfileResponseDto.java +++ b/src/main/java/com/petmatz/domain/user/response/GetMyProfileResponseDto.java @@ -30,7 +30,6 @@ public class GetMyProfileResponseDto extends LogInResponseDto { private Integer regionCode; public GetMyProfileResponseDto(User user) { - super(); this.id = user.getId(); this.accountId = user.getAccountId(); this.nickname = user.getNickname(); diff --git a/src/main/java/com/petmatz/domain/user/response/GetRecommendationResponseDto.java b/src/main/java/com/petmatz/domain/user/response/GetRecommendationResponseDto.java index 92f432a..9ed9899 100644 --- a/src/main/java/com/petmatz/domain/user/response/GetRecommendationResponseDto.java +++ b/src/main/java/com/petmatz/domain/user/response/GetRecommendationResponseDto.java @@ -11,8 +11,7 @@ public class GetRecommendationResponseDto extends LogInResponseDto { private boolean isRecommended; - private GetRecommendationResponseDto(boolean isRecommended) { - super(); + public GetRecommendationResponseDto(boolean isRecommended) { this.isRecommended=isRecommended; } diff --git a/src/main/java/com/petmatz/domain/user/response/KakaoGeocodingResponse.java b/src/main/java/com/petmatz/domain/user/response/KakaoGeocodingResponse.java new file mode 100644 index 0000000..0f28913 --- /dev/null +++ b/src/main/java/com/petmatz/domain/user/response/KakaoGeocodingResponse.java @@ -0,0 +1,11 @@ +package com.petmatz.domain.user.response; + +import com.petmatz.domain.user.entity.KakaoRegion; +import lombok.Data; + +import java.util.List; + +@Data +public class KakaoGeocodingResponse { + private List documents; +} diff --git a/src/main/java/com/petmatz/domain/user/response/SendRepasswordResponseDto.java b/src/main/java/com/petmatz/domain/user/response/SendRepasswordResponseDto.java index a8b8eeb..55d9208 100644 --- a/src/main/java/com/petmatz/domain/user/response/SendRepasswordResponseDto.java +++ b/src/main/java/com/petmatz/domain/user/response/SendRepasswordResponseDto.java @@ -10,8 +10,7 @@ @Getter public class SendRepasswordResponseDto extends LogInResponseDto{ - private SendRepasswordResponseDto(){ - super(); + public SendRepasswordResponseDto(){ } public static ResponseEntity mailSendFail(){ diff --git a/src/main/java/com/petmatz/domain/user/response/SignInResponseDto.java b/src/main/java/com/petmatz/domain/user/response/SignInResponseDto.java index a1e32bb..1ab41fc 100644 --- a/src/main/java/com/petmatz/domain/user/response/SignInResponseDto.java +++ b/src/main/java/com/petmatz/domain/user/response/SignInResponseDto.java @@ -31,7 +31,7 @@ public class SignInResponseDto extends LogInResponseDto { private String region; private Integer regionCode; - private SignInResponseDto(User user) { + public SignInResponseDto(User user) { super(); this.id = user.getId(); this.accountId = user.getAccountId(); @@ -48,14 +48,4 @@ private SignInResponseDto(User user) { this.region = user.getRegion(); this.regionCode=user.getRegionCode(); } - - public static ResponseEntity success(User user) { - SignInResponseDto responseBody = new SignInResponseDto(user); - return ResponseEntity.status(HttpStatus.OK).body(responseBody); - } - - public static ResponseEntity signInFail() { - LogInResponseDto responseBody = new LogInResponseDto(ResponseCode.SIGN_IN_FAIL, ResponseMessage.SIGN_IN_FAIL); - return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(responseBody); - } } \ No newline at end of file diff --git a/src/main/java/com/petmatz/domain/user/response/SignUpResponseDto.java b/src/main/java/com/petmatz/domain/user/response/SignUpResponseDto.java index 196babc..66ea037 100644 --- a/src/main/java/com/petmatz/domain/user/response/SignUpResponseDto.java +++ b/src/main/java/com/petmatz/domain/user/response/SignUpResponseDto.java @@ -13,7 +13,7 @@ public class SignUpResponseDto extends LogInResponseDto { private String imgURL; - private SignUpResponseDto(Long id, String imgURL) { + public SignUpResponseDto(Long id, String imgURL) { super(); this.id=id; this.imgURL = imgURL; diff --git a/src/main/java/com/petmatz/domain/user/response/UpdateLocationResponseDto.java b/src/main/java/com/petmatz/domain/user/response/UpdateLocationResponseDto.java index d247f36..d614f57 100644 --- a/src/main/java/com/petmatz/domain/user/response/UpdateLocationResponseDto.java +++ b/src/main/java/com/petmatz/domain/user/response/UpdateLocationResponseDto.java @@ -12,8 +12,7 @@ public class UpdateLocationResponseDto extends LogInResponseDto{ private String region; private Integer regionCode; - private UpdateLocationResponseDto(String region,Integer regionCode){ - super(); + public UpdateLocationResponseDto(String region, Integer regionCode){ this.region = region; this.regionCode=regionCode; } diff --git a/src/main/java/com/petmatz/domain/user/service/AuthService.java b/src/main/java/com/petmatz/domain/user/service/AuthService.java new file mode 100644 index 0000000..4d1bc78 --- /dev/null +++ b/src/main/java/com/petmatz/domain/user/service/AuthService.java @@ -0,0 +1,114 @@ +package com.petmatz.domain.user.service; + +import com.petmatz.common.security.utils.JwtProvider; +import com.petmatz.domain.aws.AwsClient; +import com.petmatz.domain.aws.vo.S3Imge; +import com.petmatz.domain.user.component.AuthenticationComponent; +import com.petmatz.domain.user.entity.Certification; +import com.petmatz.domain.user.entity.KakaoRegion; +import com.petmatz.domain.user.entity.User; +import com.petmatz.domain.user.entity.UserFactory; +import com.petmatz.domain.user.info.CheckCertificationInfo; +import com.petmatz.domain.user.info.SignInInfo; +import com.petmatz.domain.user.info.SignUpInfo; +import com.petmatz.domain.user.repository.CertificationRepository; +import com.petmatz.domain.user.repository.UserRepository; +import com.petmatz.domain.user.response.SignInResponseDto; +import com.petmatz.domain.user.response.SignUpResponseDto; +import com.petmatz.domain.user.component.GeocodingComponent; +import jakarta.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.http.ResponseCookie; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import javax.naming.AuthenticationException; +import java.net.MalformedURLException; +import java.security.cert.CertificateException; + +@Component +@RequiredArgsConstructor +@Slf4j +public class AuthService { + + /** + * awsClient -> 추후에 infra 로 옮길 예정 + * 현재 1차로 분리작업만 하는중 + */ + + private final UserRepository userRepository; + private final CertificationRepository certificationRepository; + private final GeocodingComponent geocodingComponent; + private final AwsClient awsClient; // 추후에 수정 + private final JwtProvider jwtProvider; + private final AuthenticationComponent authenticationComponent; + + private PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); + + @Transactional + public SignUpResponseDto signUp(SignUpInfo info) throws MalformedURLException { + String accountId = info.getAccountId(); + String certificationNumber = info.getCertificationNumber(); + String password = info.getPassword(); + + authenticationComponent.validateRequiredFields(accountId, certificationNumber, password); + authenticationComponent.validateCertification(accountId); + authenticationComponent.validateDuplicateAccountId(accountId); + + String encodedPassword = passwordEncoder.encode(info.getPassword()); + + // 지역명과 6자리 행정코드 가져오기 + KakaoRegion kakaoRegion = geocodingComponent.getValidRegion(info.getLatitude(), info.getLongitude()); + + //Img 정제 + S3Imge petImg = awsClient.UploadImg(info.getAccountId(), info.getProfileImg(), "CUSTOM_USER_IMG", null); + + //새로운 User 생성 및 저장 + User user = UserFactory.createNewUser(info, encodedPassword, kakaoRegion.getRegionName(), kakaoRegion.getCodeAsInteger(), petImg.uploadURL()); + userRepository.save(user); + + //인증 엔티티 삭제 + certificationRepository.deleteAllByAccountId(accountId); + + return new SignUpResponseDto(user.getId(), petImg.checkResultImg()); + } + + + public SignInResponseDto signIn(SignInInfo info, HttpServletResponse response) throws AuthenticationException { + User user = authenticationComponent.validateSignInCredentials(info); + String token = authenticationComponent.createJwtToken(user); + + ResponseCookie responseCookie = ResponseCookie.from("jwt", token) + .httpOnly(true) // XSS 방지 + .secure(true) // HTTPS만 허용 + .path("/") // 모든 경로에서 접근 가능 + .sameSite("None") // SameSite=None 설정 + .maxAge((3600)) + .build(); + response.addHeader("Set-Cookie", responseCookie.toString()); + // 로그인 성공 응답 반환 + return new SignInResponseDto(user); + } + + + public void logout(HttpServletResponse response) { // 예외 처리 + // 만료된 쿠키 설정 + ResponseCookie expiredCookie = ResponseCookie.from("jwt", "") + .httpOnly(true) // XSS 방지 + .secure(true) // HTTPS만 허용 + .path("/") // 모든 경로에서 접근 가능 + .sameSite("None") // SameSite=None 설정 + .maxAge(0) // 즉시 만료 + .build(); + response.addHeader("Set-Cookie", expiredCookie.toString()); + } + + @Transactional + public void checkCertification(CheckCertificationInfo info) throws CertificateException { + Certification certification = authenticationComponent.validateCertification(info); + authenticationComponent.updateCertificationStatus(certification); + } +} diff --git a/src/main/java/com/petmatz/domain/user/service/CustomOAuth2UserService.java b/src/main/java/com/petmatz/domain/user/service/CustomOAuth2UserService.java new file mode 100644 index 0000000..dd2e39b --- /dev/null +++ b/src/main/java/com/petmatz/domain/user/service/CustomOAuth2UserService.java @@ -0,0 +1,27 @@ +package com.petmatz.domain.user.service; + +import com.petmatz.domain.user.component.OAuth2UserLoader; +import lombok.RequiredArgsConstructor; +import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; +import org.springframework.security.oauth2.core.OAuth2AuthenticationException; +import org.springframework.security.oauth2.core.user.OAuth2User; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class CustomOAuth2UserService { + + private final List loaders; + + public OAuth2User loadUser(OAuth2UserRequest request) { + String registrationId = request.getClientRegistration().getRegistrationId(); + + return loaders.stream() + .filter(loader -> loader.supports(registrationId)) + .findFirst() + .orElseThrow(() -> new OAuth2AuthenticationException("지원되지 않는 id입니다 : " + registrationId)) + .loadUser(request); + } +} diff --git a/src/main/java/com/petmatz/domain/user/service/CustomOAuthUserService.java b/src/main/java/com/petmatz/domain/user/service/CustomOAuthUserService.java index e0a82ae..5ec17e2 100644 --- a/src/main/java/com/petmatz/domain/user/service/CustomOAuthUserService.java +++ b/src/main/java/com/petmatz/domain/user/service/CustomOAuthUserService.java @@ -1,75 +1,75 @@ -package com.petmatz.domain.user.service; - -import com.petmatz.domain.user.constant.LoginRole; -import com.petmatz.domain.user.constant.LoginType; -import com.petmatz.domain.user.entity.CustomOAuthUser; -import com.petmatz.domain.user.entity.User; -import com.petmatz.domain.user.repository.UserRepository; -import lombok.RequiredArgsConstructor; -import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService; -import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; -import org.springframework.security.oauth2.core.OAuth2AuthenticationException; -import org.springframework.security.oauth2.core.user.OAuth2User; -import org.springframework.stereotype.Service; - -import java.util.Map; - -@Service -@RequiredArgsConstructor -public class CustomOAuthUserService extends DefaultOAuth2UserService { - - private final UserRepository userRepository; - - @Override - public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException { - OAuth2User oAuth2User = super.loadUser(userRequest); - Map attributes = oAuth2User.getAttributes(); - - // 1. Check the registration ID (ensure it's Kakao) - String registrationId = userRequest.getClientRegistration().getRegistrationId(); - if (!"kakao".equals(registrationId)) { - throw new OAuth2AuthenticationException("Unsupported registrationId: " + registrationId); - } - - // 2. Extract attributes - String kakaoAccountId = attributes.get("id").toString(); // 고유 ID - Map kakaoAccount = (Map) attributes.get("kakao_account"); - - // Extract email (required for accountId) - String email = (String) kakaoAccount.get("email"); - if (email == null || email.isEmpty()) { - throw new OAuth2AuthenticationException("Email is required for Kakao login."); - } - - // Extract nickname - Map profile = (Map) kakaoAccount.get("profile"); - String nickname = (String) profile.getOrDefault("nickname", "Unknown User"); - - // Extract profile image (optional) - String profileImage = (String) profile.getOrDefault("profile_image_url", ""); - - // 3. Check if user exists or create new user - User user = userRepository.findByAccountId(email); - if (user == null) { - user = createNewKakaoUser(email, nickname, profileImage); // 신규 사용자 생성 - } - - // 4. Return CustomOAuthUser - return new CustomOAuthUser(user.getId(), user.getAccountId(), attributes, oAuth2User.getAuthorities()); - } - - private User createNewKakaoUser(String email, String nickname, String profileImage) { - User newUser = User.builder() - .accountId(email) // 이메일을 accountId에 저장 - .password("password") // 기본 비밀번호 설정 (필요시 변경) - .nickname(nickname) - .profileImg(profileImage) // 프로필 이미지 저장 - .loginRole(LoginRole.ROLE_USER) // 기본 역할 설정 - .loginType(LoginType.KAKAO) // 로그인 타입 - .careCompletionCount(0) - .recommendationCount(0) - .build(); - - return userRepository.save(newUser); - } -} \ No newline at end of file +//package com.petmatz.domain.user.service; +// +//import com.petmatz.domain.user.constant.LoginRole; +//import com.petmatz.domain.user.constant.LoginType; +//import com.petmatz.domain.user.entity.CustomOAuthUser; +//import com.petmatz.domain.user.entity.User; +//import com.petmatz.domain.user.repository.UserRepository; +//import lombok.RequiredArgsConstructor; +//import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService; +//import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; +//import org.springframework.security.oauth2.core.OAuth2AuthenticationException; +//import org.springframework.security.oauth2.core.user.OAuth2User; +//import org.springframework.stereotype.Service; +// +//import java.util.Map; +// +//@Service +//@RequiredArgsConstructor +//public class CustomOAuthUserService extends DefaultOAuth2UserService { +// +// private final UserRepository userRepository; +// +// @Override +// public OAuth2User loadUser(OAuth2UserRequest userRequest) throws OAuth2AuthenticationException { +// OAuth2User oAuth2User = super.loadUser(userRequest); +// Map attributes = oAuth2User.getAttributes(); +// +// // 1. Check the registration ID (ensure it's Kakao) +// String registrationId = userRequest.getClientRegistration().getRegistrationId(); +// if (!"kakao".equals(registrationId)) { +// throw new OAuth2AuthenticationException("Unsupported registrationId: " + registrationId); +// } +// +// // 2. Extract attributes +// String kakaoAccountId = attributes.get("id").toString(); // 고유 ID +// Map kakaoAccount = (Map) attributes.get("kakao_account"); +// +// // Extract email (required for accountId) +// String email = (String) kakaoAccount.get("email"); +// if (email == null || email.isEmpty()) { +// throw new OAuth2AuthenticationException("Email is required for Kakao login."); +// } +// +// // Extract nickname +// Map profile = (Map) kakaoAccount.get("profile"); +// String nickname = (String) profile.getOrDefault("nickname", "Unknown User"); +// +// // Extract profile image (optional) +// String profileImage = (String) profile.getOrDefault("profile_image_url", ""); +// +// // 3. Check if user exists or create new user +// User user = userRepository.findByAccountId(email); +// if (user == null) { +// user = createNewKakaoUser(email, nickname, profileImage); // 신규 사용자 생성 +// } +// +// // 4. Return CustomOAuthUser +// return new CustomOAuthUser(user.getId(), user.getAccountId(), attributes, oAuth2User.getAuthorities()); +// } +// +// private User createNewKakaoUser(String email, String nickname, String profileImage) { +// User newUser = User.builder() +// .accountId(email) // 이메일을 accountId에 저장 +// .password("password") // 기본 비밀번호 설정 (필요시 변경) +// .nickname(nickname) +// .profileImg(profileImage) // 프로필 이미지 저장 +// .loginRole(LoginRole.ROLE_USER) // 기본 역할 설정 +// .loginType(LoginType.KAKAO) // 로그인 타입 +// .careCompletionCount(0) +// .recommendationCount(0) +// .build(); +// +// return userRepository.save(newUser); +// } +//} \ No newline at end of file diff --git a/src/main/java/com/petmatz/domain/user/service/EmailProvider.java b/src/main/java/com/petmatz/domain/user/service/EmailProvider.java index a67349b..9e2d33c 100644 --- a/src/main/java/com/petmatz/domain/user/service/EmailProvider.java +++ b/src/main/java/com/petmatz/domain/user/service/EmailProvider.java @@ -1,5 +1,5 @@ package com.petmatz.domain.user.service; public interface EmailProvider { - boolean sendVerificationEmail(String email, String certificationNumber); + void sendVerificationEmail(String email, String certificationNumber); } diff --git a/src/main/java/com/petmatz/domain/user/service/EmailService.java b/src/main/java/com/petmatz/domain/user/service/EmailService.java new file mode 100644 index 0000000..fb11e4a --- /dev/null +++ b/src/main/java/com/petmatz/domain/user/service/EmailService.java @@ -0,0 +1,42 @@ +package com.petmatz.domain.user.service; + +import com.petmatz.api.user.request.EmailCertificationRequestDto; +import com.petmatz.domain.user.component.EmailComponent; +import com.petmatz.domain.user.component.UserUtils; +import com.petmatz.domain.user.entity.User; +import com.petmatz.domain.user.provider.CertificationNumberProvider; +import com.petmatz.domain.user.repository.UserRepository; +import com.petmatz.domain.user.response.GetMyUserDto; +import com.petmatz.domain.user.service.EmailProvider; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +@Slf4j +public class EmailService { + + private final EmailProvider emailProvider; + private final EmailComponent emailComponent; + private final UserUtils userUtils; + + + public void emailCertification(EmailCertificationRequestDto dto) { + String accountId = dto.getAccountId(); + + userUtils.checkDuplicateAccountId(accountId); + + // 인증 번호 생성 및 이메일 전송 + String certificationNumber = CertificationNumberProvider.generateNumber(); + emailProvider.sendVerificationEmail(accountId, certificationNumber); + + emailComponent.saveCertification(accountId, certificationNumber); + } + + + public GetMyUserDto receiverEmail(String accountId) { + User user = userUtils.findUser(accountId); + return new GetMyUserDto(user); + } +} diff --git a/src/main/java/com/petmatz/domain/user/service/HeartService.java b/src/main/java/com/petmatz/domain/user/service/HeartService.java new file mode 100644 index 0000000..fecbfdb --- /dev/null +++ b/src/main/java/com/petmatz/domain/user/service/HeartService.java @@ -0,0 +1,44 @@ +package com.petmatz.domain.user.service; + +import com.petmatz.api.user.request.HeartedUserDto; +import com.petmatz.api.user.request.HeartingRequestDto; +import com.petmatz.common.security.utils.JwtExtractProvider; +import com.petmatz.domain.user.component.HeartComponent; +import com.petmatz.domain.user.component.UserUtils; +import com.petmatz.domain.user.entity.User; +import com.petmatz.domain.user.repository.HeartRepository; +import com.petmatz.domain.user.repository.UserRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Component +@RequiredArgsConstructor +@Slf4j +public class HeartService { + + private final JwtExtractProvider jwtExtractProvider; + private final HeartComponent heartComponent; + private final UserUtils userUtils; + + + @Transactional + public void hearting(HeartingRequestDto dto) { + Long heartedId = dto.getHeartedId(); + Long userId = jwtExtractProvider.findIdFromJwt(); + + heartComponent.validateHeartUser(heartedId); + User currentUser = userUtils.getCurrentUser(userId); + heartComponent.toggleHeart(currentUser.getId(), heartedId); + } + + + public List getHeartedList() { + Long userId = jwtExtractProvider.findIdFromJwt(); + List heartedUsers = heartComponent.getHeartedUsers(userId); + return heartedUsers; + } +} diff --git a/src/main/java/com/petmatz/domain/user/service/KakaoUserService.java b/src/main/java/com/petmatz/domain/user/service/KakaoUserService.java new file mode 100644 index 0000000..e04dd27 --- /dev/null +++ b/src/main/java/com/petmatz/domain/user/service/KakaoUserService.java @@ -0,0 +1,64 @@ +package com.petmatz.domain.user.service; + +import com.petmatz.common.security.utils.JwtExtractProvider; +import com.petmatz.domain.user.component.GeocodingComponent; +import com.petmatz.domain.user.component.UserUtils; +import com.petmatz.domain.user.constant.LoginRole; +import com.petmatz.domain.user.constant.LoginType; +import com.petmatz.domain.user.entity.KakaoRegion; +import com.petmatz.domain.user.entity.User; +import com.petmatz.domain.user.exception.UserException; +import com.petmatz.domain.user.info.EditKakaoProfileInfo; +import com.petmatz.domain.user.repository.UserRepository; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import static com.petmatz.domain.user.exception.MatchErrorCode.*; + +@Component +@RequiredArgsConstructor +@Slf4j +public class KakaoUserService { + + /** + * 카카오 프로필 수정 어디다가 넣을지 고민중,,, + */ + + private final JwtExtractProvider jwtExtractProvider; + private final UserRepository userRepository; + private final GeocodingComponent geocodingComponent; + private final UserUtils userUtils; + + @Transactional + public void editKakaoProfile(EditKakaoProfileInfo info) { + Long userId = jwtExtractProvider.findIdFromJwt(); + userUtils.findJwtUser(userId); + userUtils.checkDuplicateId(userId); + User user = userUtils.findIdUser(userId); + + KakaoRegion kakaoRegion = geocodingComponent.getRegionFromCoordinates(info.getLatitude(), info.getLongitude()); + if (kakaoRegion == null || kakaoRegion.getCodeAsInteger() == null) { + throw new UserException(MISS_KAKAO_LOACTION); + } + + user.updateKakaoProfile(info, kakaoRegion.getRegionName(), kakaoRegion.getCodeAsInteger()); + } + + public User createNewKakaoUser(String kakaoAccountId, String email, String nickname, String profileImage) { + User newUser = User.builder() + .accountId(email) // 이메일을 accountId에 저장 + .registrationId(kakaoAccountId) + .password("password") // 기본 비밀번호 설정 (필요시 변경) + .nickname(nickname) + .profileImg(profileImage) // 프로필 이미지 저장 + .loginRole(LoginRole.ROLE_USER) // 기본 역할 설정 + .loginType(LoginType.KAKAO) // 로그인 타입 + .careCompletionCount(0) + .recommendationCount(0) + .build(); + + return userRepository.save(newUser); + } +} diff --git a/src/main/java/com/petmatz/domain/user/service/LocationService.java b/src/main/java/com/petmatz/domain/user/service/LocationService.java new file mode 100644 index 0000000..82649b1 --- /dev/null +++ b/src/main/java/com/petmatz/domain/user/service/LocationService.java @@ -0,0 +1,37 @@ +package com.petmatz.domain.user.service; + +import com.petmatz.common.security.utils.JwtExtractProvider; +import com.petmatz.domain.user.component.UserUtils; +import com.petmatz.domain.user.entity.KakaoRegion; +import com.petmatz.domain.user.entity.User; +import com.petmatz.domain.user.info.UpdateLocationInfo; +import com.petmatz.domain.user.response.UpdateLocationResponseDto; +import com.petmatz.domain.user.component.GeocodingComponent; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +@RequiredArgsConstructor +@Slf4j +public class LocationService { + + private final JwtExtractProvider jwtExtractProvider; + private final GeocodingComponent geocodingComponent; + private final UserUtils userUtils; + + @Transactional + public UpdateLocationResponseDto updateLocation(UpdateLocationInfo info) { + Long userId = jwtExtractProvider.findIdFromJwt(); + User user = userUtils.findIdUser(userId); + + /** + * 현재는 static 클래스라 이렇게 접근 + */ + KakaoRegion kakaoRegion = geocodingComponent.getValidRegion(info.getLatitude(), info.getLongitude()); + user.updateLocation(info, kakaoRegion.getRegionName(), kakaoRegion.getCodeAsInteger()); + + return new UpdateLocationResponseDto(kakaoRegion.getRegionName(), kakaoRegion.getCodeAsInteger()); + } +} diff --git a/src/main/java/com/petmatz/domain/user/service/PageService.java b/src/main/java/com/petmatz/domain/user/service/PageService.java new file mode 100644 index 0000000..add1de4 --- /dev/null +++ b/src/main/java/com/petmatz/domain/user/service/PageService.java @@ -0,0 +1,64 @@ +package com.petmatz.domain.user.service; + +import com.petmatz.common.security.utils.JwtExtractProvider; +import com.petmatz.domain.aws.AwsClient; +import com.petmatz.domain.aws.vo.S3Imge; +import com.petmatz.domain.user.component.UserUtils; +import com.petmatz.domain.user.entity.User; +import com.petmatz.domain.user.info.EditMyProfileInfo; +import com.petmatz.domain.user.repository.HeartRepository; +import com.petmatz.domain.user.repository.UserRepository; +import com.petmatz.domain.user.response.EditMyProfileResponseDto; +import com.petmatz.domain.user.response.GetMyProfileResponseDto; +import com.petmatz.domain.user.response.GetOtherProfileResponseDto; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +import java.net.MalformedURLException; + +@Component +@RequiredArgsConstructor +public class PageService { + + private final JwtExtractProvider jwtExtractProvider; + private final AwsClient awsClient; + private final UserUtils userUtils; + + + public GetMyProfileResponseDto getMypage() { + String userId = jwtExtractProvider.findAccountIdFromJwt(); + User user = userUtils.findUser(userId); + return new GetMyProfileResponseDto(user); + } + + public GetOtherProfileResponseDto getOtherMypage(Long userId) { + Long myId = jwtExtractProvider.findIdFromJwt(); + User user = userUtils.findIdUser(myId); + + // 조회 대상 사용자가 존재하는지 확인 + userUtils.findIdUser(userId); + + // 현재 로그인한 사용자가 조회 대상 사용자를 찜했는지 확인 + boolean checkHeart = userUtils.checkHeart(myId, userId); + + return new GetOtherProfileResponseDto(user, checkHeart); + } + + @Transactional + public EditMyProfileResponseDto editMyProfile(EditMyProfileInfo info) throws MalformedURLException { + Long userId = jwtExtractProvider.findIdFromJwt(); + String userEmail = jwtExtractProvider.findAccountIdFromJwt(); + User user = userUtils.findIdUser(userId); + + //Img 정제 + S3Imge petImg = awsClient.UploadImg(userEmail, info.getProfileImg(), "CUSTOM_USER_IMG", null); + + // 병합된 DTO를 기반으로 엔티티 생성 + String resultImg = user.updateImgURL(info.getProfileImg(), petImg); + user.updateProfile(info); + + return new EditMyProfileResponseDto(resultImg); + } +} diff --git a/src/main/java/com/petmatz/domain/user/service/PasswordService.java b/src/main/java/com/petmatz/domain/user/service/PasswordService.java new file mode 100644 index 0000000..87b3c35 --- /dev/null +++ b/src/main/java/com/petmatz/domain/user/service/PasswordService.java @@ -0,0 +1,58 @@ +package com.petmatz.domain.user.service; + +import com.petmatz.api.user.request.SendRepasswordRequestDto; +import com.petmatz.common.security.utils.JwtExtractProvider; +import com.petmatz.domain.user.component.PasswordComponent; +import com.petmatz.domain.user.component.UserUtils; +import com.petmatz.domain.user.entity.User; +import com.petmatz.domain.user.info.RepasswordInfo; +import com.petmatz.domain.user.provider.RePasswordProvider; +import com.petmatz.domain.user.response.RepasswordResponseDto; +import com.petmatz.domain.user.response.SendRepasswordResponseDto; +import com.petmatz.domain.user.service.RePasswordEmailProvider; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +@RequiredArgsConstructor +@Slf4j +public class PasswordService { + + private final RePasswordEmailProvider rePasswordEmailProvider; + private final JwtExtractProvider jwtExtractProvider; + private final UserUtils userUtils; + private final PasswordComponent passwordComponent; + + @Transactional + public SendRepasswordResponseDto sendRepassword(SendRepasswordRequestDto dto) { + String accountId = dto.getAccountId(); + User user = userUtils.findUser(accountId); + + String rePasswordNum = RePasswordProvider.generatePassword(); + + rePasswordEmailProvider.sendVerificationEmail(accountId, rePasswordNum); + String encodedRePasswordNum = passwordComponent.encodePassword(rePasswordNum); + user.updatePassword(encodedRePasswordNum); + + return new SendRepasswordResponseDto(); + } + + @Transactional + public void repassword(RepasswordInfo info) { + Long userId = jwtExtractProvider.findIdFromJwt(); + User user = userUtils.findIdUser(userId); + + String currentPassword = info.getCurrentPassword(); + passwordComponent.validatePassword(currentPassword, user.getPassword()); + + String newPassword = info.getNewPassword(); + + String encodedNewPassword = passwordComponent.encodePassword(newPassword); + user.updatePassword(encodedNewPassword); + } +} diff --git a/src/main/java/com/petmatz/domain/user/service/RePasswordEmailProvider.java b/src/main/java/com/petmatz/domain/user/service/RePasswordEmailProvider.java index 7bc19e8..c91d01a 100644 --- a/src/main/java/com/petmatz/domain/user/service/RePasswordEmailProvider.java +++ b/src/main/java/com/petmatz/domain/user/service/RePasswordEmailProvider.java @@ -1,5 +1,5 @@ package com.petmatz.domain.user.service; public interface RePasswordEmailProvider { - boolean sendVerificationEmail(String email, String rePassword); + void sendVerificationEmail(String email, String rePassword); } diff --git a/src/main/java/com/petmatz/domain/user/service/RecommendService.java b/src/main/java/com/petmatz/domain/user/service/RecommendService.java new file mode 100644 index 0000000..8e75cf6 --- /dev/null +++ b/src/main/java/com/petmatz/domain/user/service/RecommendService.java @@ -0,0 +1,48 @@ +package com.petmatz.domain.user.service; + +import com.petmatz.api.user.request.UpdateRecommendationRequestDto; +import com.petmatz.common.security.utils.JwtExtractProvider; +import com.petmatz.domain.user.component.RecommendComponent; +import com.petmatz.domain.user.component.UserUtils; +import com.petmatz.domain.user.entity.Recommendation; +import com.petmatz.domain.user.entity.User; +import com.petmatz.domain.user.entity.UserFactory; +import com.petmatz.domain.user.repository.RecommendationRepository; +import com.petmatz.domain.user.response.GetRecommendationResponseDto; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +@RequiredArgsConstructor +@Slf4j +public class RecommendService { + + private final JwtExtractProvider jwtExtractProvider; + private final RecommendationRepository recommendationRepository; + private final UserUtils userUtils; + private final RecommendComponent recommendComponent; + + @Transactional + public void updateRecommend(UpdateRecommendationRequestDto dto) { + Long recommendedId = dto.getUserId(); + Long myId = jwtExtractProvider.findIdFromJwt(); + User recommendedUser = userUtils.findIdUser(recommendedId); + + Integer recommendationCount = recommendedUser.getRecommendationCount() + 1; + + recommendedUser.updateRecommendation(recommendationCount); + + Recommendation recommendation = UserFactory.createRecommendation(myId, recommendedId); + recommendationRepository.save(recommendation); + } + + public GetRecommendationResponseDto getRecommend(UpdateRecommendationRequestDto dto) { + Long recommendedId = dto.getUserId(); + Long myId = jwtExtractProvider.findIdFromJwt(); + + boolean recommendUser = recommendComponent.validateRecommendUser(myId, recommendedId); + return new GetRecommendationResponseDto(recommendUser); + } +} diff --git a/src/main/java/com/petmatz/domain/user/service/UserService.java b/src/main/java/com/petmatz/domain/user/service/UserService.java index 694df81..a6166a7 100644 --- a/src/main/java/com/petmatz/domain/user/service/UserService.java +++ b/src/main/java/com/petmatz/domain/user/service/UserService.java @@ -8,23 +8,22 @@ import org.springframework.http.ResponseEntity; public interface UserService { - ResponseEntity emailCertification(EmailCertificationRequestDto dto); - ResponseEntity checkCertification(CheckCertificationInfo info); - ResponseEntity signUp(SignUpInfo info); - ResponseEntity signIn(SignInInfo info, HttpServletResponse response); - ResponseEntity logout(HttpServletResponse response); - ResponseEntity deleteId(DeleteIdRequestDto dto); - ResponseEntity getMypage(); - ResponseEntity getOtherMypage(Long userId); - ResponseEntity sendRepassword(SendRepasswordRequestDto dto); - ResponseEntity repassword(RepasswordInfo info); - ResponseEntity editMyProfile(EditMyProfileInfo info); - ResponseEntity hearting(HeartingRequestDto dto); - ResponseEntity getHeartedList(); - ResponseEntity updateLocation(UpdateLocationInfo info); - ResponseEntity updateRecommend(UpdateRecommendationRequestDto dto); - ResponseEntity editKakaoProfile(EditKakaoProfileInfo of); - +// ResponseEntity emailCertification(EmailCertificationRequestDto dto); +// ResponseEntity checkCertification(CheckCertificationInfo info); +// ResponseEntity signUp(SignUpInfo info); +// ResponseEntity signIn(SignInInfo info, HttpServletResponse response); +// ResponseEntity logout(HttpServletResponse response); +// ResponseEntity deleteId(DeleteIdRequestDto dto); +// ResponseEntity getMypage(); +// ResponseEntity getOtherMypage(Long userId); +// ResponseEntity sendRepassword(SendRepasswordRequestDto dto); +// ResponseEntity repassword(RepasswordInfo info); +// ResponseEntity editMyProfile(EditMyProfileInfo info); +// ResponseEntity hearting(HeartingRequestDto dto); +// ResponseEntity getHeartedList(); +// ResponseEntity updateLocation(UpdateLocationInfo info); +// ResponseEntity updateRecommend(UpdateRecommendationRequestDto dto); +// ResponseEntity editKakaoProfile(EditKakaoProfileInfo of); String findByUserEmail(Long userId); diff --git a/src/main/java/com/petmatz/domain/user/service/UserServiceImpl.java b/src/main/java/com/petmatz/domain/user/service/UserServiceImpl.java index 419bb3c..dc09236 100644 --- a/src/main/java/com/petmatz/domain/user/service/UserServiceImpl.java +++ b/src/main/java/com/petmatz/domain/user/service/UserServiceImpl.java @@ -1,621 +1,622 @@ -package com.petmatz.domain.user.service; - -import com.petmatz.api.user.request.*; -import com.petmatz.common.security.utils.JwtExtractProvider; -import com.petmatz.common.security.utils.JwtProvider; -import com.petmatz.domain.aws.AwsClient; -import com.petmatz.domain.aws.vo.S3Imge; -import com.petmatz.domain.pet.entity.Pet; -import com.petmatz.domain.pet.repository.PetRepository; -import com.petmatz.domain.user.entity.*; -import com.petmatz.domain.user.info.*; -import com.petmatz.domain.user.provider.CertificationNumberProvider; -import com.petmatz.domain.user.provider.RePasswordProvider; -import com.petmatz.domain.user.repository.CertificationRepository; -import com.petmatz.domain.user.repository.HeartRepository; -import com.petmatz.domain.user.repository.RecommendationRepository; -import com.petmatz.domain.user.repository.UserRepository; -import com.petmatz.domain.user.response.*; -import com.petmatz.user.common.LogInResponseDto; -import jakarta.servlet.http.HttpServletResponse; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.springframework.http.ResponseCookie; -import org.springframework.http.ResponseEntity; -import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; -import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -import java.time.LocalDateTime; -import java.util.List; -import java.util.Optional; - -@Service -@Slf4j -@RequiredArgsConstructor -public class UserServiceImpl implements UserService { - - private final UserRepository userRepository; - private final CertificationRepository certificationRepository; - private final HeartRepository heartRepository; - private final RecommendationRepository recommendationRepository; - private final JwtProvider jwtProvider; - private final EmailProvider emailProvider; - private final RePasswordEmailProvider rePasswordEmailProvider; - private final PetRepository petRepository; - - private PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); - private final JwtExtractProvider jwtExtractProvider; - - private final GeocodingService geocodingService; - - private final AwsClient awsClient; - - - @Override - public ResponseEntity emailCertification(EmailCertificationRequestDto dto) { - try { - String accountId = dto.getAccountId(); - - //이메일 전송과 동시에 아이디 중복검사 - boolean isExistId = userRepository.existsByAccountId(accountId); - if (isExistId) return EmailCertificationResponseDto.duplicateId(); - - // 인증 번호 생성 및 이메일 전송 - String certificationNumber = CertificationNumberProvider.generateNumber(); - boolean isSendSuccess = emailProvider.sendVerificationEmail(accountId, certificationNumber); - if (!isSendSuccess) return EmailCertificationResponseDto.mailSendFail(); - - // 인증 엔티티 저장 - Certification certification = Certification.builder().accountId(accountId).certificationNumber(certificationNumber).isVerified(false).build(); - certificationRepository.save(certification); - - } catch (Exception e) { - log.info("이메일 인증 실패: {}", e); - return EmailCertificationResponseDto.databaseError(); - } - return EmailCertificationResponseDto.success(); - } - - - @Override - @Transactional - public ResponseEntity checkCertification(CheckCertificationInfo info) { - try { - String accountId = info.getAccountId(); - String certificationNumber = info.getCertificationNumber(); - - Certification certification = certificationRepository.findTopByAccountIdOrderByCreatedAtDesc(accountId); - if (certification == null) return CheckCertificationResponseDto.certificationFail(); - - boolean isMatch = certification.getAccountId().equals(accountId) - && certification.getCertificationNumber().equals(certificationNumber); - - if (!isMatch) return CheckCertificationResponseDto.certificationFail(); - - // 인증 시간 검증 - LocalDateTime createdAt = certification.getCreatedAt(); - if (createdAt.isBefore(LocalDateTime.now().minusMinutes(5))) { // 5분 유효시간 - return CheckCertificationResponseDto.certificationExpired(); - } - - // 인증 완료 상태 업데이트 - certification.markAsVerified(); - certificationRepository.save(certification); - - } catch (Exception e) { - log.info("인증 번호 확인 실패: {}", e); - return CheckCertificationResponseDto.databaseError(); - } - - return CheckCertificationResponseDto.success(); - } - - - @Override - @Transactional - public ResponseEntity signUp(SignUpInfo info) { - try { - String accountId = info.getAccountId(); - String certificationNumber = info.getCertificationNumber(); - - // 1. 필수 정보 누락 확인 - if (accountId == null || certificationNumber == null || info.getPassword() == null) { - return SignUpResponseDto.missingRequiredFields(); - } - - // 2. 인증 번호 확인 - Certification certification = certificationRepository.findTopByAccountIdOrderByCreatedAtDesc(accountId); - if (certification == null || !certification.getIsVerified()) { - return SignUpResponseDto.certificationFail(); // 인증되지 않은 경우 - } - - // 3. 중복된 ID 확인 - if (userRepository.existsByAccountId(accountId)) { - return SignUpResponseDto.duplicateId(); - } - - // 5. 비밀번호 암호화 후 저장 - String encodedPassword = passwordEncoder.encode(info.getPassword()); - - // 6. GeocodingService를 통해 지역명과 6자리 행정코드 가져오기 - GeocodingService.KakaoRegion kakaoRegion = geocodingService.getRegionFromCoordinates(info.getLatitude(), info.getLongitude()); - if (kakaoRegion == null || kakaoRegion.getCodeAsInteger() == null) { - return SignUpResponseDto.locationFail(); - } - - //6-1 Img 정제 - S3Imge petImg = awsClient.UploadImg(info.getAccountId(), info.getProfileImg(), "CUSTOM_USER_IMG", null); - - // 7. 새로운 User 생성 및 저장 - User user = UserFactory.createNewUser(info, encodedPassword, kakaoRegion.getRegionName(), kakaoRegion.getCodeAsInteger(), petImg.uploadURL()); - userRepository.save(user); - - // 8. 인증 엔티티 삭제 - certificationRepository.deleteAllByAccountId(accountId); - - // 9. 성공 응답 반환 - return SignUpResponseDto.success(user.getId(), petImg.checkResultImg()); - - } catch (RuntimeException e) { - log.error("회원 가입 실패: {}", e.getMessage(), e); - throw e; - } catch (Exception e) { - log.error("회원 가입 중 처리되지 않은 예외 발생: {}", e.getMessage(), e); - return SignUpResponseDto.unknownError(); - } - } - - - @Override - public ResponseEntity signIn(SignInInfo info, HttpServletResponse response) { - try { - String accountId = info.getAccountId(); - User user = userRepository.findByAccountId(accountId); - // 사용자 존재 여부 확인 - if (user == null) { - log.info("사용자 조회 실패: {}", accountId); - return SignInResponseDto.signInFail(); - } - - // 비밀번호 확인 - String password = info.getPassword(); - String encodedPassword = user.getPassword(); - if (!passwordEncoder.matches(password, encodedPassword)) { - log.info("비밀번호 불일치: {}", accountId); - return SignInResponseDto.signInFail(); - } - - // JWT 생성 (userId를 subject로, accountId를 클레임으로 설정) - String token = jwtProvider.create(user.getId(), user.getAccountId()); - log.info("JWT 생성 완료: {}", token); - - ResponseCookie responseCookie = ResponseCookie.from("jwt", token) - .httpOnly(true) // XSS 방지 - .secure(true) // HTTPS만 허용 - .path("/") // 모든 경로에서 접근 가능 - .sameSite("None") // SameSite=None 설정 - .maxAge((3600)) - .build(); - response.addHeader("Set-Cookie", responseCookie.toString()); - // 로그인 성공 응답 반환 - return SignInResponseDto.success(user); // User 객체 전달 - } catch (Exception e) { - log.error("로그인 처리 중 예외 발생", e); - return SignInResponseDto.signInFail(); - } - } - - - @Override - public ResponseEntity logout(HttpServletResponse response) { - try { - // 만료된 쿠키 설정 - ResponseCookie expiredCookie = ResponseCookie.from("jwt", "") - .httpOnly(true) // XSS 방지 - .secure(true) // HTTPS만 허용 - .path("/") // 모든 경로에서 접근 가능 - .sameSite("None") // SameSite=None 설정 - .maxAge(0) // 즉시 만료 - .build(); - - response.addHeader("Set-Cookie", expiredCookie.toString()); - - log.info("JWT 쿠키 제거 및 로그아웃 처리 완료"); - return LogInResponseDto.success(); - } catch (Exception e) { - log.error("로그아웃 처리 중 예외 발생", e); - return LogInResponseDto.validationFail(); - } - } - - - @Override - @Transactional - public ResponseEntity deleteId(DeleteIdRequestDto dto) { - try { - Long userId = jwtExtractProvider.findIdFromJwt(); - boolean exists = userRepository.existsById(userId); - if (!exists) { - return DeleteIdResponseDto.idNotFound(); - } - - User user = userRepository.findById(userId) - .orElseThrow(() -> new IllegalArgumentException("User not found for ID: " + userId)); - - - // 비밀번호 일치 확인 - String password = dto.getPassword(); - String encodedPassword = user.getPassword(); - boolean isMatched = passwordEncoder.matches(password, encodedPassword); - if (!isMatched) return DeleteIdResponseDto.wrongPassword(); // 비밀번호 불일치 - - certificationRepository.deleteById(userId); - // 사용자 삭제 - List pets = petRepository.findAllByUserId(user.getId()); // Pet 엔티티에서 User를 참조하는 기준으로 조회 - // 명시적으로 Pet 삭제 - petRepository.deleteAll(pets); - userRepository.delete(user); - } catch (Exception e) { - log.info("회원 삭제 실패: {}", e); - return DeleteIdResponseDto.databaseError(); // 데이터베이스 오류 처리 - } - return DeleteIdResponseDto.success(); // 삭제 성공 응답 - } - - - @Override - public ResponseEntity getMypage() { - try { - String userId = jwtExtractProvider.findAccountIdFromJwt(); - User user = userRepository.findByAccountId(userId); - - boolean exists = userRepository.existsByAccountId(userId); - if (!exists) { - return GetMyProfileResponseDto.idNotFound(); - } - - return GetMyProfileResponseDto.success(user); - - } catch (Exception e) { - e.printStackTrace(); - return GetMyProfileResponseDto.databaseError(); - } - } - - - @Override - public ResponseEntity getOtherMypage(Long userId) { - try { - // 현재 로그인한 사용자 ID 가져오기 - Long myId = jwtExtractProvider.findIdFromJwt(); - if (!userRepository.existsById(myId)) { - return GetMyProfileResponseDto.idNotFound(); - } - - // 조회 대상 사용자 정보 가져오기 - User user = userRepository.findById(userId) - .orElseThrow(() -> new IllegalArgumentException("User not found for ID: " + userId)); - - // 조회 대상 사용자가 존재하는지 확인 - boolean exists = userRepository.existsById(userId); - if (!exists) { - return GetOtherProfileResponseDto.userNotFound(); - } - - // 현재 로그인한 사용자가 조회 대상 사용자를 찜했는지 확인 - boolean isMyHeartUser = heartRepository.existsByMyIdAndHeartedId(myId, userId); - - // 응답 생성 - return GetOtherProfileResponseDto.success(user, isMyHeartUser); - - } catch (Exception e) { - e.printStackTrace(); - return GetOtherProfileResponseDto.userNotFound(); - } - } - - - //TODO 고쳐야함. - @Override - @Transactional - public ResponseEntity editMyProfile(EditMyProfileInfo info) { - try { - System.out.println("info ::" + info.isCareAvailable()); - Long userId = jwtExtractProvider.findIdFromJwt(); - String userEmail = jwtExtractProvider.findAccountIdFromJwt(); - boolean exists = userRepository.existsById(userId); - if (!exists) { - return EditMyProfileResponseDto.idNotFound(); - } - - User user = userRepository.findById(userId) - .orElseThrow(() -> new IllegalArgumentException("User not found for ID: " + userId)); - - //6-1 Img 정제 - S3Imge petImg = awsClient.UploadImg(userEmail, info.getProfileImg(), "CUSTOM_USER_IMG", null); - - // 병합된 DTO를 기반으로 엔티티 생성 - String resultImg = user.updateImgURL(info.getProfileImg(), petImg); - user.updateProfile(info); - -// 반환해야 함 아래꺼 - return EditMyProfileResponseDto.success(resultImg); - - } catch (Exception e) { - log.info("프로필 수정 실패: {}", e); - return EditMyProfileResponseDto.editFailed(); - } - } - - - @Override - @Transactional - public ResponseEntity hearting(HeartingRequestDto dto) { - try { - Long heartedId = dto.getHeartedId(); - - // 대상 사용자가 존재하는지 확인 - boolean exists = userRepository.existsById(heartedId); - if (!exists) { - return HeartingResponseDto.heartedIdNotFound(); - } - - // 현재 사용자 ID 가져오기 - Long userId = jwtExtractProvider.findIdFromJwt(); - User user = userRepository.findById(userId) - .orElseThrow(() -> new IllegalArgumentException("User not found for ID: " + userId)); - - // DB에서 myId와 heartedId로 Heart 레코드 확인 - Optional existingHeart = heartRepository.findByMyIdAndHeartedId(user.getId(), heartedId); - - if (existingHeart.isPresent()) { - // 찜하기 해제 (DB에서 삭제) - heartRepository.delete(existingHeart.get()); - return HeartingResponseDto.success(); // 찜하기 해제 성공 응답 - } - - // 찜하기 진행 (DB에 저장) - Heart heart = UserFactory.createHeart(userId, heartedId); - heartRepository.save(heart); - - return HeartingResponseDto.success(); // 찜하기 성공 응답 - - } catch (Exception e) { - log.info("찜하기 실패: {}", e); - return HeartingResponseDto.databaseError(); // 데이터베이스 오류 응답 - } - } - - - @Override - public ResponseEntity getHeartedList() { - try { - Long userId = jwtExtractProvider.findIdFromJwt(); - User user = userRepository.findById(userId) - .orElseThrow(() -> new IllegalArgumentException("User not found for ID: " + userId)); - - // Heart 리스트 조회 - List heartList = heartRepository.findAllByMyId(user.getId()); - - // Heart 정보와 관련된 User 데이터 매핑 - List heartedUsers = heartList.stream() - .map(heart -> { - User heartedUser = userRepository.findById(heart.getHeartedId()) - .orElseThrow(() -> new IllegalArgumentException("User not found for ID: " + heart.getHeartedId())); - - return new HeartedUserDto( - heart.getMyId(), - heart.getHeartedId(), - heartedUser.getNickname(), - heartedUser.getProfileImg(), - heartedUser.getCareAvailable(), - heartedUser.getPreferredSizes() - ); - }) - .toList(); - - // 성공 응답 반환 - return GetHeartingListResponseDto.success(heartedUsers); - - } catch (Exception e) { - log.info("찜리스트 받아오기 실패: {}", e); - return HeartingResponseDto.databaseError(); - } - } - - - @Override - @Transactional - public ResponseEntity sendRepassword(SendRepasswordRequestDto dto) { - try { - String accountId = dto.getAccountId(); - if (!userRepository.existsByAccountId(accountId)) { - return GetMyProfileResponseDto.idNotFound(); - } - User user = userRepository.findByAccountId(accountId); - - String rePasswordNum = RePasswordProvider.generatePassword(); - log.info("Generated Repassword: {}", rePasswordNum); - - boolean isSendSuccess = rePasswordEmailProvider.sendVerificationEmail(accountId, rePasswordNum); - if (!isSendSuccess) return SendRepasswordResponseDto.mailSendFail(); - - String encodedRePasswordNum = passwordEncoder.encode(rePasswordNum); - - user.updatePassword(encodedRePasswordNum); - - } catch (Exception e) { - log.info("임시비밀번호 재설정 실패: {}", e); - return SendRepasswordResponseDto.databaseError(); - } - return SendRepasswordResponseDto.success(); - } - - - @Override - @Transactional - public ResponseEntity repassword(RepasswordInfo info) { - try { - Long userId = jwtExtractProvider.findIdFromJwt(); - User user = userRepository.findById(userId) - .orElseThrow(() -> new IllegalArgumentException("User not found for ID: " + userId)); - - String currentPassword = info.getCurrentPassword(); - - boolean isPasswordValid = passwordEncoder.matches(currentPassword, user.getPassword()); - if (!isPasswordValid) { - return RepasswordResponseDto.wrongPassword(); - } - String newPassword = info.getNewPassword(); - - String encodedNewPassword = passwordEncoder.encode(newPassword); - - user.updatePassword(encodedNewPassword); - - } catch (Exception e) { - log.info("비밀번호 재설정 실패: {}", e); - return RepasswordResponseDto.databaseError(); - } - return RepasswordResponseDto.success(); - } - - - @Override - @Transactional - public ResponseEntity updateLocation(UpdateLocationInfo info) { - try { - // JWT에서 사용자 ID 추출 - Long userId = jwtExtractProvider.findIdFromJwt(); - - // 사용자 엔티티 조회 - User user = userRepository.findById(userId) - .orElseThrow(() -> new IllegalArgumentException("User not found for ID: " + userId)); - - // 사용자 존재 여부 확인 - boolean exists = userRepository.existsById(userId); - if (!exists) { - return UpdateLocationResponseDto.userNotFound(); - } - - // GeocodingService에서 지역명과 행정코드 가져오기 - GeocodingService.KakaoRegion kakaoRegion = geocodingService.getRegionFromCoordinates(info.getLatitude(), info.getLongitude()); - if (kakaoRegion == null || kakaoRegion.getCodeAsInteger() == null) { - return UpdateLocationResponseDto.wrongLocation(); // Kakao API 호출 실패 처리 - } - - user.updateLocation(info, kakaoRegion.getRegionName(), kakaoRegion.getCodeAsInteger()); - - // 성공 응답 반환 - return UpdateLocationResponseDto.success(kakaoRegion.getRegionName(), kakaoRegion.getCodeAsInteger()); - } catch (Exception e) { - log.error("위치 업데이트 실패: {}", e.getMessage(), e); - return UpdateLocationResponseDto.wrongLocation(); - } - } - - @Override - @Transactional - public ResponseEntity updateRecommend(UpdateRecommendationRequestDto dto) { - try { - Long recommendedId = dto.getUserId(); - Long myId = jwtExtractProvider.findIdFromJwt(); - User recommendedUser = userRepository.findById(recommendedId) - .orElseThrow(() -> new IllegalArgumentException("User not found for ID: " + recommendedId)); - - boolean exists = userRepository.existsById(recommendedId); - if (!exists) { - return UpdateRecommendationResponseDto.userNotFound(); - } - Integer recommendationCount = recommendedUser.getRecommendationCount() + 1; - - recommendedUser.updateRecommendation(recommendationCount); - - Recommendation recommendation = UserFactory.createRecommendation(myId, recommendedId); - recommendationRepository.save(recommendation); - - } catch (Exception e) { - log.info("추천수 업데이트 실패: {}", e); - return UpdateRecommendationResponseDto.userNotFound(); - } - return UpdateRecommendationResponseDto.success(); - } - - @Override - public ResponseEntity getRecommend(UpdateRecommendationRequestDto dto) { - try { - Long recommendedId = dto.getUserId(); - Long myId = jwtExtractProvider.findIdFromJwt(); - - boolean exists = recommendationRepository.existsByMyIdAndRecommendedId(myId,recommendedId); - return GetRecommendationResponseDto.success(exists); - - } catch (Exception e) { - log.info("추천수 업데이트 실패: {}", e); - return GetRecommendationResponseDto.userNotFound(); - } - } - - @Override - @Transactional - public ResponseEntity editKakaoProfile(EditKakaoProfileInfo info) { - try { - Long userId = jwtExtractProvider.findIdFromJwt(); - - // userId가 null인 경우 예외 처리 - if (userId == null) { - log.warn("JWT에서 추출된 userId가 null입니다."); - return EditKakaoProfileResponseDto.idNotFound(); - } - - boolean exists = userRepository.existsById(userId); - if (!exists) { - log.warn("존재하지 않는 사용자 ID: {}", userId); - return EditKakaoProfileResponseDto.idNotFound(); - } - - User user = userRepository.findById(userId) - .orElseThrow(() -> new IllegalArgumentException("User not found for ID: " + userId)); - - GeocodingService.KakaoRegion kakaoRegion = geocodingService.getRegionFromCoordinates(info.getLatitude(), info.getLongitude()); - if (kakaoRegion == null || kakaoRegion.getCodeAsInteger() == null) { - return UpdateLocationResponseDto.wrongLocation(); // Kakao API 호출 실패 처리 - } - - user.updateKakaoProfile(info, kakaoRegion.getRegionName(), kakaoRegion.getCodeAsInteger()); - } catch (Exception e) { - log.error("프로필 수정 실패", e); - return EditKakaoProfileResponseDto.editFailed(); - } - return EditKakaoProfileResponseDto.success(); - } - - @Override - public GetMyUserDto receiverEmail(String accountId) { - try { - User user = userRepository.findByAccountId(accountId); - return new GetMyUserDto(user); - } catch (Exception e) { - e.printStackTrace(); - } - return new GetMyUserDto(); - } - - @Override - public void deleteUser(Long userUUID) { - userRepository.deleteUserById(userUUID); - } - - - public UserInfo selectUserInfo(String receiverEmail) { - User otherUser = userRepository.findByAccountId(receiverEmail); - return otherUser.of(); - } - - @Override - public String findByUserEmail(Long userId) { - return userRepository.findById(userId).get().getAccountId(); - } - -} +//package com.petmatz.domain.user.service; +// +//import com.petmatz.api.user.request.*; +//import com.petmatz.common.security.utils.JwtExtractProvider; +//import com.petmatz.common.security.utils.JwtProvider; +//import com.petmatz.domain.aws.AwsClient; +//import com.petmatz.domain.aws.vo.S3Imge; +//import com.petmatz.domain.pet.entity.Pet; +//import com.petmatz.domain.pet.repository.PetRepository; +//import com.petmatz.domain.user.component.GeocodingComponent; +//import com.petmatz.domain.user.entity.*; +//import com.petmatz.domain.user.info.*; +//import com.petmatz.domain.user.provider.CertificationNumberProvider; +//import com.petmatz.domain.user.provider.RePasswordProvider; +//import com.petmatz.domain.user.repository.CertificationRepository; +//import com.petmatz.domain.user.repository.HeartRepository; +//import com.petmatz.domain.user.repository.RecommendationRepository; +//import com.petmatz.domain.user.repository.UserRepository; +//import com.petmatz.domain.user.response.*; +//import com.petmatz.user.common.LogInResponseDto; +//import jakarta.servlet.http.HttpServletResponse; +//import lombok.RequiredArgsConstructor; +//import lombok.extern.slf4j.Slf4j; +//import org.springframework.http.ResponseCookie; +//import org.springframework.http.ResponseEntity; +//import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; +//import org.springframework.security.crypto.password.PasswordEncoder; +//import org.springframework.stereotype.Service; +//import org.springframework.transaction.annotation.Transactional; +// +//import java.time.LocalDateTime; +//import java.util.List; +//import java.util.Optional; +// +//@Service +//@Slf4j +//@RequiredArgsConstructor +//public class UserServiceImpl implements UserService { +// +// private final UserRepository userRepository; +// private final CertificationRepository certificationRepository; +// private final HeartRepository heartRepository; +// private final RecommendationRepository recommendationRepository; +// private final JwtProvider jwtProvider; +// private final EmailProvider emailProvider; +// private final RePasswordEmailProvider rePasswordEmailProvider; +// private final PetRepository petRepository; +// +// private PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(); +// private final JwtExtractProvider jwtExtractProvider; +// +// private final GeocodingComponent geocodingComponent; +// +// private final AwsClient awsClient; +// +// +// @Override +// public ResponseEntity emailCertification(EmailCertificationRequestDto dto) { +// try { +// String accountId = dto.getAccountId(); +// +// //이메일 전송과 동시에 아이디 중복검사 +// boolean isExistId = userRepository.existsByAccountId(accountId); +// if (isExistId) return EmailCertificationResponseDto.duplicateId(); +// +// // 인증 번호 생성 및 이메일 전송 +// String certificationNumber = CertificationNumberProvider.generateNumber(); +// boolean isSendSuccess = emailProvider.sendVerificationEmail(accountId, certificationNumber); +// if (!isSendSuccess) return EmailCertificationResponseDto.mailSendFail(); +// +// // 인증 엔티티 저장 +// Certification certification = Certification.builder().accountId(accountId).certificationNumber(certificationNumber).isVerified(false).build(); +// certificationRepository.save(certification); +// +// } catch (Exception e) { +// log.info("이메일 인증 실패: {}", e); +// return EmailCertificationResponseDto.databaseError(); +// } +// return EmailCertificationResponseDto.success(); +// } +// +// +// @Override +// @Transactional +// public ResponseEntity checkCertification(CheckCertificationInfo info) { +// try { +// String accountId = info.getAccountId(); +// String certificationNumber = info.getCertificationNumber(); +// +// Certification certification = certificationRepository.findTopByAccountIdOrderByCreatedAtDesc(accountId); +// if (certification == null) return CheckCertificationResponseDto.certificationFail(); +// +// boolean isMatch = certification.getAccountId().equals(accountId) +// && certification.getCertificationNumber().equals(certificationNumber); +// +// if (!isMatch) return CheckCertificationResponseDto.certificationFail(); +// +// // 인증 시간 검증 +// LocalDateTime createdAt = certification.getCreatedAt(); +// if (createdAt.isBefore(LocalDateTime.now().minusMinutes(5))) { // 5분 유효시간 +// return CheckCertificationResponseDto.certificationExpired(); +// } +// +// // 인증 완료 상태 업데이트 +// certification.markAsVerified(); +// certificationRepository.save(certification); +// +// } catch (Exception e) { +// log.info("인증 번호 확인 실패: {}", e); +// return CheckCertificationResponseDto.databaseError(); +// } +// +// return CheckCertificationResponseDto.success(); +// } +// +// +// @Override +// @Transactional +// public ResponseEntity signUp(SignUpInfo info) { +// try { +// String accountId = info.getAccountId(); +// String certificationNumber = info.getCertificationNumber(); +// +// // 1. 필수 정보 누락 확인 +// if (accountId == null || certificationNumber == null || info.getPassword() == null) { +// return SignUpResponseDto.missingRequiredFields(); +// } +// +// // 2. 인증 번호 확인 +// Certification certification = certificationRepository.findTopByAccountIdOrderByCreatedAtDesc(accountId); +// if (certification == null || !certification.getIsVerified()) { +// return SignUpResponseDto.certificationFail(); // 인증되지 않은 경우 +// } +// +// // 3. 중복된 ID 확인 +// if (userRepository.existsByAccountId(accountId)) { +// return SignUpResponseDto.duplicateId(); +// } +// +// // 5. 비밀번호 암호화 후 저장 +// String encodedPassword = passwordEncoder.encode(info.getPassword()); +// +// // 6. GeocodingService를 통해 지역명과 6자리 행정코드 가져오기 +// GeocodingComponent.KakaoRegion kakaoRegion = geocodingComponent.getRegionFromCoordinates(info.getLatitude(), info.getLongitude()); +// if (kakaoRegion == null || kakaoRegion.getCodeAsInteger() == null) { +// return SignUpResponseDto.locationFail(); +// } +// +// //6-1 Img 정제 +// S3Imge petImg = awsClient.UploadImg(info.getAccountId(), info.getProfileImg(), "CUSTOM_USER_IMG", null); +// +// // 7. 새로운 User 생성 및 저장 +// User user = UserFactory.createNewUser(info, encodedPassword, kakaoRegion.getRegionName(), kakaoRegion.getCodeAsInteger(), petImg.uploadURL()); +// userRepository.save(user); +// +// // 8. 인증 엔티티 삭제 +// certificationRepository.deleteAllByAccountId(accountId); +// +// // 9. 성공 응답 반환 +// return SignUpResponseDto.success(user.getId(), petImg.checkResultImg()); +// +// } catch (RuntimeException e) { +// log.error("회원 가입 실패: {}", e.getMessage(), e); +// throw e; +// } catch (Exception e) { +// log.error("회원 가입 중 처리되지 않은 예외 발생: {}", e.getMessage(), e); +// return SignUpResponseDto.unknownError(); +// } +// } +// +// +// @Override +// public ResponseEntity signIn(SignInInfo info, HttpServletResponse response) { +// try { +// String accountId = info.getAccountId(); +// User user = userRepository.findByAccountId(accountId); +// // 사용자 존재 여부 확인 +// if (user == null) { +// log.info("사용자 조회 실패: {}", accountId); +// return SignInResponseDto.signInFail(); +// } +// +// // 비밀번호 확인 +// String password = info.getPassword(); +// String encodedPassword = user.getPassword(); +// if (!passwordEncoder.matches(password, encodedPassword)) { +// log.info("비밀번호 불일치: {}", accountId); +// return SignInResponseDto.signInFail(); +// } +// +// // JWT 생성 (userId를 subject로, accountId를 클레임으로 설정) +// String token = jwtProvider.create(user.getId(), user.getAccountId()); +// log.info("JWT 생성 완료: {}", token); +// +// ResponseCookie responseCookie = ResponseCookie.from("jwt", token) +// .httpOnly(true) // XSS 방지 +// .secure(true) // HTTPS만 허용 +// .path("/") // 모든 경로에서 접근 가능 +// .sameSite("None") // SameSite=None 설정 +// .maxAge((3600)) +// .build(); +// response.addHeader("Set-Cookie", responseCookie.toString()); +// // 로그인 성공 응답 반환 +// return SignInResponseDto.success(user); // User 객체 전달 +// } catch (Exception e) { +// log.error("로그인 처리 중 예외 발생", e); +// return SignInResponseDto.signInFail(); +// } +// } +// +// +// @Override +// public ResponseEntity logout(HttpServletResponse response) { +// try { +// // 만료된 쿠키 설정 +// ResponseCookie expiredCookie = ResponseCookie.from("jwt", "") +// .httpOnly(true) // XSS 방지 +// .secure(true) // HTTPS만 허용 +// .path("/") // 모든 경로에서 접근 가능 +// .sameSite("None") // SameSite=None 설정 +// .maxAge(0) // 즉시 만료 +// .build(); +// +// response.addHeader("Set-Cookie", expiredCookie.toString()); +// +// log.info("JWT 쿠키 제거 및 로그아웃 처리 완료"); +// return LogInResponseDto.success(); +// } catch (Exception e) { +// log.error("로그아웃 처리 중 예외 발생", e); +// return LogInResponseDto.validationFail(); +// } +// } +// +// +// @Override +// @Transactional +// public ResponseEntity deleteId(DeleteIdRequestDto dto) { +// try { +// Long userId = jwtExtractProvider.findIdFromJwt(); +// boolean exists = userRepository.existsById(userId); +// if (!exists) { +// return DeleteIdResponseDto.idNotFound(); +// } +// +// User user = userRepository.findById(userId) +// .orElseThrow(() -> new IllegalArgumentException("User not found for ID: " + userId)); +// +// +// // 비밀번호 일치 확인 +// String password = dto.getPassword(); +// String encodedPassword = user.getPassword(); +// boolean isMatched = passwordEncoder.matches(password, encodedPassword); +// if (!isMatched) return DeleteIdResponseDto.wrongPassword(); // 비밀번호 불일치 +// +// certificationRepository.deleteById(userId); +// // 사용자 삭제 +// List pets = petRepository.findAllByUserId(user.getId()); // Pet 엔티티에서 User를 참조하는 기준으로 조회 +// // 명시적으로 Pet 삭제 +// petRepository.deleteAll(pets); +// userRepository.delete(user); +// } catch (Exception e) { +// log.info("회원 삭제 실패: {}", e); +// return DeleteIdResponseDto.databaseError(); // 데이터베이스 오류 처리 +// } +// return DeleteIdResponseDto.success(); // 삭제 성공 응답 +// } +// +// +// @Override +// public ResponseEntity getMypage() { +// try { +// String userId = jwtExtractProvider.findAccountIdFromJwt(); +// User user = userRepository.findByAccountId(userId); +// +// boolean exists = userRepository.existsByAccountId(userId); +// if (!exists) { +// return GetMyProfileResponseDto.idNotFound(); +// } +// +// return GetMyProfileResponseDto.success(user); +// +// } catch (Exception e) { +// e.printStackTrace(); +// return GetMyProfileResponseDto.databaseError(); +// } +// } +// +// +// @Override +// public ResponseEntity getOtherMypage(Long userId) { +// try { +// // 현재 로그인한 사용자 ID 가져오기 +// Long myId = jwtExtractProvider.findIdFromJwt(); +// if (!userRepository.existsById(myId)) { +// return GetMyProfileResponseDto.idNotFound(); +// } +// +// // 조회 대상 사용자 정보 가져오기 +// User user = userRepository.findById(userId) +// .orElseThrow(() -> new IllegalArgumentException("User not found for ID: " + userId)); +// +// // 조회 대상 사용자가 존재하는지 확인 +// boolean exists = userRepository.existsById(userId); +// if (!exists) { +// return GetOtherProfileResponseDto.userNotFound(); +// } +// +// // 현재 로그인한 사용자가 조회 대상 사용자를 찜했는지 확인 +// boolean isMyHeartUser = heartRepository.existsByMyIdAndHeartedId(myId, userId); +// +// // 응답 생성 +// return GetOtherProfileResponseDto.success(user, isMyHeartUser); +// +// } catch (Exception e) { +// e.printStackTrace(); +// return GetOtherProfileResponseDto.userNotFound(); +// } +// } +// +// +// //TODO 고쳐야함. +// @Override +// @Transactional +// public ResponseEntity editMyProfile(EditMyProfileInfo info) { +// try { +// System.out.println("info ::" + info.isCareAvailable()); +// Long userId = jwtExtractProvider.findIdFromJwt(); +// String userEmail = jwtExtractProvider.findAccountIdFromJwt(); +// boolean exists = userRepository.existsById(userId); +// if (!exists) { +// return EditMyProfileResponseDto.idNotFound(); +// } +// +// User user = userRepository.findById(userId) +// .orElseThrow(() -> new IllegalArgumentException("User not found for ID: " + userId)); +// +// //6-1 Img 정제 +// S3Imge petImg = awsClient.UploadImg(userEmail, info.getProfileImg(), "CUSTOM_USER_IMG", null); +// +// // 병합된 DTO를 기반으로 엔티티 생성 +// String resultImg = user.updateImgURL(info.getProfileImg(), petImg); +// user.updateProfile(info); +// +//// 반환해야 함 아래꺼 +// return EditMyProfileResponseDto.success(resultImg); +// +// } catch (Exception e) { +// log.info("프로필 수정 실패: {}", e); +// return EditMyProfileResponseDto.editFailed(); +// } +// } +// +// +// @Override +// @Transactional +// public ResponseEntity hearting(HeartingRequestDto dto) { +// try { +// Long heartedId = dto.getHeartedId(); +// +// // 대상 사용자가 존재하는지 확인 +// boolean exists = userRepository.existsById(heartedId); +// if (!exists) { +// return HeartingResponseDto.heartedIdNotFound(); +// } +// +// // 현재 사용자 ID 가져오기 +// Long userId = jwtExtractProvider.findIdFromJwt(); +// User user = userRepository.findById(userId) +// .orElseThrow(() -> new IllegalArgumentException("User not found for ID: " + userId)); +// +// // DB에서 myId와 heartedId로 Heart 레코드 확인 +// Optional existingHeart = heartRepository.findByMyIdAndHeartedId(user.getId(), heartedId); +// +// if (existingHeart.isPresent()) { +// // 찜하기 해제 (DB에서 삭제) +// heartRepository.delete(existingHeart.get()); +// return HeartingResponseDto.success(); // 찜하기 해제 성공 응답 +// } +// +// // 찜하기 진행 (DB에 저장) +// Heart heart = UserFactory.createHeart(userId, heartedId); +// heartRepository.save(heart); +// +// return HeartingResponseDto.success(); // 찜하기 성공 응답 +// +// } catch (Exception e) { +// log.info("찜하기 실패: {}", e); +// return HeartingResponseDto.databaseError(); // 데이터베이스 오류 응답 +// } +// } +// +// +// @Override +// public ResponseEntity getHeartedList() { +// try { +// Long userId = jwtExtractProvider.findIdFromJwt(); +// User user = userRepository.findById(userId) +// .orElseThrow(() -> new IllegalArgumentException("User not found for ID: " + userId)); +// +// // Heart 리스트 조회 +// List heartList = heartRepository.findAllByMyId(user.getId()); +// +// // Heart 정보와 관련된 User 데이터 매핑 +// List heartedUsers = heartList.stream() +// .map(heart -> { +// User heartedUser = userRepository.findById(heart.getHeartedId()) +// .orElseThrow(() -> new IllegalArgumentException("User not found for ID: " + heart.getHeartedId())); +// +// return new HeartedUserDto( +// heart.getMyId(), +// heart.getHeartedId(), +// heartedUser.getNickname(), +// heartedUser.getProfileImg(), +// heartedUser.getCareAvailable(), +// heartedUser.getPreferredSizes() +// ); +// }) +// .toList(); +// +// // 성공 응답 반환 +// return GetHeartingListResponseDto.success(heartedUsers); +// +// } catch (Exception e) { +// log.info("찜리스트 받아오기 실패: {}", e); +// return HeartingResponseDto.databaseError(); +// } +// } +// +// +// @Override +// @Transactional +// public ResponseEntity sendRepassword(SendRepasswordRequestDto dto) { +// try { +// String accountId = dto.getAccountId(); +// if (!userRepository.existsByAccountId(accountId)) { +// return GetMyProfileResponseDto.idNotFound(); +// } +// User user = userRepository.findByAccountId(accountId); +// +// String rePasswordNum = RePasswordProvider.generatePassword(); +// log.info("Generated Repassword: {}", rePasswordNum); +// +//// boolean isSendSuccess = rePasswordEmailProvider.sendVerificationEmail(accountId, rePasswordNum); +//// if (!isSendSuccess) return SendRepasswordResponseDto.mailSendFail(); +// +// String encodedRePasswordNum = passwordEncoder.encode(rePasswordNum); +// +// user.updatePassword(encodedRePasswordNum); +// +// } catch (Exception e) { +// log.info("임시비밀번호 재설정 실패: {}", e); +// return SendRepasswordResponseDto.databaseError(); +// } +// return SendRepasswordResponseDto.success(); +// } +// +// +// @Override +// @Transactional +// public ResponseEntity repassword(RepasswordInfo info) { +// try { +// Long userId = jwtExtractProvider.findIdFromJwt(); +// User user = userRepository.findById(userId) +// .orElseThrow(() -> new IllegalArgumentException("User not found for ID: " + userId)); +// +// String currentPassword = info.getCurrentPassword(); +// +// boolean isPasswordValid = passwordEncoder.matches(currentPassword, user.getPassword()); +// if (!isPasswordValid) { +// return RepasswordResponseDto.wrongPassword(); +// } +// String newPassword = info.getNewPassword(); +// +// String encodedNewPassword = passwordEncoder.encode(newPassword); +// +// user.updatePassword(encodedNewPassword); +// +// } catch (Exception e) { +// log.info("비밀번호 재설정 실패: {}", e); +// return RepasswordResponseDto.databaseError(); +// } +// return RepasswordResponseDto.success(); +// } +// +// +// @Override +// @Transactional +// public ResponseEntity updateLocation(UpdateLocationInfo info) { +// try { +// // JWT에서 사용자 ID 추출 +// Long userId = jwtExtractProvider.findIdFromJwt(); +// +// // 사용자 엔티티 조회 +// User user = userRepository.findById(userId) +// .orElseThrow(() -> new IllegalArgumentException("User not found for ID: " + userId)); +// +// // 사용자 존재 여부 확인 +// boolean exists = userRepository.existsById(userId); +// if (!exists) { +// return UpdateLocationResponseDto.userNotFound(); +// } +// +// // GeocodingService에서 지역명과 행정코드 가져오기 +// GeocodingComponent.KakaoRegion kakaoRegion = geocodingComponent.getRegionFromCoordinates(info.getLatitude(), info.getLongitude()); +// if (kakaoRegion == null || kakaoRegion.getCodeAsInteger() == null) { +// return UpdateLocationResponseDto.wrongLocation(); // Kakao API 호출 실패 처리 +// } +// +// user.updateLocation(info, kakaoRegion.getRegionName(), kakaoRegion.getCodeAsInteger()); +// +// // 성공 응답 반환 +// return UpdateLocationResponseDto.success(kakaoRegion.getRegionName(), kakaoRegion.getCodeAsInteger()); +// } catch (Exception e) { +// log.error("위치 업데이트 실패: {}", e.getMessage(), e); +// return UpdateLocationResponseDto.wrongLocation(); +// } +// } +// +// @Override +// @Transactional +// public ResponseEntity updateRecommend(UpdateRecommendationRequestDto dto) { +// try { +// Long recommendedId = dto.getUserId(); +// Long myId = jwtExtractProvider.findIdFromJwt(); +// User recommendedUser = userRepository.findById(recommendedId) +// .orElseThrow(() -> new IllegalArgumentException("User not found for ID: " + recommendedId)); +// +// boolean exists = userRepository.existsById(recommendedId); +// if (!exists) { +// return UpdateRecommendationResponseDto.userNotFound(); +// } +// Integer recommendationCount = recommendedUser.getRecommendationCount() + 1; +// +// recommendedUser.updateRecommendation(recommendationCount); +// +// Recommendation recommendation = UserFactory.createRecommendation(myId, recommendedId); +// recommendationRepository.save(recommendation); +// +// } catch (Exception e) { +// log.info("추천수 업데이트 실패: {}", e); +// return UpdateRecommendationResponseDto.userNotFound(); +// } +// return UpdateRecommendationResponseDto.success(); +// } +// +// @Override +// public ResponseEntity getRecommend(UpdateRecommendationRequestDto dto) { +// try { +// Long recommendedId = dto.getUserId(); +// Long myId = jwtExtractProvider.findIdFromJwt(); +// +// boolean exists = recommendationRepository.existsByMyIdAndRecommendedId(myId,recommendedId); +// return GetRecommendationResponseDto.success(exists); +// +// } catch (Exception e) { +// log.info("추천수 업데이트 실패: {}", e); +// return GetRecommendationResponseDto.userNotFound(); +// } +// } +// +// @Override +// @Transactional +// public ResponseEntity editKakaoProfile(EditKakaoProfileInfo info) { +// try { +// Long userId = jwtExtractProvider.findIdFromJwt(); +// +// // userId가 null인 경우 예외 처리 +// if (userId == null) { +// log.warn("JWT에서 추출된 userId가 null입니다."); +// return EditKakaoProfileResponseDto.idNotFound(); +// } +// +// boolean exists = userRepository.existsById(userId); +// if (!exists) { +// log.warn("존재하지 않는 사용자 ID: {}", userId); +// return EditKakaoProfileResponseDto.idNotFound(); +// } +// +// User user = userRepository.findById(userId) +// .orElseThrow(() -> new IllegalArgumentException("User not found for ID: " + userId)); +// +// GeocodingComponent.KakaoRegion kakaoRegion = geocodingComponent.getRegionFromCoordinates(info.getLatitude(), info.getLongitude()); +// if (kakaoRegion == null || kakaoRegion.getCodeAsInteger() == null) { +// return UpdateLocationResponseDto.wrongLocation(); // Kakao API 호출 실패 처리 +// } +// +// user.updateKakaoProfile(info, kakaoRegion.getRegionName(), kakaoRegion.getCodeAsInteger()); +// } catch (Exception e) { +// log.error("프로필 수정 실패", e); +// return EditKakaoProfileResponseDto.editFailed(); +// } +// return EditKakaoProfileResponseDto.success(); +// } +// +// @Override +// public GetMyUserDto receiverEmail(String accountId) { +// try { +// User user = userRepository.findByAccountId(accountId); +// return new GetMyUserDto(user); +// } catch (Exception e) { +// e.printStackTrace(); +// } +// return new GetMyUserDto(); +// } +// +// @Override +// public void deleteUser(Long userUUID) { +// userRepository.deleteUserById(userUUID); +// } +// +// +// public UserInfo selectUserInfo(String receiverEmail) { +// User otherUser = userRepository.findByAccountId(receiverEmail); +// return otherUser.of(); +// } +// +// @Override +// public String findByUserEmail(Long userId) { +// return userRepository.findById(userId).get().getAccountId(); +// } +// +//} diff --git a/src/main/java/com/petmatz/infra/email/EmailProviderImpl.java b/src/main/java/com/petmatz/infra/email/EmailProviderImpl.java index 15aedfa..a0502cc 100644 --- a/src/main/java/com/petmatz/infra/email/EmailProviderImpl.java +++ b/src/main/java/com/petmatz/infra/email/EmailProviderImpl.java @@ -1,5 +1,6 @@ package com.petmatz.infra.email; +import com.petmatz.domain.user.exception.UserException; import com.petmatz.domain.user.service.EmailProvider; import jakarta.mail.internet.MimeMessage; import lombok.RequiredArgsConstructor; @@ -10,6 +11,8 @@ import org.thymeleaf.TemplateEngine; import org.thymeleaf.context.Context; +import static com.petmatz.domain.user.exception.MatchErrorCode.FAIL_MAIL_SEND; + @Component @RequiredArgsConstructor @Slf4j @@ -27,8 +30,7 @@ public class EmailProviderImpl implements EmailProvider { * @return 이메일 전송 성공 여부 (true: 성공, false: 실패) */ @Override - public boolean sendVerificationEmail(String email, String certificationNumber) { - + public void sendVerificationEmail(String email, String certificationNumber) { try { System.out.println(certificationNumber); // MIME 타입의 이메일 메시지 생성 @@ -47,11 +49,8 @@ public boolean sendVerificationEmail(String email, String certificationNumber) { javaMailSender.send(message); } catch (Exception e) { - log.info("이메일 {} 로 전송 실패", email); - log.info("Error: {}", e); - return false; + throw new UserException(FAIL_MAIL_SEND); } - return true; // 전송 성공 시 true 리턴 } /** diff --git a/src/main/java/com/petmatz/infra/email/RePasswordEmailProviderImpl.java b/src/main/java/com/petmatz/infra/email/RePasswordEmailProviderImpl.java index b7e9741..4a87bba 100644 --- a/src/main/java/com/petmatz/infra/email/RePasswordEmailProviderImpl.java +++ b/src/main/java/com/petmatz/infra/email/RePasswordEmailProviderImpl.java @@ -1,5 +1,6 @@ package com.petmatz.infra.email; +import com.petmatz.domain.user.exception.UserException; import com.petmatz.domain.user.service.RePasswordEmailProvider; import jakarta.mail.internet.MimeMessage; import lombok.RequiredArgsConstructor; @@ -10,6 +11,8 @@ import org.thymeleaf.TemplateEngine; import org.thymeleaf.context.Context; +import static com.petmatz.domain.user.exception.MatchErrorCode.FAIL_MAIL_SEND; + @Component @RequiredArgsConstructor @Slf4j @@ -21,8 +24,7 @@ public class RePasswordEmailProviderImpl implements RePasswordEmailProvider { @Override - public boolean sendVerificationEmail(String email, String rePassword) { - + public void sendVerificationEmail(String email, String rePassword) { try { // MIME 타입의 이메일 메시지 생성 MimeMessage message = javaMailSender.createMimeMessage(); @@ -40,11 +42,8 @@ public boolean sendVerificationEmail(String email, String rePassword) { javaMailSender.send(message); } catch (Exception e) { - log.info("이메일 {} 로 전송 실패", email); - log.info("Error: {}", e); - return false; + throw new UserException(FAIL_MAIL_SEND); // 추후에 메일 예외로 변경 } - return true; // 전송 성공 시 true 리턴 }