diff --git a/dateroad-api/src/main/java/org/dateroad/auth/filter/JwtAuthenticationFilter.java b/dateroad-api/src/main/java/org/dateroad/auth/filter/JwtAuthenticationFilter.java index 6d4de96a..a9eadb48 100644 --- a/dateroad-api/src/main/java/org/dateroad/auth/filter/JwtAuthenticationFilter.java +++ b/dateroad-api/src/main/java/org/dateroad/auth/filter/JwtAuthenticationFilter.java @@ -9,8 +9,10 @@ import org.dateroad.code.FailureCode; import org.dateroad.common.Constants; import org.dateroad.exception.UnauthorizedException; +import org.springframework.context.annotation.Bean; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import org.springframework.web.filter.OncePerRequestFilter; @@ -20,6 +22,7 @@ @RequiredArgsConstructor +@Component public class JwtAuthenticationFilter extends OncePerRequestFilter { private final JwtProvider jwtProvider; diff --git a/dateroad-api/src/main/java/org/dateroad/auth/jwt/JwtGenerator.java b/dateroad-api/src/main/java/org/dateroad/auth/jwt/JwtGenerator.java index 43fb6ddf..ba4cfdab 100644 --- a/dateroad-api/src/main/java/org/dateroad/auth/jwt/JwtGenerator.java +++ b/dateroad-api/src/main/java/org/dateroad/auth/jwt/JwtGenerator.java @@ -19,13 +19,13 @@ public class JwtGenerator { public String generateAccessToken(final long userId) { final Date now = new Date(); - final Date expiryDate = generateExpirationDate(now); + final Date expireDate = generateExpirationDate(now); return Jwts.builder() .setHeaderParam(Header.TYPE, Header.JWT_TYPE) .setSubject(String.valueOf(userId)) .setIssuedAt(now) - .setExpiration(expiryDate) + .setExpiration(expireDate) .signWith(getSigningKey(), SignatureAlgorithm.HS256) .compact(); } diff --git a/dateroad-api/src/main/java/org/dateroad/auth/jwt/JwtProvider.java b/dateroad-api/src/main/java/org/dateroad/auth/jwt/JwtProvider.java index ff3aa003..8855abed 100644 --- a/dateroad-api/src/main/java/org/dateroad/auth/jwt/JwtProvider.java +++ b/dateroad-api/src/main/java/org/dateroad/auth/jwt/JwtProvider.java @@ -5,8 +5,15 @@ import lombok.RequiredArgsConstructor; import org.dateroad.auth.jwt.refreshtoken.RefreshTokenGenerator; import org.dateroad.code.FailureCode; +import org.dateroad.exception.UnauthorizedException; +import org.dateroad.refreshtoken.domain.RefreshToken; +import org.dateroad.refreshtoken.repository.RefreshTokenRepository; import org.springframework.stereotype.Component; +import java.time.LocalDateTime; +import java.util.Arrays; +import java.util.Base64; + @RequiredArgsConstructor @Component public class JwtProvider { @@ -20,6 +27,18 @@ public Token issueToken(final long userId) { ); } + //refreshToken 재발급할 때 검증 + public void validateRefreshToken(LocalDateTime expireDate) { + if (expireDate.isBefore(LocalDateTime.now())) { + throw new UnauthorizedException(FailureCode.EXPIRED_REFRESH_TOKEN); + } + } + + //Base64 인코딩된 리프레시 토큰 문자열을 바이트 배열 + private byte[] toBinary(String refreshToken) { + return Base64.getDecoder().decode(refreshToken); + } + public long getUserIdFromSubject(String token) { Jws jws = jwtGenerator.parseToken(token); String subject = jws.getBody().getSubject(); diff --git a/dateroad-api/src/main/java/org/dateroad/auth/jwt/JwtValidator.java b/dateroad-api/src/main/java/org/dateroad/auth/jwt/JwtValidator.java index 53078ce5..e6b885ca 100644 --- a/dateroad-api/src/main/java/org/dateroad/auth/jwt/JwtValidator.java +++ b/dateroad-api/src/main/java/org/dateroad/auth/jwt/JwtValidator.java @@ -2,9 +2,9 @@ import org.dateroad.code.FailureCode; import org.dateroad.exception.UnauthorizedException; +import org.springframework.stereotype.Component; public class JwtValidator { - public void equalRefreshToken(String refreshToken, String storedRefreshToken) { if (!refreshToken.equals(storedRefreshToken)) { throw new UnauthorizedException(FailureCode.UNAUTHORIZED); diff --git a/dateroad-api/src/main/java/org/dateroad/auth/jwt/refreshtoken/RefreshTokenGenerator.java b/dateroad-api/src/main/java/org/dateroad/auth/jwt/refreshtoken/RefreshTokenGenerator.java index 06d7230e..be00347f 100644 --- a/dateroad-api/src/main/java/org/dateroad/auth/jwt/refreshtoken/RefreshTokenGenerator.java +++ b/dateroad-api/src/main/java/org/dateroad/auth/jwt/refreshtoken/RefreshTokenGenerator.java @@ -12,6 +12,7 @@ import java.time.LocalDateTime; import java.util.Arrays; import java.util.Base64; +import java.util.Optional; @RequiredArgsConstructor @Component @@ -22,30 +23,19 @@ public class RefreshTokenGenerator { public String generateRefreshToken(final long userId) { SecureRandom random = createSecureRandom(); - //SecureRandom을 사용하여 45 바이트의 랜덤 토큰을 생성 - byte[] token = new byte[TOKEN_BYTE_SIZE]; - random.nextBytes(token); - LocalDateTime expireAt = LocalDateTime.now().plusWeeks(2); + // SecureRandom을 사용하여 45 바이트의 랜덤 토큰을 생성 + byte[] tokenBytes = new byte[TOKEN_BYTE_SIZE]; + random.nextBytes(tokenBytes); - RefreshToken newRefreshToken = RefreshToken.create(token, userId, expireAt); - refreshTokenRepository.save(newRefreshToken); - - return Base64.getEncoder().encodeToString(token); - } + // 바이트 배열을 Base64 인코딩하여 문자열로 변환 + String token = Base64.getEncoder().encodeToString(tokenBytes); - //refreshToken 재발급할 때 검증 - public Long getUserIdOrThrow(final String refreshToken) { - byte[] convertedRefreshToken = toBinary(refreshToken); + LocalDateTime expireAt = LocalDateTime.now().plusWeeks(4); - RefreshToken findRefreshToken = refreshTokenRepository.findUserIdByToken(Arrays.toString(convertedRefreshToken).getBytes()); - if (findRefreshToken == null) { - throw new UnauthorizedException(FailureCode.INVALID_REFRESH_TOKEN_VALUE); - } + RefreshToken newRefreshToken = RefreshToken.create(token, userId, expireAt); + refreshTokenRepository.save(newRefreshToken); - if (findRefreshToken.getExpiredAt().isBefore(LocalDateTime.now())) { - throw new UnauthorizedException(FailureCode.EXPIRED_REFRESH_TOKEN); - } - return findRefreshToken.getUserId(); + return token; } public void deleteRefreshToken(final Long userId) { @@ -60,8 +50,4 @@ private SecureRandom createSecureRandom() { return new SecureRandom(buffer.array()); } - //Base64 인코딩된 리프레시 토큰 문자열을 바이트 배열 - private byte[] toBinary(String refreshToken) { - return Base64.getDecoder().decode(refreshToken); - } } diff --git a/dateroad-api/src/main/java/org/dateroad/course/api/CourseController.java b/dateroad-api/src/main/java/org/dateroad/course/api/CourseController.java index 0116ac15..5a8f7853 100644 --- a/dateroad-api/src/main/java/org/dateroad/course/api/CourseController.java +++ b/dateroad-api/src/main/java/org/dateroad/course/api/CourseController.java @@ -1,7 +1,6 @@ package org.dateroad.course.api; -import java.net.URI; import java.util.List; import lombok.RequiredArgsConstructor; import org.dateroad.auth.argumentresolve.UserId; @@ -19,15 +18,7 @@ import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestHeader; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestPart; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; @RestController @@ -39,7 +30,7 @@ public class CourseController { @GetMapping public ResponseEntity getAllCourse( - @ModelAttribute CourseGetAllReq courseGetAllReq + final @ModelAttribute CourseGetAllReq courseGetAllReq ) { CourseGetAllRes courseAll = courseService.getAllCourses(courseGetAllReq); return ResponseEntity.ok(courseAll); @@ -47,13 +38,13 @@ public ResponseEntity getAllCourse( @GetMapping("/date-access") public ResponseEntity getAllDataAccesCourse( - @UserId Long userId + final @UserId Long userId ) { DateAccessGetAllRes dateAccessGetAllRes = courseService.getAllDataAccessCourse(userId); return ResponseEntity.ok(dateAccessGetAllRes); } - @PostMapping(value = "/create", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_JSON_VALUE}) + @PostMapping(consumes = {MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_JSON_VALUE}) public ResponseEntity createCourse( @UserId final Long userId, @RequestPart("course") final CourseCreateReq courseCreateReq, @@ -76,6 +67,12 @@ public ResponseEntity openCourse( @RequestBody final PointUseReq pointUseReq ) { courseService.openCourse(userId,courseId,pointUseReq); + } + + @PostMapping("/{courseId}/likes") + public ResponseEntity createCourseLlike(@UserId final Long userId, + @PathVariable final Long courseId) { + courseService.createCourseLike(userId, courseId); return ResponseEntity.ok().build(); } } diff --git a/dateroad-api/src/main/java/org/dateroad/course/service/CourseService.java b/dateroad-api/src/main/java/org/dateroad/course/service/CourseService.java index 74dbb154..3b51cbad 100644 --- a/dateroad-api/src/main/java/org/dateroad/course/service/CourseService.java +++ b/dateroad-api/src/main/java/org/dateroad/course/service/CourseService.java @@ -18,8 +18,10 @@ import org.dateroad.date.repository.CourseRepository; import org.dateroad.dateAccess.domain.DateAccess; import org.dateroad.dateAccess.repository.DateAccessRepository; -import org.dateroad.exception.DateRoadException; +import org.dateroad.exception.ConflictException; +import org.dateroad.exception.EntityNotFoundException; import org.dateroad.image.domain.Image; +import org.dateroad.like.domain.Like; import org.dateroad.like.repository.LikeRepository; import org.dateroad.point.domain.Point; import org.dateroad.point.repository.PointRepository; @@ -48,6 +50,15 @@ public CourseGetAllRes getAllCourses(final CourseGetAllReq courseGetAllReq) { return CourseGetAllRes.of(courseDtoGetResList); } + + @Transactional + public void createCourseLike(final Long userId, final Long courseId) { + User findUser = getUser(userId); + Course findCourse = getCourse(courseId); + validateCourseLike(findUser, findCourse); + saveCourseLike(findUser, findCourse); + } + private List convertToDtoList(final List entities, final Function converter) { return entities.stream() .map(converter) @@ -78,16 +89,34 @@ public DateAccessGetAllRes getAllDataAccessCourse(final Long userId) { return DateAccessGetAllRes.of(courseDtoGetResList); } + private User getUser(final Long userId) { + return userRepository.findById(userId) + .orElseThrow(() -> new EntityNotFoundException(FailureCode.USER_NOT_FOUND)); + } + + private Course getCourse(final Long courseId) { + return courseRepository.findById(courseId) + .orElseThrow(() -> new EntityNotFoundException(FailureCode.COURSE_NOT_FOUND)); + } + + private void validateCourseLike(User findUser, Course findCourse) { + if (likeRepository.findByUserAndCourse(findUser, findCourse).isPresent()) { + throw new ConflictException(FailureCode.DUPLICATE_COURSE_LIKE); + } + } + + private void saveCourseLike(User user, Course course) { + Like like = Like.create(course, user); + likeRepository.save(like); + } + @Transactional public Course createCourse(final Long userId, final CourseCreateReq courseRegisterReq, final List places, final List images) { final float totalTime = places.stream() .map(CoursePlaceGetReq::getDuration) .reduce(0.0f, Float::sum); - User user = userRepository.findById(userId) - .orElseThrow( - () -> new DateRoadException(FailureCode.ENTITY_NOT_FOUND) - ); + User user = getUser(userId); Course course = Course.create( user, courseRegisterReq.getTitle(), @@ -101,8 +130,8 @@ public Course createCourse(final Long userId, final CourseCreateReq courseRegist ); Course saveCourse = courseRepository.save(course); List imageList = asyncService.createImage(images, saveCourse); - String thumnailUrl = imageList.getLast().getImageUrl(); - course.setThumbnail(thumnailUrl); + String thumbnailUrl = imageList.getLast().getImageUrl(); + course.setThumbnail(thumbnailUrl); return saveCourse; } diff --git a/dateroad-api/src/main/java/org/dateroad/date/api/DateController.java b/dateroad-api/src/main/java/org/dateroad/date/api/DateController.java index 4374aff9..d9207ff2 100644 --- a/dateroad-api/src/main/java/org/dateroad/date/api/DateController.java +++ b/dateroad-api/src/main/java/org/dateroad/date/api/DateController.java @@ -4,6 +4,8 @@ import org.dateroad.auth.argumentresolve.UserId; import org.dateroad.date.dto.request.DateCreateReq; import org.dateroad.date.dto.response.DateDetailRes; +import org.dateroad.date.dto.response.DatesGetRes; +import org.dateroad.date.dto.response.DateGetNearestRes; import org.dateroad.date.service.DateService; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -22,8 +24,15 @@ public ResponseEntity createDate(@UserId final Long userId, return ResponseEntity.status(HttpStatus.CREATED).build(); } + @GetMapping + public ResponseEntity getDates(@UserId final Long userId, + @RequestParam final String time) { + DatesGetRes datesGetRes = dateService.getDates(userId, time); + return ResponseEntity.ok(datesGetRes); + } + @GetMapping("/{dateId}") - public ResponseEntity getDateDetail(@RequestHeader final Long userId, + public ResponseEntity getDateDetail(@UserId final Long userId, @PathVariable final Long dateId) { DateDetailRes dateDetailRes = dateService.getDateDetail(userId, dateId); return ResponseEntity.ok(dateDetailRes); @@ -35,4 +44,11 @@ public ResponseEntity deleteDate(@UserId final Long userId, dateService.deleteDate(userId, dateId); return ResponseEntity.ok().build(); } + + @GetMapping("/nearest") + public ResponseEntity getNearestDate(@UserId final Long userId) { + DateGetNearestRes dateGetNearestRes = dateService.getNearestDate(userId); + return ResponseEntity + .ok(dateGetNearestRes); + } } diff --git a/dateroad-api/src/main/java/org/dateroad/date/dto/response/DateDetailRes.java b/dateroad-api/src/main/java/org/dateroad/date/dto/response/DateDetailRes.java index bea522ee..69429105 100644 --- a/dateroad-api/src/main/java/org/dateroad/date/dto/response/DateDetailRes.java +++ b/dateroad-api/src/main/java/org/dateroad/date/dto/response/DateDetailRes.java @@ -1,5 +1,6 @@ package org.dateroad.date.dto.response; +import com.fasterxml.jackson.annotation.JsonFormat; import lombok.AccessLevel; import lombok.Builder; import org.dateroad.date.domain.Date; @@ -14,9 +15,11 @@ public record DateDetailRes( Long dateId, String title, + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm", timezone = "Asia/Seoul") LocalTime startAt, String city, List tags, + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy.MM.dd", timezone = "Asia/Seoul") LocalDate date, List places ) { diff --git a/dateroad-api/src/main/java/org/dateroad/date/dto/response/DateGetNearestRes.java b/dateroad-api/src/main/java/org/dateroad/date/dto/response/DateGetNearestRes.java new file mode 100644 index 00000000..07138a62 --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/date/dto/response/DateGetNearestRes.java @@ -0,0 +1,37 @@ +package org.dateroad.date.dto.response; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.AccessLevel; +import lombok.Builder; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; + +@Builder(access = AccessLevel.PRIVATE) +public record DateGetNearestRes( + Long dateId, + int dDay, + String dateName, + int month, + int day, + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "hh:mm a", timezone = "Asia/Seoul") + LocalTime startAt +) { + public static DateGetNearestRes of(Long dateId, + int dDay, + String dateName, + int month, + int day, + LocalTime startAt) { + return DateGetNearestRes.builder() + .dateId(dateId) + .dDay(dDay) + .dateName(dateName) + .month(month) + .day(day) + .startAt(startAt) + .build(); + } + +} diff --git a/dateroad-api/src/main/java/org/dateroad/date/dto/response/DateGetRes.java b/dateroad-api/src/main/java/org/dateroad/date/dto/response/DateGetRes.java new file mode 100644 index 00000000..d76c49cf --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/date/dto/response/DateGetRes.java @@ -0,0 +1,34 @@ +package org.dateroad.date.dto.response; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.AccessLevel; +import lombok.Builder; +import org.dateroad.date.domain.Date; +import org.dateroad.tag.domain.DateTag; + +import java.time.LocalDate; +import java.util.List; + +@Builder(access = AccessLevel.PRIVATE) +public record DateGetRes( + Long dateId, + String title, + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy.MM.dd", timezone = "Asia/Seoul") + LocalDate date, + String city, + List tags, + int dDay +) { + public static DateGetRes of(Date date, List tags, int dDay) { + return DateGetRes.builder() + .dateId(date.getId()) + .title(date.getTitle()) + .date(date.getDate()) + .city(date.getCity()) + .tags(tags.stream() + .map(TagGetRes::of) + .toList()) + .dDay(dDay) + .build(); + } +} diff --git a/dateroad-api/src/main/java/org/dateroad/date/dto/response/DatesGetRes.java b/dateroad-api/src/main/java/org/dateroad/date/dto/response/DatesGetRes.java new file mode 100644 index 00000000..23181ebf --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/date/dto/response/DatesGetRes.java @@ -0,0 +1,17 @@ +package org.dateroad.date.dto.response; + +import lombok.AccessLevel; +import lombok.Builder; + +import java.util.List; + +@Builder(access = AccessLevel.PRIVATE) +public record DatesGetRes( + List dates +) { + public static DatesGetRes of(List dates) { + return DatesGetRes.builder() + .dates(dates) + .build(); + } +} diff --git a/dateroad-api/src/main/java/org/dateroad/date/service/DateRepository.java b/dateroad-api/src/main/java/org/dateroad/date/service/DateRepository.java index e723c8b3..de67c89d 100644 --- a/dateroad-api/src/main/java/org/dateroad/date/service/DateRepository.java +++ b/dateroad-api/src/main/java/org/dateroad/date/service/DateRepository.java @@ -2,6 +2,24 @@ import org.dateroad.date.domain.Date; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.time.LocalDate; +import java.util.List; + +import java.time.LocalDate; +import java.time.LocalTime; +import java.util.Optional; public interface DateRepository extends JpaRepository { + Optional findFirstByUserIdAndDateAfterOrDateAndStartAtAfterOrderByDateAscStartAtAsc( + Long userId, LocalDate currentDate, LocalDate sameDay, LocalTime currentTime); + @Query("select d from Date d where d.user.id = :userId and d.date < :currentDate") + List findPastDatesByUserId(@Param("userId") Long userId, @Param("currentDate") LocalDate currentDate); + + @Query("select d from Date d where d.user.id = :userId and d.date >= :currentDate") + List findFutureDatesByUserId(@Param("userId") Long userId, @Param("currentDate") LocalDate currentDate); } + + diff --git a/dateroad-api/src/main/java/org/dateroad/date/service/DateService.java b/dateroad-api/src/main/java/org/dateroad/date/service/DateService.java index b78a6c53..3bd3e91b 100644 --- a/dateroad-api/src/main/java/org/dateroad/date/service/DateService.java +++ b/dateroad-api/src/main/java/org/dateroad/date/service/DateService.java @@ -7,10 +7,14 @@ import org.dateroad.date.dto.request.PlaceCreateReq; import org.dateroad.date.dto.request.TagCreateReq; import org.dateroad.date.dto.response.DateDetailRes; +import org.dateroad.date.dto.response.DateGetRes; +import org.dateroad.date.dto.response.DatesGetRes; +import org.dateroad.date.dto.response.DateGetNearestRes; import org.dateroad.date.repository.DatePlaceRepository; import org.dateroad.date.repository.DateTagRepository; import org.dateroad.exception.EntityNotFoundException; import org.dateroad.exception.ForbiddenException; +import org.dateroad.exception.UnauthorizedException; import org.dateroad.place.domain.DatePlace; import org.dateroad.tag.domain.DateTag; import org.dateroad.user.domain.User; @@ -18,6 +22,9 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.time.LocalDate; +import java.time.LocalTime; +import java.time.temporal.ChronoUnit; import java.util.List; @RequiredArgsConstructor @@ -32,9 +39,18 @@ public class DateService { @Transactional public void createDate(final Long userId, final DateCreateReq dateCreateReq) { User findUser = getUser(userId); - Date date = createDate(findUser, dateCreateReq); - createDateTag(date, dateCreateReq.tags()); - createDatePlace(date, dateCreateReq.places()); + Date date = saveDate(findUser, dateCreateReq); + saveDateTag(date, dateCreateReq.tags()); + saveDatePlace(date, dateCreateReq.places()); + } + + public DatesGetRes getDates(final Long userId, final String time) { + LocalDate currentDate = LocalDate.now(); + List dates = fetchDatesByUserIdAndTime(userId, time, currentDate); + List dateGetResList = dates.stream() + .map(date -> createDateGetRes(date, currentDate)) + .toList(); + return DatesGetRes.of(dateGetResList); } public DateDetailRes getDateDetail(final Long userId, final Long dateId) { @@ -56,41 +72,80 @@ public void deleteDate(final Long userId, final Long dateId) { dateRepository.deleteById(dateId); } + public DateGetNearestRes getNearestDate(final Long userId) { + LocalDate currentDate = LocalDate.now(); + LocalTime currentTime = LocalTime.now(); + User findUser = getUser(userId); + Date nearest = findNearestDate(findUser.getId(), currentDate, currentTime); ; + int dDay = calculateDDay(nearest.getDate(), currentDate); + return DateGetNearestRes + .of( + nearest.getId(), + dDay, + nearest.getTitle(), + nearest.getDate().getMonthValue(), + nearest.getDate().getDayOfMonth(), + nearest.getStartAt() + ); + } + private User getUser(Long userId) { return userRepository.findById(userId) .orElseThrow(() -> new EntityNotFoundException(FailureCode.USER_NOT_FOUND)); } - private Date createDate(User findUser, DateCreateReq dateCreateReq) { + private Date saveDate(final User findUser, final DateCreateReq dateCreateReq) { Date date = Date.create(findUser, dateCreateReq.title(), dateCreateReq.date(), dateCreateReq.startAt(), dateCreateReq.country(), dateCreateReq.city()); return dateRepository.save(date); } - private void createDateTag(Date date, List tags) { + private void saveDateTag(final Date date, final List tags) { List dateTags = tags.stream() .map(t -> DateTag.create(date, t.tag())).toList(); dateTagRepository.saveAll(dateTags); } - private void createDatePlace(Date date, List places) { + private void saveDatePlace(final Date date, final List places) { List datePlaces = places.stream() .map(p -> DatePlace.create(date, p.name(), p.duration(), p.sequence())).toList(); datePlaceRepository.saveAll(datePlaces); } - private Date getDate(Long dateId) { + private List fetchDatesByUserIdAndTime(final Long userId, final String time, final LocalDate currentDate) { + if (time.equalsIgnoreCase("PAST")) { + return dateRepository.findPastDatesByUserId(userId, currentDate); + } + else if (time.equalsIgnoreCase("FUTURE")) { + return dateRepository.findFutureDatesByUserId(userId, currentDate); + } + else { + throw new UnauthorizedException(FailureCode.INVALID_DATE_GET_TYPE); + } + } + + private DateGetRes createDateGetRes(final Date date, final LocalDate currentDate) { + int dDay = calculateDday(date.getDate(), currentDate); + List dateTags = getDateTag(date); + return DateGetRes.of(date, dateTags, dDay); + } + + private int calculateDday(final LocalDate date, final LocalDate currentDate) { + return (int) ChronoUnit.DAYS.between(currentDate, date); + } + + private Date getDate(final Long dateId) { return dateRepository.findById(dateId) .orElseThrow(() -> new EntityNotFoundException(FailureCode.DATE_NOT_FOUND)); } - private void validateDate(User findUser, Date findDate) { + private void validateDate(final User findUser, final Date findDate) { if (!findUser.equals(findDate.getUser())) { throw new ForbiddenException(FailureCode.DATE_DELETE_ACCESS_DENIED); } } - private List getDateTag(Date date) { + private List getDateTag(final Date date) { List dateTags = dateTagRepository.findByDate(date); if (dateTags == null | dateTags.isEmpty()) { throw new EntityNotFoundException(FailureCode.DATE_TAG_NOT_FOUND); @@ -98,11 +153,26 @@ private List getDateTag(Date date) { return dateTags; } - private List getDatePlace(Date date) { + private List getDatePlace(final Date date) { List datePlaces = datePlaceRepository.findByDate(date); if (datePlaces == null | datePlaces.isEmpty()) { throw new EntityNotFoundException(FailureCode.DATE_PLACE_NOT_FOUND); } return datePlaces; } + //dDay 계산 + private int calculateDDay(LocalDate eventDate, LocalDate currentDate) { + if (eventDate.isEqual(currentDate)) { + return 0; + } else { + return (int) ChronoUnit.DAYS.between(currentDate, eventDate); + } + } + + //가장 가까운 데이트 가져오기 + private Date findNearestDate(Long userId, LocalDate currentDate, LocalTime currentTime) { + return dateRepository.findFirstByUserIdAndDateAfterOrDateAndStartAtAfterOrderByDateAscStartAtAsc(userId, currentDate, currentDate, currentTime) + .orElseThrow(() -> new EntityNotFoundException(FailureCode.DATE_NOT_FOUND)); + } + } diff --git a/dateroad-api/src/main/java/org/dateroad/user/api/UserController.java b/dateroad-api/src/main/java/org/dateroad/user/api/UserController.java index d78723e5..2f95d87a 100644 --- a/dateroad-api/src/main/java/org/dateroad/user/api/UserController.java +++ b/dateroad-api/src/main/java/org/dateroad/user/api/UserController.java @@ -5,9 +5,10 @@ import org.dateroad.user.dto.request.AppleWithdrawAuthCodeReq; import org.dateroad.user.dto.request.UserSignInReq; import org.dateroad.user.dto.request.UserSignUpReq; -import org.dateroad.user.dto.response.UserSignInRes; -import org.dateroad.user.dto.response.UsersignUpRes; +import org.dateroad.user.dto.response.UserJwtInfoRes; +import org.dateroad.user.dto.response.UserInfoMainRes; import org.dateroad.user.service.AuthService; +import org.dateroad.user.service.UserService; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -19,20 +20,21 @@ @RequestMapping("/api/v1/users") public class UserController { private final AuthService authService; + private final UserService userService; @PostMapping("/signup") - public ResponseEntity signUp(@RequestHeader(AUTHORIZATION) final String token, - @RequestBody final UserSignUpReq userSignUPReq) { - UsersignUpRes userSignUpRes = authService.signUp(token, userSignUPReq); + public ResponseEntity signUp(@RequestHeader(AUTHORIZATION) final String token, + @RequestBody final UserSignUpReq userSignUPReq) { + UserJwtInfoRes userSignUpRes = authService.signUp(token, userSignUPReq); return ResponseEntity .status(HttpStatus.CREATED) .body(userSignUpRes); } @PostMapping("/signin") - public ResponseEntity signIn(@RequestHeader(AUTHORIZATION) final String token, + public ResponseEntity signIn(@RequestHeader(AUTHORIZATION) final String token, @RequestBody final UserSignInReq userSignInReq) { - UserSignInRes userSignInRes = authService.signIn(token, userSignInReq); + UserJwtInfoRes userSignInRes = authService.signIn(token, userSignInReq); return ResponseEntity .ok(userSignInRes); } @@ -60,5 +62,19 @@ public ResponseEntity withdraw(@UserId final Long userId, return ResponseEntity .ok() .build(); + } + @PatchMapping("/reissue") + public ResponseEntity reissue(@RequestHeader(AUTHORIZATION) final String refreshToken) { + UserJwtInfoRes userJwtInfoRes = authService.reissue(refreshToken); + return ResponseEntity + .ok(userJwtInfoRes); + + } + + @GetMapping("/main") + public ResponseEntity getUserInfo(@UserId final Long userId) { + UserInfoMainRes userInfoMainRes = userService.getUserInfoMain(userId); + return ResponseEntity + .ok(userInfoMainRes); } } diff --git a/dateroad-api/src/main/java/org/dateroad/user/dto/response/UserInfoMainRes.java b/dateroad-api/src/main/java/org/dateroad/user/dto/response/UserInfoMainRes.java new file mode 100644 index 00000000..7115c16b --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/user/dto/response/UserInfoMainRes.java @@ -0,0 +1,19 @@ +package org.dateroad.user.dto.response; + +import lombok.AccessLevel; +import lombok.Builder; + +@Builder(access = AccessLevel.PRIVATE) +public record UserInfoMainRes( + String name, + int point, + String image +) { + public static UserInfoMainRes of(String name, int point, String image) { + return UserInfoMainRes.builder() + .name(name) + .point(point) + .image(image) + .build(); + } +} diff --git a/dateroad-api/src/main/java/org/dateroad/user/dto/response/UserSignInRes.java b/dateroad-api/src/main/java/org/dateroad/user/dto/response/UserJwtInfoRes.java similarity index 66% rename from dateroad-api/src/main/java/org/dateroad/user/dto/response/UserSignInRes.java rename to dateroad-api/src/main/java/org/dateroad/user/dto/response/UserJwtInfoRes.java index bedaa9ab..2b5dd384 100644 --- a/dateroad-api/src/main/java/org/dateroad/user/dto/response/UserSignInRes.java +++ b/dateroad-api/src/main/java/org/dateroad/user/dto/response/UserJwtInfoRes.java @@ -3,15 +3,14 @@ import lombok.AccessLevel; import lombok.Builder; - @Builder(access = AccessLevel.PRIVATE) -public record UserSignInRes( +public record UserJwtInfoRes( Long userId, String accessToken, String refreshToken ) { - public static UserSignInRes of(final long userId, final String accessToken, final String refreshToken) { - return UserSignInRes.builder() + public static UserJwtInfoRes of(final Long userId, final String accessToken, final String refreshToken) { + return UserJwtInfoRes.builder() .userId(userId) .accessToken(accessToken) .refreshToken(refreshToken) diff --git a/dateroad-api/src/main/java/org/dateroad/user/dto/response/UsersignUpRes.java b/dateroad-api/src/main/java/org/dateroad/user/dto/response/UsersignUpRes.java deleted file mode 100644 index 85fc2e5d..00000000 --- a/dateroad-api/src/main/java/org/dateroad/user/dto/response/UsersignUpRes.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.dateroad.user.dto.response; - -import lombok.AccessLevel; -import lombok.Builder; - -@Builder(access = AccessLevel.PRIVATE) -public record UsersignUpRes( - Long userId, - String accessToken, - String refreshToken -) { - public static UsersignUpRes of(final Long userId, final String accessToken, final String refreshToken) { - return UsersignUpRes.builder() - .userId(userId) - .accessToken(accessToken) - .refreshToken(refreshToken) - .build(); - } -} diff --git a/dateroad-api/src/main/java/org/dateroad/user/service/AuthService.java b/dateroad-api/src/main/java/org/dateroad/user/service/AuthService.java index 57364959..4a5312d6 100644 --- a/dateroad-api/src/main/java/org/dateroad/user/service/AuthService.java +++ b/dateroad-api/src/main/java/org/dateroad/user/service/AuthService.java @@ -1,13 +1,19 @@ package org.dateroad.user.service; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.dateroad.auth.jwt.JwtProvider; import org.dateroad.auth.jwt.Token; +import org.dateroad.auth.jwt.refreshtoken.RefreshTokenGenerator; import org.dateroad.code.FailureCode; import org.dateroad.exception.*; import org.dateroad.feign.apple.AppleFeignProvider; import org.dateroad.feign.kakao.KakaoFeignApi; import org.dateroad.feign.kakao.KakaoFeignProvider; +import org.dateroad.exception.ConflictException; +import org.dateroad.exception.EntityNotFoundException; +import org.dateroad.exception.UnauthorizedException; +import org.dateroad.refreshtoken.domain.RefreshToken; import org.dateroad.refreshtoken.repository.RefreshTokenRepository; import org.dateroad.tag.domain.DateTagType; import org.dateroad.tag.domain.UserTag; @@ -18,16 +24,20 @@ import org.dateroad.user.dto.request.UserSignInReq; import org.dateroad.user.repository.UserRepository; import org.dateroad.user.dto.request.UserSignUpReq; -import org.dateroad.user.dto.response.UserSignInRes; -import org.dateroad.user.dto.response.UsersignUpRes; +import org.dateroad.user.dto.response.UserJwtInfoRes; +import org.springframework.boot.autoconfigure.data.redis.RedisProperties; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.util.Arrays; +import java.util.Base64; import java.util.List; +import java.util.Optional; @RequiredArgsConstructor @Transactional(readOnly = true) @Service +@Slf4j public class AuthService { private final UserRepository userRepository; private final KakaoFeignProvider kakaoFeignProvider; @@ -38,7 +48,7 @@ public class AuthService { private final KakaoFeignApi kakaoFeignApi; @Transactional - public UsersignUpRes signUp(final String token, final UserSignUpReq userSignUpReq) { + public UserJwtInfoRes signUp(final String token, final UserSignUpReq userSignUpReq) { String platformUserId = getUserPlatformId(userSignUpReq.platform(), token); validateUserTagSize(userSignUpReq.tag()); checkNickname(userSignUpReq.name()); @@ -47,18 +57,26 @@ public UsersignUpRes signUp(final String token, final UserSignUpReq userSignUpRe saveUserTag(newUser, userSignUpReq.tag()); Token issuedToken = jwtProvider.issueToken(newUser.getId()); - return UsersignUpRes.of(newUser.getId(), issuedToken.accessToken(), issuedToken.refreshToken()); + return UserJwtInfoRes.of(newUser.getId(), issuedToken.accessToken(), issuedToken.refreshToken()); } @Transactional - public UserSignInRes signIn(final String token, final UserSignInReq userSignInReq) { + public UserJwtInfoRes signIn(final String token, final UserSignInReq userSignInReq) { String platformUserId = getUserPlatformId(userSignInReq.platform(), token); User foundUser = getUserByPlatformAndPlatformUserId(userSignInReq.platform(), platformUserId); + deleteRefreshToken(foundUser.getId()); Token issuedToken = jwtProvider.issueToken(foundUser.getId()); - return UserSignInRes.of(foundUser.getId(), issuedToken.accessToken(), issuedToken.refreshToken()); + return UserJwtInfoRes.of(foundUser.getId(), issuedToken.accessToken(), issuedToken.refreshToken()); } @Transactional + public UserJwtInfoRes reissue(final String refreshToken) { + RefreshToken foundRefreshToken = getRefreshTokenByToken(refreshToken); + jwtProvider.validateRefreshToken(foundRefreshToken.getExpiredAt()); + Long userId = foundRefreshToken.getUserId(); + Token newToken = jwtProvider.issueToken(userId); + return UserJwtInfoRes.of(userId, newToken.accessToken(), newToken.refreshToken()); + } public void withdraw(final Long userId, final AppleWithdrawAuthCodeReq AppleWithdrawAuthCodeReq) { //todo: #45브랜치 머지후, 메서드 이용 @@ -79,9 +97,7 @@ public void withdraw(final Long userId, final AppleWithdrawAuthCodeReq AppleWith //닉네임 중복체크 public void checkNickname(final String nickname) { - if (!userRepository.existsByName(nickname)) { - return; - } else { + if (userRepository.existsByName(nickname)) { throw new ConflictException(FailureCode.DUPLICATE_NICKNAME); } } @@ -145,6 +161,19 @@ private void validateUserTagSize(final List userTags) { } } + public RefreshToken getRefreshTokenByToken(final String refreshToken) { + try { + return refreshTokenRepository.findByToken(refreshToken) + .orElseThrow(() -> new UnauthorizedException(FailureCode.UNAUTHORIZED)); + } catch (IllegalArgumentException e) { + log.error(e.getMessage()); + throw new UnauthorizedException(FailureCode.INVALID_REFRESH_TOKEN_VALUE); + } catch (Exception e) { + log.error(e.getMessage()); + throw new UnauthorizedException((FailureCode.UNAUTHORIZED)); + } + } + //refreshToken 삭제 private void deleteRefreshToken(final long userId) { refreshTokenRepository.deleteByUserId(userId); diff --git a/dateroad-api/src/main/java/org/dateroad/user/service/UserService.java b/dateroad-api/src/main/java/org/dateroad/user/service/UserService.java new file mode 100644 index 00000000..3af924dc --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/user/service/UserService.java @@ -0,0 +1,27 @@ +package org.dateroad.user.service; + +import lombok.RequiredArgsConstructor; +import org.dateroad.code.FailureCode; +import org.dateroad.exception.EntityNotFoundException; +import org.dateroad.user.domain.User; +import org.dateroad.user.dto.response.UserInfoMainRes; +import org.dateroad.user.repository.UserRepository; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class UserService { + private final UserRepository userRepository; + + public UserInfoMainRes getUserInfoMain(final Long userId) { + User foundUser = findUserById(userId); + return UserInfoMainRes.of(foundUser.getName(), foundUser.getTotalPoint(), foundUser.getImageUrl()); + } + + private User findUserById(final Long userId) { + return userRepository.findById(userId) + .orElseThrow(() -> new EntityNotFoundException(FailureCode.USER_NOT_FOUND)); + } +} diff --git a/dateroad-common/src/main/java/org/dateroad/code/FailureCode.java b/dateroad-common/src/main/java/org/dateroad/code/FailureCode.java index 6f3530af..74617b01 100644 --- a/dateroad-common/src/main/java/org/dateroad/code/FailureCode.java +++ b/dateroad-common/src/main/java/org/dateroad/code/FailureCode.java @@ -38,6 +38,7 @@ public enum FailureCode { INVALID_KAKAO_ACCESS(HttpStatus.UNAUTHORIZED, "e4026", "잘못된 카카오 통신 접근입니다."), UN_LINK_WITH_KAKAO_UNAUTHORIZED(HttpStatus.UNAUTHORIZED, "e4027", "카카오 연결 끊기 통신에 실패했습니다"), INVALID_APPLE_TOKEN_ACCESS(HttpStatus.UNAUTHORIZED, "e4028", "잘못된 애플 토큰 통신 접근입니다."), + INVALID_DATE_GET_TYPE(HttpStatus.UNAUTHORIZED, "e4029", "잘못된 데이트 타입 검색입니다."), /** * 403 Forbidden @@ -55,6 +56,8 @@ public enum FailureCode { DATE_NOT_FOUND(HttpStatus.NOT_FOUND, "e4044", "데이트를 찾을 수 없습니다."), DATE_TAG_NOT_FOUND(HttpStatus.NOT_FOUND, "e4045", "데이트 태그를 찾을 수 없습니다."), DATE_PLACE_NOT_FOUND(HttpStatus.NOT_FOUND, "e4046", "데이트 장소를 찾을 수 없습니다."), + COURSE_NOT_FOUND(HttpStatus.NOT_FOUND, "e4047", "데이트 코스를 찾을 수 없습니다."), + NEAREST_DATE_NOT_FOUND(HttpStatus.NOT_FOUND, "e4048", "다가오는 데이트를 찾을 수 없습니다."), COURSE_NOT_FOUND(HttpStatus.NOT_FOUND, "e4047", "코스를 찾을수 없습니다."), INSUFFICIENT_USER_POINTS(HttpStatus.NOT_FOUND, "e4048", "유저의 포인트가 부족합니다."), @@ -69,6 +72,7 @@ public enum FailureCode { CONFLICT(HttpStatus.CONFLICT, "e4090", "이미 존재하는 리소스입니다."), DUPLICATE_USER(HttpStatus.CONFLICT, "e4091", "이미 존재하는 유저입니다."), DUPLICATE_NICKNAME(HttpStatus.CONFLICT, "e4092", "이미 존재하는 닉네임입니다."), + DUPLICATE_COURSE_LIKE(HttpStatus.CONFLICT, "e4093", "해당 데이트 코스에 좋아요가 이미 존재합니다."), INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "e5000", "서버 내부 오류입니다."); /** diff --git a/dateroad-domain/src/main/java/org/dateroad/like/repository/LikeRepository.java b/dateroad-domain/src/main/java/org/dateroad/like/repository/LikeRepository.java index 4b4db229..fc231081 100644 --- a/dateroad-domain/src/main/java/org/dateroad/like/repository/LikeRepository.java +++ b/dateroad-domain/src/main/java/org/dateroad/like/repository/LikeRepository.java @@ -3,10 +3,12 @@ import java.util.Optional; import org.dateroad.date.domain.Course; import org.dateroad.like.domain.Like; +import org.dateroad.user.domain.User; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository public interface LikeRepository extends JpaRepository { Optional countByCourse(Course course); + Optional findByUserAndCourse(User user, Course course); } diff --git a/dateroad-domain/src/main/java/org/dateroad/refreshtoken/domain/RefreshToken.java b/dateroad-domain/src/main/java/org/dateroad/refreshtoken/domain/RefreshToken.java index 22483343..e7f7e8f5 100644 --- a/dateroad-domain/src/main/java/org/dateroad/refreshtoken/domain/RefreshToken.java +++ b/dateroad-domain/src/main/java/org/dateroad/refreshtoken/domain/RefreshToken.java @@ -18,8 +18,8 @@ public class RefreshToken { @Id @NotNull - @Column(name = "refresh_token_id") - private byte[] token; + @Column(name = "refresh_token_id", nullable = false) + private String token; @Column(name = "user_id") private Long userId; @@ -27,7 +27,7 @@ public class RefreshToken { @Column(name = "expired_at") private LocalDateTime expiredAt; - public static RefreshToken create(final byte[] token, final Long userId, LocalDateTime expiredAt) { + public static RefreshToken create(final String token, final Long userId, LocalDateTime expiredAt) { return RefreshToken.builder() .token(token) .userId(userId) diff --git a/dateroad-domain/src/main/java/org/dateroad/refreshtoken/repository/RefreshTokenRepository.java b/dateroad-domain/src/main/java/org/dateroad/refreshtoken/repository/RefreshTokenRepository.java index be8a9c17..63f2781c 100644 --- a/dateroad-domain/src/main/java/org/dateroad/refreshtoken/repository/RefreshTokenRepository.java +++ b/dateroad-domain/src/main/java/org/dateroad/refreshtoken/repository/RefreshTokenRepository.java @@ -1,12 +1,13 @@ package org.dateroad.refreshtoken.repository; -import jakarta.validation.constraints.NotNull; import org.dateroad.refreshtoken.domain.RefreshToken; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.stereotype.Repository; -public interface RefreshTokenRepository extends JpaRepository { - RefreshToken findUserIdByToken(@NotNull byte[] token); +import java.util.Optional; + +public interface RefreshTokenRepository extends JpaRepository { + + Optional findByToken(String token); void deleteByUserId(final Long userId); } diff --git a/dateroad-domain/src/main/java/org/dateroad/tag/repository/UserTagRepository.java b/dateroad-domain/src/main/java/org/dateroad/tag/repository/UserTagRepository.java index 7a2a9781..a8b6434c 100644 --- a/dateroad-domain/src/main/java/org/dateroad/tag/repository/UserTagRepository.java +++ b/dateroad-domain/src/main/java/org/dateroad/tag/repository/UserTagRepository.java @@ -5,4 +5,5 @@ import org.springframework.stereotype.Repository; public interface UserTagRepository extends JpaRepository { + } diff --git a/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoFeignProvider.java b/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoFeignProvider.java index 375d7c48..120bae95 100644 --- a/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoFeignProvider.java +++ b/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoFeignProvider.java @@ -6,7 +6,7 @@ import lombok.extern.slf4j.Slf4j; import org.dateroad.code.FailureCode; import org.dateroad.exception.UnauthorizedException; -import org.dateroad.feign.kakao.dto.response.KaKaoErrorRes; +import org.dateroad.feign.kakao.dto.response.KakaoErrorRes; import org.dateroad.feign.kakao.dto.response.KakaoAccessTokenInfoRes; import org.springframework.stereotype.Component; @@ -46,7 +46,7 @@ private KakaoAccessTokenInfoRes getKakaoAccessTokenInfoFeign(final String access log.error("Kakao feign exception : ", e); //kakaoResponseDTO로 변경 - KaKaoErrorRes errorResponse = convertToKakaoErrorResponse(e.contentUTF8()); + KakaoErrorRes errorResponse = convertToKakaoErrorResponse(e.contentUTF8()); //카카오에서 주는 에러 코드가 -1이면 카카오 내부 에러, 나머지는 카카오 액세스 토큰 에러 if (errorResponse.code() == -1) { @@ -69,9 +69,9 @@ private String getKakaoRequestHeader(final KakaoRequestType kakaoRequestType, fi } } - private KaKaoErrorRes convertToKakaoErrorResponse(String responseBody) { + private KakaoErrorRes convertToKakaoErrorResponse(String responseBody) { try { - return objectMapper.readValue(responseBody, KaKaoErrorRes.class); + return objectMapper.readValue(responseBody, KakaoErrorRes.class); } catch (IOException e) { log.error("Convert To KakaoErrorResponse Error : ", e); throw new UnauthorizedException(FailureCode.INVALID_KAKAO_TOKEN); diff --git a/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoPlatformUserIdProvider.java b/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoPlatformUserIdProvider.java new file mode 100644 index 00000000..6753486d --- /dev/null +++ b/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoPlatformUserIdProvider.java @@ -0,0 +1,62 @@ +package org.dateroad.feign.kakao; + +import com.fasterxml.jackson.databind.ObjectMapper; +import feign.FeignException; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dateroad.code.FailureCode; +import org.dateroad.exception.UnauthorizedException; +import org.dateroad.feign.kakao.dto.response.KakaoErrorRes; +import org.dateroad.feign.kakao.dto.response.KakaoAccessTokenInfoRes; +import org.springframework.stereotype.Component; + +import java.io.IOException; + +@Slf4j +@RequiredArgsConstructor +@Component +public class KakaoPlatformUserIdProvider { + private final KakaoFeignApi kakaoFeignApi; + private final ObjectMapper objectMapper; + private static final String TOKEN_TYPE = "Bearer "; + + //AuthService에서 호출 : 카카오에서 주는 userId 받아오기 + public String getKakaoPlatformUserId(final String accessToken) { + String kakaoAccessTokenWithTokenType = getAccessTokenWithTokenType(accessToken); + KakaoAccessTokenInfoRes kakaoAccessTokenInfoRes = getKakaoAccessTokenInfo(kakaoAccessTokenWithTokenType); + return String.valueOf(kakaoAccessTokenInfoRes.id()); + } + + private KakaoAccessTokenInfoRes getKakaoAccessTokenInfo(final String token) { + try { + return kakaoFeignApi.getKakaoPlatformUserId(token); + } catch (FeignException e) { + log.error("Kakao feign exception : ", e); + + //kakaoResponseDTO로 변경 + KakaoErrorRes errorResponse = convertToKakaoErrorResponse(e.contentUTF8()); + + //카카오에서 주는 에러 코드가 -1이면 카카오 내부 에러, 나머지는 카카오 액세스 토큰 에러 + if (errorResponse.code() == -1) { + log.error("Kakao feign exception : ", e); + throw new UnauthorizedException(FailureCode.KAKAO_INTERNER_ERROR); + } else { + log.error("feign exception : ", e); + throw new UnauthorizedException(FailureCode.INVALID_KAKAO_TOKEN); + } + } + } + + private String getAccessTokenWithTokenType(String accessToken) { + return TOKEN_TYPE + accessToken; + } + + private KakaoErrorRes convertToKakaoErrorResponse(String responseBody) { + try { + return objectMapper.readValue(responseBody, KakaoErrorRes.class); + } catch (IOException e) { + log.error("Convert To KakaoErrorResponse Error : ", e); + throw new UnauthorizedException(FailureCode.UNAUTHORIZED); + } + } +} diff --git a/dateroad-external/src/main/java/org/dateroad/feign/kakao/dto/response/KaKaoErrorRes.java b/dateroad-external/src/main/java/org/dateroad/feign/kakao/dto/response/KakaoErrorRes.java similarity index 65% rename from dateroad-external/src/main/java/org/dateroad/feign/kakao/dto/response/KaKaoErrorRes.java rename to dateroad-external/src/main/java/org/dateroad/feign/kakao/dto/response/KakaoErrorRes.java index 5852a410..f309fdeb 100644 --- a/dateroad-external/src/main/java/org/dateroad/feign/kakao/dto/response/KaKaoErrorRes.java +++ b/dateroad-external/src/main/java/org/dateroad/feign/kakao/dto/response/KakaoErrorRes.java @@ -2,8 +2,8 @@ import lombok.Getter; -public record KaKaoErrorRes( - String error, +public record KakaoErrorRes( + String msg, int code ) { }