From b12d28c001ffbf9849776a99c048fc0a0ae99846 Mon Sep 17 00:00:00 2001 From: Kwak Seong Joon Date: Thu, 11 Jul 2024 00:23:52 +0900 Subject: [PATCH 01/78] =?UTF-8?q?[feat]=20RefreshTokenRepository=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=B6=94=EA=B0=80=20-=20#54?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../refreshtoken/repository/RefreshTokenRepository.java | 9 +++++---- .../java/org/dateroad/feign/kakao/KakaoFeignApi.java | 2 +- .../feign/kakao/KakaoPlatformUserIdProvider.java | 2 +- 3 files changed, 7 insertions(+), 6 deletions(-) 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-external/src/main/java/org/dateroad/feign/kakao/KakaoFeignApi.java b/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoFeignApi.java index e2db7ba1..5a186495 100644 --- a/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoFeignApi.java +++ b/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoFeignApi.java @@ -6,6 +6,6 @@ @FeignClient(name = "${feign.kakao.name}", url = "${feign.kakao.url}") public interface KakaoFeignApi { - @GetMapping + @GetMapping("/access_token_info") KakaoAccessTokenInfoRes getKakaoPlatformUserId(@RequestHeader("Authorization") String accessTokenWithTokenType); } 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 index eb91bf0c..31c6dd35 100644 --- a/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoPlatformUserIdProvider.java +++ b/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoPlatformUserIdProvider.java @@ -54,7 +54,7 @@ private KakaoErrorRes convertToKakaoErrorResponse(String responseBody) { return objectMapper.readValue(responseBody, KakaoErrorRes.class); } catch (IOException e) { log.error("Convert To KakaoErrorResponse Error : ", e); - throw new UnauthorizedException(FailureCode.INVALID_KAKAO_TOKEN); + throw new UnauthorizedException(FailureCode.UNAUTHORIZED); } } } From e50ec2e49d175b7cb77711e330e2d203ee0c9c0c Mon Sep 17 00:00:00 2001 From: Kwak Seong Joon Date: Thu, 11 Jul 2024 00:25:17 +0900 Subject: [PATCH 02/78] =?UTF-8?q?[feat]=20=EB=A6=AC=ED=94=84=EB=A0=88?= =?UTF-8?q?=EC=8B=9C=ED=86=A0=ED=81=B0=20=EC=A0=80=EC=9E=A5=EB=B0=A9?= =?UTF-8?q?=EC=8B=9D=20=EB=B3=80=EA=B2=BD=20-=20#54?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/dateroad/auth/jwt/JwtGenerator.java | 4 +-- .../refreshtoken/RefreshTokenGenerator.java | 34 ++++++------------- ...UserSignInRes.java => UserJwtInfoRes.java} | 7 ++-- .../user/dto/response/UsersignUpRes.java | 19 ----------- .../refreshtoken/domain/RefreshToken.java | 8 ++--- 5 files changed, 19 insertions(+), 53 deletions(-) rename dateroad-api/src/main/java/org/dateroad/user/dto/response/{UserSignInRes.java => UserJwtInfoRes.java} (66%) delete mode 100644 dateroad-api/src/main/java/org/dateroad/user/dto/response/UsersignUpRes.java 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/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/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-domain/src/main/java/org/dateroad/refreshtoken/domain/RefreshToken.java b/dateroad-domain/src/main/java/org/dateroad/refreshtoken/domain/RefreshToken.java index 22483343..1f952579 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 @@ -12,14 +12,14 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor(access = AccessLevel.PRIVATE) @Getter -@Table(name = "refresh_token") +@Table(name = "refreshtoken") @Entity 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) From 9a61212b54fdef2ed2b8fa203c8dcd5f6f16ca4c Mon Sep 17 00:00:00 2001 From: Kwak Seong Joon Date: Thu, 11 Jul 2024 00:25:53 +0900 Subject: [PATCH 03/78] =?UTF-8?q?[feat]=20=EC=9E=AC=EB=B0=9C=EA=B8=89?= =?UTF-8?q?=ED=95=A0=20=EB=95=8C,=20=EB=A7=8C=EB=A3=8C=20=EC=B2=B4?= =?UTF-8?q?=ED=81=AC=20-=20#54?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/dateroad/auth/jwt/JwtProvider.java | 22 +++++++++++++++++++ .../org/dateroad/auth/jwt/JwtValidator.java | 2 +- 2 files changed, 23 insertions(+), 1 deletion(-) 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..4701c56a 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,13 +5,21 @@ 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 { private final JwtGenerator jwtGenerator; private final RefreshTokenGenerator refreshTokenGenerator; + private final RefreshTokenRepository refreshTokenRepository; public Token issueToken(final long userId) { return Token.of( @@ -20,6 +28,20 @@ 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); From 850c25459379a7ff8c6ea4704fc397a7a64c6758 Mon Sep 17 00:00:00 2001 From: Kwak Seong Joon Date: Thu, 11 Jul 2024 00:26:18 +0900 Subject: [PATCH 04/78] =?UTF-8?q?[feat]=20AuthService=EC=97=90=20=EC=9E=AC?= =?UTF-8?q?=EB=B0=9C=EA=B8=89=20=EB=A9=94=EC=84=9C=EB=93=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20-=20#54?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/dateroad/user/api/UserController.java | 21 ++++--- .../dateroad/user/service/AuthService.java | 56 ++++++++++++++++--- 2 files changed, 61 insertions(+), 16 deletions(-) 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 24037156..bb73e0ee 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 @@ -4,8 +4,7 @@ import org.dateroad.auth.argumentresolve.UserId; 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.service.AuthService; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -20,18 +19,18 @@ public class UserController { private final AuthService authService; @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); } @@ -51,4 +50,12 @@ public ResponseEntity checkNickname(@RequestParam("name") final String nic .ok() .build(); } + + @PatchMapping("/reissue") + public ResponseEntity reissue(@RequestHeader(AUTHORIZATION) String refreshToken) { + UserJwtInfoRes userJwtInfoRes = authService.reissue(refreshToken); + return ResponseEntity + .ok(userJwtInfoRes); + + } } 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 bc6af7bd..c83258e3 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,14 +1,18 @@ 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.ConflictException; import org.dateroad.exception.EntityNotFoundException; import org.dateroad.exception.InvalidValueException; +import org.dateroad.exception.UnauthorizedException; import org.dateroad.feign.apple.ApplePlatformUserIdProvider; import org.dateroad.feign.kakao.KakaoPlatformUserIdProvider; +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,15 +22,19 @@ 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 @Service +@Slf4j public class AuthService { private final UserRepository userRepository; private final KakaoPlatformUserIdProvider kakaoPlatformUserIdProvider; @@ -36,7 +44,7 @@ public class AuthService { private final RefreshTokenRepository refreshTokenRepository; @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()); @@ -45,22 +53,28 @@ 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); 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 checkNickname(final String nickname) { - if (!userRepository.existsByName(nickname)) { - return; - } else { + if (userRepository.existsByName(nickname)) { throw new ConflictException(FailureCode.DUPLICATE_NICKNAME); } } @@ -122,8 +136,32 @@ private void validateUserTagSize(final List userTags) { } } + public RefreshToken getRefreshTokenByToken(final String refreshToken) { + try { +// byte[] decodedRefreshToken = Base64.getDecoder().decode(refreshToken); + RefreshToken optionalRefreshToken = refreshTokenRepository.findByToken(refreshToken) + .orElseThrow(() -> new UnauthorizedException(FailureCode.UNAUTHORIZED)); + if (optionalRefreshToken == null) { + throw new UnauthorizedException(FailureCode.UNAUTHORIZED); + } + return optionalRefreshToken; + } catch (IllegalArgumentException e) { + // Base64 decoding failed + log.error(e.getMessage()); + throw new UnauthorizedException(FailureCode.INVALID_REFRESH_TOKEN_VALUE); + } catch (Exception e) { + // Log the actual exception + log.info(e.getMessage()); + throw new RuntimeException("An unexpected error occurred", e); + } + } + //refreshToken 삭제 private void deleteRefreshToken(final long userId) { refreshTokenRepository.deleteByUserId(userId); } + + public byte[] toBinary(String token) { + return Base64.getDecoder().decode(token); + } } From 22ad7c33c9a59c1c76170f3b21d3f3d99cd3bf3f Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Thu, 11 Jul 2024 00:32:17 +0900 Subject: [PATCH 05/78] =?UTF-8?q?[feat]=20controller=20=EA=B5=AC=ED=98=84?= =?UTF-8?q?=20-=20#42?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/dateroad/config/AsyncConfig.java | 12 ++++++++ .../dateroad/course/api/CourseController.java | 30 +++++++++++++++++-- 2 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 dateroad-api/src/main/java/org/dateroad/config/AsyncConfig.java diff --git a/dateroad-api/src/main/java/org/dateroad/config/AsyncConfig.java b/dateroad-api/src/main/java/org/dateroad/config/AsyncConfig.java new file mode 100644 index 00000000..fd9c9e19 --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/config/AsyncConfig.java @@ -0,0 +1,12 @@ +package org.dateroad.config; + +import java.util.concurrent.Executor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +@Configuration +@EnableAsync +public class AsyncConfig { +} 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 3cef9e80..a1579a34 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,31 +1,46 @@ package org.dateroad.course.api; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import java.net.MulticastSocket; +import java.net.URI; +import java.util.List; +import javax.xml.crypto.OctetStreamData; import lombok.RequiredArgsConstructor; +import org.dateroad.Image.dto.request.ImageReq; import org.dateroad.auth.argumentresolve.UserId; import org.dateroad.course.dto.request.CourseGetAllReq; +import org.dateroad.course.dto.request.CourseCreateReq; import org.dateroad.course.dto.response.CourseGetAllRes; import org.dateroad.course.dto.response.DateAccessGetAllRes; import org.dateroad.course.service.CourseService; -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.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.RequestParam; +import org.springframework.web.bind.annotation.RequestPart; import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.multipart.MultipartFile; @RestController -@RequestMapping("/api/v1/courses") +//@RequestMapping("/api/v1/courses") +@RequestMapping("/api/v1") @RequiredArgsConstructor public class CourseController { private final CourseService courseService; + @GetMapping public ResponseEntity getAllCourse( @ModelAttribute CourseGetAllReq courseGetAllReq ) { CourseGetAllRes courseAll = courseService.getAllCourses(courseGetAllReq); return ResponseEntity.ok(courseAll); - } @GetMapping("/date-access") @@ -35,4 +50,13 @@ public ResponseEntity getAllDataAccesCourse( DateAccessGetAllRes dateAccessGetAllRes = courseService.getAllDataAccessCourse(userId); return ResponseEntity.ok(dateAccessGetAllRes); } + + @PostMapping("/c") + public ResponseEntity createCourse( + @RequestHeader Long userId, + @ModelAttribute CourseCreateReq courseCreateReq + ) { + return ResponseEntity.created( + URI.create(courseService.createCourse(userId, courseCreateReq))).build(); + } } From 3ec0bb680d68635664ccfca4c0dcf1cea6edd963 Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Thu, 11 Jul 2024 00:33:28 +0900 Subject: [PATCH 06/78] =?UTF-8?q?[feat]=20course=20tag,=20place=20?= =?UTF-8?q?=EC=97=94=ED=8B=B0=ED=8B=B0=20=EB=B0=8F=20repository=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20-=20#42?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../course/dto/request/CourseCreateReq.java | 52 +++++++++++++++++++ .../course/dto/request/CoursePlaceGetReq.java | 20 +++++++ .../course/dto/request/TagCreateReq.java | 16 ++++++ .../repository/CoursePlaceRepository.java | 4 +- .../tag/repository/CourseTagRepository.java | 9 ++++ 5 files changed, 98 insertions(+), 3 deletions(-) create mode 100644 dateroad-api/src/main/java/org/dateroad/course/dto/request/CourseCreateReq.java create mode 100644 dateroad-api/src/main/java/org/dateroad/course/dto/request/CoursePlaceGetReq.java create mode 100644 dateroad-api/src/main/java/org/dateroad/course/dto/request/TagCreateReq.java create mode 100644 dateroad-domain/src/main/java/org/dateroad/tag/repository/CourseTagRepository.java diff --git a/dateroad-api/src/main/java/org/dateroad/course/dto/request/CourseCreateReq.java b/dateroad-api/src/main/java/org/dateroad/course/dto/request/CourseCreateReq.java new file mode 100644 index 00000000..1b5ce250 --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/course/dto/request/CourseCreateReq.java @@ -0,0 +1,52 @@ +package org.dateroad.course.dto.request; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonFormat.Shape; +import java.time.LocalDate; +import java.time.LocalTime; +import java.util.List; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import org.dateroad.Image.dto.request.ImageReq; +import org.dateroad.tag.domain.DateTagType; +import org.springframework.format.annotation.DateTimeFormat; +import org.springframework.web.multipart.MultipartFile; + +@Builder(access = AccessLevel.PROTECTED) +public record CourseCreateReq( + String title, + @DateTimeFormat(pattern = "yyyy.MM.dd") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy.MM.dd", timezone = "Asia/Seoul") + LocalDate date, + @DateTimeFormat(pattern = "HH:mm") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm", timezone = "Asia/Seoul") + LocalTime startAt, + List tags, + String country, + String city, + List places, + String description, + int cost, + List images +) { + public static CourseCreateReq of(String title, LocalDate date, LocalTime startAt, List tags, + String country, + String city, + List places, String description, int cost, + List images) { + return CourseCreateReq.builder() + .title(title) + .date(date) + .startAt(startAt) + .tags(tags) + .country(country) + .city(city) + .places(places) + .description(description) + .cost(cost) + .images(images) + .build(); + } +} diff --git a/dateroad-api/src/main/java/org/dateroad/course/dto/request/CoursePlaceGetReq.java b/dateroad-api/src/main/java/org/dateroad/course/dto/request/CoursePlaceGetReq.java new file mode 100644 index 00000000..d2da6e21 --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/course/dto/request/CoursePlaceGetReq.java @@ -0,0 +1,20 @@ +package org.dateroad.course.dto.request; + +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Setter; + +@Builder +public record CoursePlaceGetReq( + String title, + float duration, + int sequence +) { + public static CoursePlaceGetReq of(String title, float duration, int sequence) { + return CoursePlaceGetReq.builder() + .title(title) + .duration(duration) + .sequence(sequence) + .build(); + } +} diff --git a/dateroad-api/src/main/java/org/dateroad/course/dto/request/TagCreateReq.java b/dateroad-api/src/main/java/org/dateroad/course/dto/request/TagCreateReq.java new file mode 100644 index 00000000..8d37c1fe --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/course/dto/request/TagCreateReq.java @@ -0,0 +1,16 @@ +package org.dateroad.course.dto.request; + + +import lombok.Builder; +import lombok.Setter; +import org.dateroad.tag.domain.DateTagType; + +@Builder +public record TagCreateReq( + DateTagType tag +) { + public static TagCreateReq of(DateTagType tag) { + return TagCreateReq.builder().tag(tag).build(); + } + +} \ No newline at end of file diff --git a/dateroad-domain/src/main/java/org/dateroad/place/repository/CoursePlaceRepository.java b/dateroad-domain/src/main/java/org/dateroad/place/repository/CoursePlaceRepository.java index 7037d6c2..c55db46d 100644 --- a/dateroad-domain/src/main/java/org/dateroad/place/repository/CoursePlaceRepository.java +++ b/dateroad-domain/src/main/java/org/dateroad/place/repository/CoursePlaceRepository.java @@ -1,7 +1,5 @@ package org.dateroad.place.repository; -import java.util.List; -import org.dateroad.date.domain.Course; import org.dateroad.place.domain.CoursePlace; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; @@ -11,5 +9,5 @@ @Repository public interface CoursePlaceRepository extends JpaRepository { @Query("SELECT SUM(p.duration) FROM CoursePlace p WHERE p.course.id = :courseId") - Integer findTotalDurationByCourseId(@Param("courseId") Long courseId); + Float findTotalDurationByCourseId(@Param("courseId") Long courseId); } diff --git a/dateroad-domain/src/main/java/org/dateroad/tag/repository/CourseTagRepository.java b/dateroad-domain/src/main/java/org/dateroad/tag/repository/CourseTagRepository.java new file mode 100644 index 00000000..f834f0ef --- /dev/null +++ b/dateroad-domain/src/main/java/org/dateroad/tag/repository/CourseTagRepository.java @@ -0,0 +1,9 @@ +package org.dateroad.tag.repository; + +import org.dateroad.tag.domain.CourseTag; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface CourseTagRepository extends JpaRepository { +} From 28db8c8286ea17fbad54395522c04e666481a4bb Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Thu, 11 Jul 2024 00:35:06 +0900 Subject: [PATCH 07/78] =?UTF-8?q?[feat]=20course=20service=20=EB=B0=8F=20P?= =?UTF-8?q?lace,Tag,Image=20Service=20=EA=B5=AC=ED=98=84=20-=20#42?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dateroad/Image/dto/request/ImageReq.java | 22 ++++++ .../dateroad/Image/service/ImageService.java | 52 ++++++++++++++ .../dateroad/course/facade/CourseFacade.java | 47 ++++++++++++ .../course/service/CoursePlaceService.java | 35 +++++++++ .../course/service/CourseService.java | 71 ++++++++++++------- .../course/service/CourseTagService.java | 33 +++++++++ .../java/org/dateroad/image/domain/Image.java | 2 +- .../main/java/org/dateroad/s3/S3Service.java | 11 +-- 8 files changed, 242 insertions(+), 31 deletions(-) create mode 100644 dateroad-api/src/main/java/org/dateroad/Image/dto/request/ImageReq.java create mode 100644 dateroad-api/src/main/java/org/dateroad/Image/service/ImageService.java create mode 100644 dateroad-api/src/main/java/org/dateroad/course/facade/CourseFacade.java create mode 100644 dateroad-api/src/main/java/org/dateroad/course/service/CoursePlaceService.java create mode 100644 dateroad-api/src/main/java/org/dateroad/course/service/CourseTagService.java diff --git a/dateroad-api/src/main/java/org/dateroad/Image/dto/request/ImageReq.java b/dateroad-api/src/main/java/org/dateroad/Image/dto/request/ImageReq.java new file mode 100644 index 00000000..5832320c --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/Image/dto/request/ImageReq.java @@ -0,0 +1,22 @@ +package org.dateroad.Image.dto.request; + +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Setter; +import org.springframework.http.MediaType; +import org.springframework.web.multipart.MultipartFile; + +@Builder(access = AccessLevel.PRIVATE) +public record ImageReq( + MultipartFile image, + int sequence +) { + public static ImageReq of(MultipartFile image, int sequence) { + return ImageReq.builder() + .image(image) + .sequence(sequence) + .build(); + } +} diff --git a/dateroad-api/src/main/java/org/dateroad/Image/service/ImageService.java b/dateroad-api/src/main/java/org/dateroad/Image/service/ImageService.java new file mode 100644 index 00000000..c1b03325 --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/Image/service/ImageService.java @@ -0,0 +1,52 @@ +package org.dateroad.Image.service; + +import java.io.IOException; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.atomic.AtomicInteger; +import lombok.RequiredArgsConstructor; +import org.dateroad.code.FailureCode; +import org.dateroad.date.domain.Course; +import org.dateroad.exception.DateRoadException; +import org.dateroad.image.domain.Image; +import org.dateroad.image.repository.ImageRepository; +import org.dateroad.s3.S3Service; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +@Service +@RequiredArgsConstructor +public class ImageService { + private final ImageRepository imageRepository; + private final S3Service s3Service; + @Value("${s3.bucket.path}") + private String path; + + @Transactional + public void saveImages(final List images, final Course course) { + AtomicInteger sequence = new AtomicInteger(); + List courseimages = images.stream() + .map(img -> { + try { + return Image.create( + course, + s3Service.uploadImage(path, img).get(), + sequence.getAndIncrement() + ); + } catch (IOException | ExecutionException | InterruptedException e) { + throw new RuntimeException(e); + } + }) + .toList(); + imageRepository.saveAll(courseimages); + } + + public Image findFirstByCourseOrderBySequenceAsc(Course course) { + return imageRepository.findFirstByCourseOrderBySequenceAsc(course) + .orElseThrow( + () -> new DateRoadException(FailureCode.COURSE_THUMBNAIL_NOT_FOUND) + ); + } +} diff --git a/dateroad-api/src/main/java/org/dateroad/course/facade/CourseFacade.java b/dateroad-api/src/main/java/org/dateroad/course/facade/CourseFacade.java new file mode 100644 index 00000000..64d2f919 --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/course/facade/CourseFacade.java @@ -0,0 +1,47 @@ +package org.dateroad.course.facade; + +import java.util.List; +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import org.dateroad.Image.service.ImageService; +import org.dateroad.course.dto.request.CoursePlaceGetReq; +import org.dateroad.course.dto.request.TagCreateReq; +import org.dateroad.course.service.CoursePlaceService; +import org.dateroad.course.service.CourseTagService; +import org.dateroad.date.domain.Course; +import org.dateroad.image.domain.Image; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +@Service +@RequiredArgsConstructor(access = AccessLevel.PROTECTED) +@Transactional(readOnly = true) +public class CourseFacade { + private final CoursePlaceService coursePlaceService; + private final ImageService imageService; + private final CourseTagService courseTagService; + + public Image findFirstByCourseOrderBySequenceAsc(final Course course) { + return imageService.findFirstByCourseOrderBySequenceAsc(course); + } + + public float findTotalDurationByCourseId(final Long id) { + return coursePlaceService.findTotalDurationByCourseId(id); + } + + public void createImage(final List images, final Course course) { + imageService.saveImages(images, course); + } + + @Async + public void createCourseTags(final List tags, final Course course) { + courseTagService.createCourseTags(tags, course); + } + + @Async + public void createCoursePlaces(final List places,final Course course) { + coursePlaceService.createCoursePlace(places,course); + } +} diff --git a/dateroad-api/src/main/java/org/dateroad/course/service/CoursePlaceService.java b/dateroad-api/src/main/java/org/dateroad/course/service/CoursePlaceService.java new file mode 100644 index 00000000..6524bc77 --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/course/service/CoursePlaceService.java @@ -0,0 +1,35 @@ +package org.dateroad.course.service; + +import java.util.List; +import java.util.stream.Collectors; +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import org.dateroad.course.dto.request.CoursePlaceGetReq; +import org.dateroad.date.domain.Course; +import org.dateroad.place.domain.CoursePlace; +import org.dateroad.place.repository.CoursePlaceRepository; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor(access = AccessLevel.PROTECTED) +public class CoursePlaceService { + private final CoursePlaceRepository coursePlaceRepository; + + public float findTotalDurationByCourseId(final Long id) { + return coursePlaceRepository.findTotalDurationByCourseId(id); + } + + @Transactional + public void createCoursePlace(final List places, final Course course) { + List coursePlaces = places.stream() + .map(placeReq -> CoursePlace.create( + placeReq.title(), + placeReq.duration(), + course, + placeReq.sequence() + )) + .collect(Collectors.toList()); + coursePlaceRepository.saveAll(coursePlaces); + } +} 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 9422b674..a4cd962f 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 @@ -3,59 +3,54 @@ import java.util.List; import java.util.function.Function; import java.util.stream.Collectors; +import lombok.AccessLevel; import lombok.RequiredArgsConstructor; -import org.dateroad.code.FailureCode; import org.dateroad.course.dto.request.CourseGetAllReq; -import org.dateroad.course.dto.response.CourseDtoRes; +import org.dateroad.course.dto.request.CourseCreateReq; +import org.dateroad.course.dto.request.CoursePlaceGetReq; +import org.dateroad.course.dto.response.CourseDtoGetRes; import org.dateroad.course.dto.response.CourseGetAllRes; import org.dateroad.course.dto.response.DateAccessGetAllRes; +import org.dateroad.course.facade.CourseFacade; import org.dateroad.date.domain.Course; import org.dateroad.date.repository.CourseRepository; -import org.dateroad.dateAccess.repository.DataAccessRepository; -import org.dateroad.exception.DateRoadException; +import org.dateroad.dateAccess.repository.DateAccessRepository; import org.dateroad.image.domain.Image; -import org.dateroad.image.repository.ImageRepository; import org.dateroad.like.repository.LikeRepository; -import org.dateroad.place.repository.CoursePlaceRepository; import org.springframework.data.jpa.domain.Specification; -import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; -import org.springframework.web.ErrorResponseException; +import org.springframework.transaction.annotation.Transactional; @Service -@RequiredArgsConstructor +@RequiredArgsConstructor(access = AccessLevel.PROTECTED) +@Transactional(readOnly = true) public class CourseService { private final CourseRepository courseRepository; private final LikeRepository likeRepository; - private final ImageRepository imageRepository; - private final CoursePlaceRepository coursePlaceRepository; - private final DataAccessRepository dataAccessRepository; + private final DateAccessRepository dateAccessRepository; + private final CourseFacade courseFacade; public CourseGetAllRes getAllCourses(CourseGetAllReq courseGetAllReq) { Specification spec = CourseSpecifications.filterByCriteria(courseGetAllReq); List courses = courseRepository.findAll(spec); - List courseDtoResList = convertToDtoList(courses, Function.identity()); - return CourseGetAllRes.of(courseDtoResList); + List courseDtoGetResList = convertToDtoList(courses, Function.identity()); + return CourseGetAllRes.of(courseDtoGetResList); } - private List convertToDtoList(List entities, Function converter) { + private List convertToDtoList(List entities, Function converter) { return entities.stream() .map(converter) .map(this::convertToDto) .collect(Collectors.toList()); } - private CourseDtoRes convertToDto(Course course) { + private CourseDtoGetRes convertToDto(Course course) { int likeCount = likeRepository.countByCourse(course) .orElse(0); - Image thumbnailImage = imageRepository.findFirstByCourseOrderBySequenceAsc(course) - .orElseThrow( - () -> new DateRoadException(FailureCode.COURSE_THUMBNAIL_NOT_FOUND) - ); + Image thumbnailImage = courseFacade.findFirstByCourseOrderBySequenceAsc(course); String thumbnailUrl = thumbnailImage != null ? thumbnailImage.getImageUrl() : null; - float duration = coursePlaceRepository.findTotalDurationByCourseId(course.getId()); - - return CourseDtoRes.of( + float duration = courseFacade.findTotalDurationByCourseId(course.getId()); + return CourseDtoGetRes.of( course.getId(), thumbnailUrl, course.getCity(), @@ -67,8 +62,32 @@ private CourseDtoRes convertToDto(Course course) { } public DateAccessGetAllRes getAllDataAccessCourse(Long userId) { - List accesses = dataAccessRepository.findCoursesByUserId(userId); - List courseDtoResList = convertToDtoList(accesses, Function.identity()); - return DateAccessGetAllRes.of(courseDtoResList); + List accesses = dateAccessRepository.findCoursesByUserId(userId); + List courseDtoGetResList = convertToDtoList(accesses, Function.identity()); + return DateAccessGetAllRes.of(courseDtoGetResList); + } + + @Transactional + public String createCourse(Long userId, CourseCreateReq courseRegisterReq) { + System.out.println(courseRegisterReq); + final float totalTime = courseRegisterReq.places().stream() + .map(CoursePlaceGetReq::duration) // 각 CoursePlaceGetReq 객체의 duration 값을 추출 + .reduce(0.0f, Float::sum); // 모든 duration 값을 합산 + + final Course course = Course.create( + courseRegisterReq.title(), + courseRegisterReq.description(), + courseRegisterReq.country(), + courseRegisterReq.city(), + courseRegisterReq.cost(), + courseRegisterReq.date(), + courseRegisterReq.startAt(), + totalTime + ); + courseFacade.createImage(courseRegisterReq.images(), course); + courseFacade.createCoursePlaces(courseRegisterReq.places(), course); + courseFacade.createCourseTags(courseRegisterReq.tags(), course); + + return courseRepository.save(course).getId().toString(); } } diff --git a/dateroad-api/src/main/java/org/dateroad/course/service/CourseTagService.java b/dateroad-api/src/main/java/org/dateroad/course/service/CourseTagService.java new file mode 100644 index 00000000..0bcd951b --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/course/service/CourseTagService.java @@ -0,0 +1,33 @@ +package org.dateroad.course.service; + +import java.util.List; +import java.util.stream.Collectors; +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import org.dateroad.course.dto.request.TagCreateReq; +import org.dateroad.date.domain.Course; +import org.dateroad.place.domain.CoursePlace; +import org.dateroad.tag.domain.CourseTag; +import org.dateroad.tag.domain.DateTagType; +import org.dateroad.tag.repository.CourseTagRepository; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +@RequiredArgsConstructor(access = AccessLevel.PROTECTED) +@Transactional(readOnly = true) +public class CourseTagService { + private final CourseTagRepository courseTagRepository; + + @Transactional + public void createCourseTags(List tags, Course course) { + List coursePlaces = tags.stream() + .map(tag -> CourseTag.create( + course, + tag.tag() + )) + .collect(Collectors.toList()); + courseTagRepository.saveAll(coursePlaces); + } +} \ No newline at end of file diff --git a/dateroad-domain/src/main/java/org/dateroad/image/domain/Image.java b/dateroad-domain/src/main/java/org/dateroad/image/domain/Image.java index 38ad641c..8b306247 100644 --- a/dateroad-domain/src/main/java/org/dateroad/image/domain/Image.java +++ b/dateroad-domain/src/main/java/org/dateroad/image/domain/Image.java @@ -44,7 +44,7 @@ public class Image extends BaseTimeEntity { @NotNull private int sequence; - public static Image create0(final Course course, final String imageUrl, int sequence) { + public static Image create(final Course course, final String imageUrl, int sequence) { return Image.builder() .course(course) .imageUrl(imageUrl) diff --git a/dateroad-external/src/main/java/org/dateroad/s3/S3Service.java b/dateroad-external/src/main/java/org/dateroad/s3/S3Service.java index 40fd47f9..03fd04cb 100644 --- a/dateroad-external/src/main/java/org/dateroad/s3/S3Service.java +++ b/dateroad-external/src/main/java/org/dateroad/s3/S3Service.java @@ -1,7 +1,11 @@ package org.dateroad.s3; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.Future; import org.springframework.beans.factory.annotation.Value; +import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; +import org.springframework.util.concurrent.ListenableFuture; import org.springframework.web.multipart.MultipartFile; import software.amazon.awssdk.core.sync.RequestBody; import software.amazon.awssdk.services.s3.S3Client; @@ -15,7 +19,6 @@ @Component public class S3Service { - private final String bucketName; private final AWSConfig awsConfig; private static final List IMAGE_EXTENSIONS = Arrays.asList("image/jpeg", "image/png", "image/jpg", "image/webp"); @@ -26,8 +29,8 @@ public S3Service(@Value("${aws-property.s3-bucket-name}") final String bucketNam this.awsConfig = awsConfig; } - - public String uploadImage(String directoryPath, MultipartFile image) throws IOException { + @Async + public Future uploadImage(String directoryPath, MultipartFile image) throws IOException { final String key = directoryPath + generateImageFileName(); final S3Client s3Client = awsConfig.getS3Client(); @@ -43,7 +46,7 @@ public String uploadImage(String directoryPath, MultipartFile image) throws IOEx RequestBody requestBody = RequestBody.fromBytes(image.getBytes()); s3Client.putObject(request, requestBody); - return key; + return CompletableFuture.completedFuture(key); } public void deleteImage(String key) throws IOException { From 6f332e673e92255aa691b5ffdf6e64631fe183db Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Thu, 11 Jul 2024 00:36:03 +0900 Subject: [PATCH 08/78] =?UTF-8?q?[feat]=20Course=20time=20=ED=95=84?= =?UTF-8?q?=EB=93=9C=20=EC=B6=94=EA=B0=80=20-=20#42?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/dateroad/date/domain/Course.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/dateroad-domain/src/main/java/org/dateroad/date/domain/Course.java b/dateroad-domain/src/main/java/org/dateroad/date/domain/Course.java index b226e834..4bfe4539 100644 --- a/dateroad-domain/src/main/java/org/dateroad/date/domain/Course.java +++ b/dateroad-domain/src/main/java/org/dateroad/date/domain/Course.java @@ -10,6 +10,7 @@ import jakarta.validation.constraints.NotNull; import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.LocalTime; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; @@ -38,10 +39,14 @@ public class Course extends DateBase { @NotNull private int cost; + @Column(name = "time") + @NotNull + private float time; + public static Course create(final String title, final String description, final String country, final String city, final int cost, final LocalDate date, - final LocalDateTime startAt) { + final LocalTime startAt, final float time) { return Course.builder() .title(title) .description(description) @@ -50,6 +55,7 @@ public static Course create(final String title, final String description, .cost(cost) .date(date) .startAt(startAt) + .time(time) .build(); } } From 0764fa5d9201413bbfa564d69ed9c3ace23b7d20 Mon Sep 17 00:00:00 2001 From: Kwak Seong Joon Date: Thu, 11 Jul 2024 00:42:12 +0900 Subject: [PATCH 09/78] =?UTF-8?q?[chore]=20=EC=BD=94=EB=93=9C=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC=20-=20#54?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/dateroad/user/service/AuthService.java | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) 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 c83258e3..9ad5026e 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 @@ -138,19 +138,12 @@ private void validateUserTagSize(final List userTags) { public RefreshToken getRefreshTokenByToken(final String refreshToken) { try { -// byte[] decodedRefreshToken = Base64.getDecoder().decode(refreshToken); - RefreshToken optionalRefreshToken = refreshTokenRepository.findByToken(refreshToken) + return refreshTokenRepository.findByToken(refreshToken) .orElseThrow(() -> new UnauthorizedException(FailureCode.UNAUTHORIZED)); - if (optionalRefreshToken == null) { - throw new UnauthorizedException(FailureCode.UNAUTHORIZED); - } - return optionalRefreshToken; } catch (IllegalArgumentException e) { - // Base64 decoding failed log.error(e.getMessage()); throw new UnauthorizedException(FailureCode.INVALID_REFRESH_TOKEN_VALUE); } catch (Exception e) { - // Log the actual exception log.info(e.getMessage()); throw new RuntimeException("An unexpected error occurred", e); } @@ -160,8 +153,4 @@ public RefreshToken getRefreshTokenByToken(final String refreshToken) { private void deleteRefreshToken(final long userId) { refreshTokenRepository.deleteByUserId(userId); } - - public byte[] toBinary(String token) { - return Base64.getDecoder().decode(token); - } } From 0f825547e49a7138694730f810ba32ace0ac2d40 Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Thu, 11 Jul 2024 00:54:44 +0900 Subject: [PATCH 10/78] =?UTF-8?q?[feat]=20DateAccessRepository=20=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20-=20#42?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/dateroad/date/domain/Date.java | 3 ++- .../src/main/java/org/dateroad/date/domain/DateBase.java | 7 ++++++- ...DataAccessRepository.java => DateAccessRepository.java} | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) rename dateroad-domain/src/main/java/org/dateroad/dateAccess/repository/{DataAccessRepository.java => DateAccessRepository.java} (88%) diff --git a/dateroad-domain/src/main/java/org/dateroad/date/domain/Date.java b/dateroad-domain/src/main/java/org/dateroad/date/domain/Date.java index 968036d2..b66d8d9e 100644 --- a/dateroad-domain/src/main/java/org/dateroad/date/domain/Date.java +++ b/dateroad-domain/src/main/java/org/dateroad/date/domain/Date.java @@ -8,6 +8,7 @@ import jakarta.persistence.Table; import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.LocalTime; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; @@ -26,7 +27,7 @@ public class Date extends DateBase { public static Date create(final String title, final String country, final String city, LocalDate date, - final LocalDateTime startAt) { + final LocalTime startAt) { return Date.builder() .title(title) .city(city) diff --git a/dateroad-domain/src/main/java/org/dateroad/date/domain/DateBase.java b/dateroad-domain/src/main/java/org/dateroad/date/domain/DateBase.java index d1dafafe..7d0c1ff0 100644 --- a/dateroad-domain/src/main/java/org/dateroad/date/domain/DateBase.java +++ b/dateroad-domain/src/main/java/org/dateroad/date/domain/DateBase.java @@ -8,6 +8,7 @@ import jakarta.validation.constraints.NotNull; import java.time.LocalDate; import java.time.LocalDateTime; +import java.time.LocalTime; import lombok.AccessLevel; import lombok.AllArgsConstructor; import lombok.Getter; @@ -37,7 +38,7 @@ public abstract class DateBase extends BaseTimeEntity { @Column(name = "start_at") @NotNull - private LocalDateTime startAt; + private LocalTime startAt; @Column(name = "country") @NotNull @@ -46,4 +47,8 @@ public abstract class DateBase extends BaseTimeEntity { @Column(name = "city") @NotNull private String city; + + @Column(name = "thumbnail") + @NotNull + private String thumbnail; } diff --git a/dateroad-domain/src/main/java/org/dateroad/dateAccess/repository/DataAccessRepository.java b/dateroad-domain/src/main/java/org/dateroad/dateAccess/repository/DateAccessRepository.java similarity index 88% rename from dateroad-domain/src/main/java/org/dateroad/dateAccess/repository/DataAccessRepository.java rename to dateroad-domain/src/main/java/org/dateroad/dateAccess/repository/DateAccessRepository.java index 2edf845e..caacedbd 100644 --- a/dateroad-domain/src/main/java/org/dateroad/dateAccess/repository/DataAccessRepository.java +++ b/dateroad-domain/src/main/java/org/dateroad/dateAccess/repository/DateAccessRepository.java @@ -7,7 +7,7 @@ import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -public interface DataAccessRepository extends JpaRepository { +public interface DateAccessRepository extends JpaRepository { @Query("SELECT da.course FROM DateAccess da WHERE da.user.id = :userId") List findCoursesByUserId(@Param("userId") Long userId); } From 64f924ab80076265d05bf13ccbcdea44eeacfd6b Mon Sep 17 00:00:00 2001 From: Kwak Seong Joon Date: Thu, 11 Jul 2024 00:55:43 +0900 Subject: [PATCH 11/78] =?UTF-8?q?[chore]=20final=20=EC=B6=94=EA=B0=80=20-?= =?UTF-8?q?=20#54?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/dateroad/user/api/UserController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 bb73e0ee..e2296d80 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 @@ -52,10 +52,10 @@ public ResponseEntity checkNickname(@RequestParam("name") final String nic } @PatchMapping("/reissue") - public ResponseEntity reissue(@RequestHeader(AUTHORIZATION) String refreshToken) { + public ResponseEntity reissue(@RequestHeader(AUTHORIZATION) final String refreshToken) { UserJwtInfoRes userJwtInfoRes = authService.reissue(refreshToken); return ResponseEntity .ok(userJwtInfoRes); - + } } From e7ba67517e5876fb001f4385a6bac0ee094778a5 Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Thu, 11 Jul 2024 00:56:28 +0900 Subject: [PATCH 12/78] =?UTF-8?q?[feat]=20Course=EA=B4=80=EB=A0=A8=20Dto?= =?UTF-8?q?=20=EA=B5=AC=ED=98=84=20-=20#42?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dateroad/course/api/CourseController.java | 1 + .../course/dto/request/CourseCreateReq.java | 8 ++------ ...{CourseDtoRes.java => CourseDtoGetRes.java} | 18 +++++++++--------- .../course/dto/response/CourseGetAllRes.java | 8 ++------ .../dto/response/DateAccessGetAllRes.java | 4 ++-- .../dateroad/course/facade/CourseFacade.java | 4 ++-- .../course/service/CourseTagService.java | 7 ++----- 7 files changed, 20 insertions(+), 30 deletions(-) rename dateroad-api/src/main/java/org/dateroad/course/dto/response/{CourseDtoRes.java => CourseDtoGetRes.java} (53%) 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 a1579a34..c2be0213 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 @@ -56,6 +56,7 @@ public ResponseEntity createCourse( @RequestHeader Long userId, @ModelAttribute CourseCreateReq courseCreateReq ) { + System.out.println(courseCreateReq); return ResponseEntity.created( URI.create(courseService.createCourse(userId, courseCreateReq))).build(); } diff --git a/dateroad-api/src/main/java/org/dateroad/course/dto/request/CourseCreateReq.java b/dateroad-api/src/main/java/org/dateroad/course/dto/request/CourseCreateReq.java index 1b5ce250..678e40f5 100644 --- a/dateroad-api/src/main/java/org/dateroad/course/dto/request/CourseCreateReq.java +++ b/dateroad-api/src/main/java/org/dateroad/course/dto/request/CourseCreateReq.java @@ -1,15 +1,11 @@ package org.dateroad.course.dto.request; import com.fasterxml.jackson.annotation.JsonFormat; -import com.fasterxml.jackson.annotation.JsonFormat.Shape; import java.time.LocalDate; import java.time.LocalTime; import java.util.List; import lombok.AccessLevel; import lombok.Builder; -import lombok.Getter; -import lombok.Setter; -import org.dateroad.Image.dto.request.ImageReq; import org.dateroad.tag.domain.DateTagType; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.web.multipart.MultipartFile; @@ -23,7 +19,7 @@ public record CourseCreateReq( @DateTimeFormat(pattern = "HH:mm") @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm", timezone = "Asia/Seoul") LocalTime startAt, - List tags, + List tags, String country, String city, List places, @@ -31,7 +27,7 @@ public record CourseCreateReq( int cost, List images ) { - public static CourseCreateReq of(String title, LocalDate date, LocalTime startAt, List tags, + public static CourseCreateReq of(String title, LocalDate date, LocalTime startAt, List tags, String country, String city, List places, String description, int cost, diff --git a/dateroad-api/src/main/java/org/dateroad/course/dto/response/CourseDtoRes.java b/dateroad-api/src/main/java/org/dateroad/course/dto/response/CourseDtoGetRes.java similarity index 53% rename from dateroad-api/src/main/java/org/dateroad/course/dto/response/CourseDtoRes.java rename to dateroad-api/src/main/java/org/dateroad/course/dto/response/CourseDtoGetRes.java index f536bfab..7f17640a 100644 --- a/dateroad-api/src/main/java/org/dateroad/course/dto/response/CourseDtoRes.java +++ b/dateroad-api/src/main/java/org/dateroad/course/dto/response/CourseDtoGetRes.java @@ -3,7 +3,7 @@ import lombok.Builder; @Builder -public record CourseDtoRes( +public record CourseDtoGetRes( Long courseId, String thumbnail, String city, @@ -12,14 +12,14 @@ public record CourseDtoRes( int cost, float duration ) { - public static CourseDtoRes of(Long courseId, - String thumbnail, - String city, - String title, - int like, - int cost, - float duration) { - return CourseDtoRes.builder() + public static CourseDtoGetRes of(Long courseId, + String thumbnail, + String city, + String title, + int like, + int cost, + float duration) { + return CourseDtoGetRes.builder() .courseId(courseId) .thumbnail(thumbnail) .city(city) diff --git a/dateroad-api/src/main/java/org/dateroad/course/dto/response/CourseGetAllRes.java b/dateroad-api/src/main/java/org/dateroad/course/dto/response/CourseGetAllRes.java index 4281f6be..0dd1cb8f 100644 --- a/dateroad-api/src/main/java/org/dateroad/course/dto/response/CourseGetAllRes.java +++ b/dateroad-api/src/main/java/org/dateroad/course/dto/response/CourseGetAllRes.java @@ -2,18 +2,14 @@ import java.util.List; import lombok.Builder; -import lombok.experimental.SuperBuilder; @Builder public record CourseGetAllRes( - List courses + List courses ) { - - - public static CourseGetAllRes of(List courses) { + public static CourseGetAllRes of(List courses) { return CourseGetAllRes.builder() .courses(courses) .build(); } - } diff --git a/dateroad-api/src/main/java/org/dateroad/course/dto/response/DateAccessGetAllRes.java b/dateroad-api/src/main/java/org/dateroad/course/dto/response/DateAccessGetAllRes.java index bad864f6..5c09f5d0 100644 --- a/dateroad-api/src/main/java/org/dateroad/course/dto/response/DateAccessGetAllRes.java +++ b/dateroad-api/src/main/java/org/dateroad/course/dto/response/DateAccessGetAllRes.java @@ -5,9 +5,9 @@ @Builder public record DateAccessGetAllRes( - List courses + List courses ) { - public static DateAccessGetAllRes of(List dataAccessCourse) { + public static DateAccessGetAllRes of(List dataAccessCourse) { return DateAccessGetAllRes.builder() .courses(dataAccessCourse) .build(); diff --git a/dateroad-api/src/main/java/org/dateroad/course/facade/CourseFacade.java b/dateroad-api/src/main/java/org/dateroad/course/facade/CourseFacade.java index 64d2f919..5e1efc2b 100644 --- a/dateroad-api/src/main/java/org/dateroad/course/facade/CourseFacade.java +++ b/dateroad-api/src/main/java/org/dateroad/course/facade/CourseFacade.java @@ -5,11 +5,11 @@ import lombok.RequiredArgsConstructor; import org.dateroad.Image.service.ImageService; import org.dateroad.course.dto.request.CoursePlaceGetReq; -import org.dateroad.course.dto.request.TagCreateReq; import org.dateroad.course.service.CoursePlaceService; import org.dateroad.course.service.CourseTagService; import org.dateroad.date.domain.Course; import org.dateroad.image.domain.Image; +import org.dateroad.tag.domain.DateTagType; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -36,7 +36,7 @@ public void createImage(final List images, final Course course) { } @Async - public void createCourseTags(final List tags, final Course course) { + public void createCourseTags(final List tags, final Course course) { courseTagService.createCourseTags(tags, course); } diff --git a/dateroad-api/src/main/java/org/dateroad/course/service/CourseTagService.java b/dateroad-api/src/main/java/org/dateroad/course/service/CourseTagService.java index 0bcd951b..14744193 100644 --- a/dateroad-api/src/main/java/org/dateroad/course/service/CourseTagService.java +++ b/dateroad-api/src/main/java/org/dateroad/course/service/CourseTagService.java @@ -4,13 +4,10 @@ import java.util.stream.Collectors; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; -import org.dateroad.course.dto.request.TagCreateReq; import org.dateroad.date.domain.Course; -import org.dateroad.place.domain.CoursePlace; import org.dateroad.tag.domain.CourseTag; import org.dateroad.tag.domain.DateTagType; import org.dateroad.tag.repository.CourseTagRepository; -import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -21,11 +18,11 @@ public class CourseTagService { private final CourseTagRepository courseTagRepository; @Transactional - public void createCourseTags(List tags, Course course) { + public void createCourseTags(List tags, Course course) { List coursePlaces = tags.stream() .map(tag -> CourseTag.create( course, - tag.tag() + tag )) .collect(Collectors.toList()); courseTagRepository.saveAll(coursePlaces); From 675819d7f41bda613c464c3bbbba5651371101b9 Mon Sep 17 00:00:00 2001 From: Kwak Seong Joon Date: Thu, 11 Jul 2024 01:38:25 +0900 Subject: [PATCH 13/78] =?UTF-8?q?[feat]=20=EC=9C=A0=EC=A0=80=20=EC=84=9C?= =?UTF-8?q?=EB=B9=84=EC=8A=A4=EC=97=90=20=ED=9A=8C=EC=9B=90=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=EC=A1=B0=ED=9A=8C(=EB=A9=94=EC=9D=B8)=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20-=20#57?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/dto/response/UserInfoMainRes.java | 8 ++++++ .../dateroad/user/service/UserService.java | 28 +++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 dateroad-api/src/main/java/org/dateroad/user/dto/response/UserInfoMainRes.java create mode 100644 dateroad-api/src/main/java/org/dateroad/user/service/UserService.java 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..240f446f --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/user/dto/response/UserInfoMainRes.java @@ -0,0 +1,8 @@ +package org.dateroad.user.dto.response; + +public record UserProfileMainRes( + String name, + int point, + String imageUrl +) { +} 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..46dd79e0 --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/user/service/UserService.java @@ -0,0 +1,28 @@ +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(Long userId) { + return userRepository.findById(userId) + .orElseThrow(() -> new EntityNotFoundException(FailureCode.USER_NOT_FOUND)); + } + +} From 10219669ec06037e9d98b14c5e5b20ec07f99f5a Mon Sep 17 00:00:00 2001 From: Kwak Seong Joon Date: Thu, 11 Jul 2024 01:38:44 +0900 Subject: [PATCH 14/78] =?UTF-8?q?[feat]=20UserController=EC=97=90=20?= =?UTF-8?q?=ED=9A=8C=EC=9B=90=EC=A0=95=EB=B3=B4=EC=A1=B0=ED=9A=8C=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20=EA=B5=AC=ED=98=84=20-=20#57?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/dateroad/user/api/UserController.java | 10 ++++++++++ .../user/dto/response/UserInfoMainRes.java | 15 +++++++++++++-- 2 files changed, 23 insertions(+), 2 deletions(-) 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..3596cfa6 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,11 @@ 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.UserInfoMainRes; import org.dateroad.user.dto.response.UserSignInRes; import org.dateroad.user.dto.response.UsersignUpRes; 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,6 +21,7 @@ @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, @@ -61,4 +64,11 @@ public ResponseEntity withdraw(@UserId final Long userId, .ok() .build(); } + + @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 index 240f446f..7115c16b 100644 --- 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 @@ -1,8 +1,19 @@ package org.dateroad.user.dto.response; -public record UserProfileMainRes( +import lombok.AccessLevel; +import lombok.Builder; + +@Builder(access = AccessLevel.PRIVATE) +public record UserInfoMainRes( String name, int point, - String imageUrl + String image ) { + public static UserInfoMainRes of(String name, int point, String image) { + return UserInfoMainRes.builder() + .name(name) + .point(point) + .image(image) + .build(); + } } From f7ac244a3e85be3c5a8fe6734c295678a3af84fb Mon Sep 17 00:00:00 2001 From: Kwak Seong Joon Date: Thu, 11 Jul 2024 02:27:22 +0900 Subject: [PATCH 15/78] =?UTF-8?q?[feat]=20DateController=EC=97=90=20?= =?UTF-8?q?=EA=B0=80=EA=B9=8C=EC=9A=B4=EC=9D=BC=EC=A0=95=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EA=B5=AC=ED=98=84=20-=20#58?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/dateroad/date/api/DateController.java | 8 ++++++++ .../org/dateroad/date/dto/response/DateGetNearestRes.java | 2 ++ .../src/main/java/org/dateroad/code/FailureCode.java | 1 + .../src/main/java/org/dateroad/date/domain/Date.java | 2 ++ 4 files changed, 13 insertions(+) create mode 100644 dateroad-api/src/main/java/org/dateroad/date/dto/response/DateGetNearestRes.java 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 b19a3d36..8f279ecc 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 @@ -3,6 +3,7 @@ import lombok.RequiredArgsConstructor; import org.dateroad.auth.argumentresolve.UserId; import org.dateroad.date.dto.request.DateCreateReq; +import org.dateroad.date.dto.response.DateGetNearestRes; import org.dateroad.date.service.DateService; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -27,4 +28,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/DateGetNearestRes.java b/dateroad-api/src/main/java/org/dateroad/date/dto/response/DateGetNearestRes.java new file mode 100644 index 00000000..a1ad0a17 --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/date/dto/response/DateGetNearestRes.java @@ -0,0 +1,2 @@ +package org.dateroad.date.dto.response;public record DateGetNearestRes() { +} 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 77fa8f1d..aceab748 100644 --- a/dateroad-common/src/main/java/org/dateroad/code/FailureCode.java +++ b/dateroad-common/src/main/java/org/dateroad/code/FailureCode.java @@ -53,6 +53,7 @@ public enum FailureCode { USER_NOT_FOUND(HttpStatus.NOT_FOUND, "e4042", "유저를 찾을 수 없습니다."), COURSE_THUMBNAIL_NOT_FOUND(HttpStatus.NOT_FOUND, "e4043", "코스 썸네일을 찾을수 없습니다."), DATE_NOT_FOUND(HttpStatus.NOT_FOUND, "e4044", "데이트를 찾을 수 없습니다."), + NEAREST_DATE_NOT_FOUND(HttpStatus.NOT_FOUND, "e4045", "다가오는 데이트를 찾을 수 없습니다."), /** * 405 Method Not Allowed diff --git a/dateroad-domain/src/main/java/org/dateroad/date/domain/Date.java b/dateroad-domain/src/main/java/org/dateroad/date/domain/Date.java index d750aee5..d6324723 100644 --- a/dateroad-domain/src/main/java/org/dateroad/date/domain/Date.java +++ b/dateroad-domain/src/main/java/org/dateroad/date/domain/Date.java @@ -10,6 +10,7 @@ import java.time.LocalTime; import lombok.AccessLevel; import lombok.AllArgsConstructor; +import lombok.Getter; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; import org.dateroad.user.domain.User; @@ -18,6 +19,7 @@ @SuperBuilder @NoArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor(access = AccessLevel.PRIVATE) +@Getter @Table(name = "dates") public class Date extends DateBase { @Id From 88f74a72d52ac7ffe9552ec4dcce134229b9d2d5 Mon Sep 17 00:00:00 2001 From: Kwak Seong Joon Date: Thu, 11 Jul 2024 02:27:34 +0900 Subject: [PATCH 16/78] =?UTF-8?q?[feat]=20DTO=20=EC=B6=94=EA=B0=80=20-=20#?= =?UTF-8?q?58?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../date/dto/request/DateCreateReq.java | 2 +- .../date/dto/response/DateGetNearestRes.java | 37 ++++++++++++++++++- 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/dateroad-api/src/main/java/org/dateroad/date/dto/request/DateCreateReq.java b/dateroad-api/src/main/java/org/dateroad/date/dto/request/DateCreateReq.java index 57832b3f..f93de9d9 100644 --- a/dateroad-api/src/main/java/org/dateroad/date/dto/request/DateCreateReq.java +++ b/dateroad-api/src/main/java/org/dateroad/date/dto/request/DateCreateReq.java @@ -10,7 +10,7 @@ public record DateCreateReq( String title, @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy.MM.dd", timezone = "Asia/Seoul") LocalDate date, - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm", timezone = "Asia/Seoul") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "hh:mm a", timezone = "Asia/Seoul") LocalTime startAt, List tags, String country, 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 index a1ad0a17..07138a62 100644 --- 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 @@ -1,2 +1,37 @@ -package org.dateroad.date.dto.response;public record DateGetNearestRes() { +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(); + } + } From 5725396624f23b20798e122bc7edfbb785140643 Mon Sep 17 00:00:00 2001 From: Kwak Seong Joon Date: Thu, 11 Jul 2024 02:27:52 +0900 Subject: [PATCH 17/78] =?UTF-8?q?[feat]=20=EA=B0=80=EA=B9=8C=EC=9A=B4=20?= =?UTF-8?q?=EC=9D=BC=EC=A0=95=20=EA=B0=80=EC=A0=B8=EC=98=A4=EA=B8=B0=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20-=20#58?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dateroad/date/service/DateRepository.java | 8 +++++ .../dateroad/date/service/DateService.java | 31 +++++++++++++++++++ 2 files changed, 39 insertions(+) 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..3758eb34 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,14 @@ import org.dateroad.date.domain.Date; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.repository.query.Param; + +import java.time.LocalDate; +import java.util.Optional; public interface DateRepository extends JpaRepository { + + Optional findTopByUserIdAndDateAfterOrderByDateAscStartAtAsc( + @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 005a5943..a110d34f 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 @@ -1,11 +1,13 @@ package org.dateroad.date.service; import lombok.RequiredArgsConstructor; +import lombok.experimental.SuperBuilder; import org.dateroad.code.FailureCode; import org.dateroad.date.domain.Date; import org.dateroad.date.dto.request.DateCreateReq; import org.dateroad.date.dto.request.PlaceCreateReq; import org.dateroad.date.dto.request.TagCreateReq; +import org.dateroad.date.dto.response.DateGetNearestRes; import org.dateroad.date.repository.DatePlaceRepository; import org.dateroad.date.repository.DateTagRepository; import org.dateroad.exception.EntityNotFoundException; @@ -17,6 +19,8 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.time.LocalDate; +import java.time.temporal.ChronoUnit; import java.util.List; @RequiredArgsConstructor @@ -46,6 +50,22 @@ public void deleteDate(Long userId, Long dateId) { dateRepository.deleteById(dateId); } + public DateGetNearestRes getNearestDate(final Long userId) { + LocalDate currentDate = LocalDate.now(); + User findUser = getUser(userId); + Date nearest = findNearestDate(findUser.getId(), currentDate) ; + 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)); @@ -79,4 +99,15 @@ private void validateDate(User findUser, Date findDate) { throw new ForbiddenException(FailureCode.DATE_DELETE_ACCESS_DENIED); } } + + //dDay 계산 + private int calculateDDay(final LocalDate eventDate, final LocalDate now) { + return (int) ChronoUnit.DAYS.between(now, eventDate); + } + + //가장 가까운 데이트 가져오기 + private Date findNearestDate(final Long userId, final LocalDate now) { + return dateRepository.findTopByUserIdAndDateAfterOrderByDateAscStartAtAsc(userId, now) + .orElseThrow(() -> new EntityNotFoundException(FailureCode.NEAREST_DATE_NOT_FOUND)); + } } From 0490ae8865989fb25d7ca183099bc22a483bd554 Mon Sep 17 00:00:00 2001 From: Kwak Seong Joon Date: Thu, 11 Jul 2024 02:32:15 +0900 Subject: [PATCH 18/78] =?UTF-8?q?[feat]=20=EC=9E=AC=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=EC=8B=9C=20refreshToken=20=EC=82=AD=EC=A0=9C=20-=20#5?= =?UTF-8?q?4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/dateroad/user/service/AuthService.java | 1 + .../java/org/dateroad/refreshtoken/domain/RefreshToken.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) 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 9ad5026e..45260681 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 @@ -60,6 +60,7 @@ public UserJwtInfoRes signUp(final String token, final UserSignUpReq userSignUpR 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 UserJwtInfoRes.of(foundUser.getId(), issuedToken.accessToken(), issuedToken.refreshToken()); } 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 1f952579..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 @@ -12,7 +12,7 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor(access = AccessLevel.PRIVATE) @Getter -@Table(name = "refreshtoken") +@Table(name = "refresh_token") @Entity public class RefreshToken { From b28376caff1462db81016acb511afb000719bb89 Mon Sep 17 00:00:00 2001 From: Kwak Seong Joon Date: Thu, 11 Jul 2024 04:31:04 +0900 Subject: [PATCH 19/78] =?UTF-8?q?[feat]=20=EA=B0=80=EC=9E=A5=20=EA=B0=80?= =?UTF-8?q?=EA=B9=8C=EC=9A=B4=20=EC=9D=BC=EC=A0=95=20=EA=B0=80=EC=A0=B8?= =?UTF-8?q?=EC=98=A4=EA=B8=B0=20=EA=B5=AC=ED=98=84=20-=20#58?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../date/dto/request/DateCreateReq.java | 2 +- .../dateroad/date/service/DateRepository.java | 10 +++---- .../dateroad/date/service/DateService.java | 30 +++++++++++-------- 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/dateroad-api/src/main/java/org/dateroad/date/dto/request/DateCreateReq.java b/dateroad-api/src/main/java/org/dateroad/date/dto/request/DateCreateReq.java index f93de9d9..57832b3f 100644 --- a/dateroad-api/src/main/java/org/dateroad/date/dto/request/DateCreateReq.java +++ b/dateroad-api/src/main/java/org/dateroad/date/dto/request/DateCreateReq.java @@ -10,7 +10,7 @@ public record DateCreateReq( String title, @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy.MM.dd", timezone = "Asia/Seoul") LocalDate date, - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "hh:mm a", timezone = "Asia/Seoul") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm", timezone = "Asia/Seoul") LocalTime startAt, List tags, String country, 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 3758eb34..6f3ce0c7 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,14 +2,14 @@ import org.dateroad.date.domain.Date; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.repository.query.Param; import java.time.LocalDate; +import java.time.LocalTime; import java.util.Optional; public interface DateRepository extends JpaRepository { - - Optional findTopByUserIdAndDateAfterOrderByDateAscStartAtAsc( - @Param("userId") Long userId, - @Param("currentDate") LocalDate currentDate); + Optional findFirstByUserIdAndDateAfterOrDateAndStartAtAfterOrderByDateAscStartAtAsc( + Long userId, LocalDate currentDate, LocalDate sameDay, LocalTime currentTime); } + + 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 a110d34f..88e8335b 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 @@ -1,7 +1,6 @@ package org.dateroad.date.service; import lombok.RequiredArgsConstructor; -import lombok.experimental.SuperBuilder; import org.dateroad.code.FailureCode; import org.dateroad.date.domain.Date; import org.dateroad.date.dto.request.DateCreateReq; @@ -20,6 +19,7 @@ import org.springframework.transaction.annotation.Transactional; import java.time.LocalDate; +import java.time.LocalTime; import java.time.temporal.ChronoUnit; import java.util.List; @@ -52,18 +52,19 @@ public void deleteDate(Long userId, Long 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) ; - int dDay = calculateDDay(nearest.getDate(), currentDate); + Date nearest = findNearestDate(findUser.getId(), currentDate, currentTime); ; + int dDay = calculateDDay(nearest.getDateDay(), currentDate); return DateGetNearestRes .of( nearest.getId(), dDay, nearest.getTitle(), - nearest.getDate().getMonthValue(), - nearest.getDate().getDayOfMonth(), - nearest.getStartAt()); - + nearest.getDateDay().getMonthValue(), + nearest.getDateDay().getDayOfMonth(), + nearest.getStartAt() + ); } private User getUser(Long userId) { @@ -101,13 +102,18 @@ private void validateDate(User findUser, Date findDate) { } //dDay 계산 - private int calculateDDay(final LocalDate eventDate, final LocalDate now) { - return (int) ChronoUnit.DAYS.between(now, eventDate); + private int calculateDDay(LocalDate eventDate, LocalDate currentDate) { + if (eventDate.isEqual(currentDate)) { + return 0; + } else { + return (int) ChronoUnit.DAYS.between(currentDate, eventDate); + } } //가장 가까운 데이트 가져오기 - private Date findNearestDate(final Long userId, final LocalDate now) { - return dateRepository.findTopByUserIdAndDateAfterOrderByDateAscStartAtAsc(userId, now) - .orElseThrow(() -> new EntityNotFoundException(FailureCode.NEAREST_DATE_NOT_FOUND)); + private Date findNearestDate(Long userId, LocalDate currentDate, LocalTime currentTime) { + return dateRepository.findFirstByUserIdAndDateAfterOrDateAndStartAtAfterOrderByDateAscStartAtAsc(userId, currentDate, currentDate, currentTime) + .orElseThrow(() -> new EntityNotFoundException(FailureCode.DATE_NOT_FOUND)); } + } From 197c573622de96215ff771d08f113ef65cdbb200 Mon Sep 17 00:00:00 2001 From: Kwak Seong Joon Date: Thu, 11 Jul 2024 04:42:05 +0900 Subject: [PATCH 20/78] =?UTF-8?q?[fix]=20=EB=B3=80=EC=88=98=EB=AA=85=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20-=20#58?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/dateroad/date/service/DateService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 88e8335b..a5f41813 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 @@ -55,14 +55,14 @@ public DateGetNearestRes getNearestDate(final Long userId) { LocalTime currentTime = LocalTime.now(); User findUser = getUser(userId); Date nearest = findNearestDate(findUser.getId(), currentDate, currentTime); ; - int dDay = calculateDDay(nearest.getDateDay(), currentDate); + int dDay = calculateDDay(nearest.getDate(), currentDate); return DateGetNearestRes .of( nearest.getId(), dDay, nearest.getTitle(), - nearest.getDateDay().getMonthValue(), - nearest.getDateDay().getDayOfMonth(), + nearest.getDate().getMonthValue(), + nearest.getDate().getDayOfMonth(), nearest.getStartAt() ); } From 987714241028dd28afa6b6eb4dc2d99160ece84e Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Thu, 11 Jul 2024 09:29:52 +0900 Subject: [PATCH 21/78] =?UTF-8?q?[feat]=20course=20=EC=83=9D=EC=84=B1=20AP?= =?UTF-8?q?I=20Controller=20,Service=20,=20Repository=20=EA=B5=AC=ED=98=84?= =?UTF-8?q?=20-=20#42?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dateroad/Image/service/ImageService.java | 10 ++-- .../dateroad/course/api/CourseController.java | 30 ++++++------ .../course/dto/request/CourseCreateReq.java | 18 ++++---- .../dateroad/course/facade/CourseFacade.java | 15 +++--- .../course/service/CoursePlaceService.java | 10 ++-- .../course/service/CourseService.java | 46 +++++++++++-------- .../course/service/CourseTagService.java | 11 +++-- .../repository/CoursePlaceRepository.java | 2 + .../user/repository/UserRepository.java | 1 + 9 files changed, 81 insertions(+), 62 deletions(-) diff --git a/dateroad-api/src/main/java/org/dateroad/Image/service/ImageService.java b/dateroad-api/src/main/java/org/dateroad/Image/service/ImageService.java index c1b03325..d24965fa 100644 --- a/dateroad-api/src/main/java/org/dateroad/Image/service/ImageService.java +++ b/dateroad-api/src/main/java/org/dateroad/Image/service/ImageService.java @@ -18,21 +18,23 @@ @Service @RequiredArgsConstructor +@Transactional(readOnly = true) public class ImageService { private final ImageRepository imageRepository; private final S3Service s3Service; @Value("${s3.bucket.path}") private String path; + @Value("${cloudfront.domain}") + private String cachePath; - @Transactional - public void saveImages(final List images, final Course course) { + public String saveImages(final List images, final Course course) { AtomicInteger sequence = new AtomicInteger(); List courseimages = images.stream() .map(img -> { try { return Image.create( course, - s3Service.uploadImage(path, img).get(), + cachePath + s3Service.uploadImage(path, img).get(), sequence.getAndIncrement() ); } catch (IOException | ExecutionException | InterruptedException e) { @@ -40,7 +42,7 @@ public void saveImages(final List images, final Course course) { } }) .toList(); - imageRepository.saveAll(courseimages); + return imageRepository.saveAll(courseimages).getFirst().getImageUrl(); } public Image findFirstByCourseOrderBySequenceAsc(Course course) { 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 c2be0213..e336cc3c 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,39 +1,36 @@ package org.dateroad.course.api; -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.media.Content; -import java.net.MulticastSocket; import java.net.URI; import java.util.List; -import javax.xml.crypto.OctetStreamData; import lombok.RequiredArgsConstructor; -import org.dateroad.Image.dto.request.ImageReq; import org.dateroad.auth.argumentresolve.UserId; import org.dateroad.course.dto.request.CourseGetAllReq; import org.dateroad.course.dto.request.CourseCreateReq; +import org.dateroad.course.dto.request.CoursePlaceGetReq; +import org.dateroad.course.dto.request.TagCreateReq; import org.dateroad.course.dto.response.CourseGetAllRes; import org.dateroad.course.dto.response.DateAccessGetAllRes; +import org.dateroad.course.facade.CourseFacade; import org.dateroad.course.service.CourseService; +import org.dateroad.date.domain.Course; 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.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.RequestParam; import org.springframework.web.bind.annotation.RequestPart; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; @RestController -//@RequestMapping("/api/v1/courses") -@RequestMapping("/api/v1") +@RequestMapping("/api/v1/courses") @RequiredArgsConstructor public class CourseController { private final CourseService courseService; + private final CourseFacade courseFacade; @GetMapping public ResponseEntity getAllCourse( @@ -51,13 +48,18 @@ public ResponseEntity getAllDataAccesCourse( return ResponseEntity.ok(dateAccessGetAllRes); } - @PostMapping("/c") + @PostMapping(value = "/create", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_JSON_VALUE}) public ResponseEntity createCourse( - @RequestHeader Long userId, - @ModelAttribute CourseCreateReq courseCreateReq + @RequestHeader final Long userId, + @RequestPart("course") final CourseCreateReq courseCreateReq, + @RequestPart("tags") final List tags, + @RequestPart("places") final List places, + @RequestPart("images") final List images ) { - System.out.println(courseCreateReq); + Course course = courseService.createCourse(userId, courseCreateReq, places, images); + courseFacade.createCoursePlace(places, course); + courseFacade.createCourseTags(tags, course); return ResponseEntity.created( - URI.create(courseService.createCourse(userId, courseCreateReq))).build(); + URI.create(course.getId().toString())).build(); } } diff --git a/dateroad-api/src/main/java/org/dateroad/course/dto/request/CourseCreateReq.java b/dateroad-api/src/main/java/org/dateroad/course/dto/request/CourseCreateReq.java index 678e40f5..dd7de8d0 100644 --- a/dateroad-api/src/main/java/org/dateroad/course/dto/request/CourseCreateReq.java +++ b/dateroad-api/src/main/java/org/dateroad/course/dto/request/CourseCreateReq.java @@ -4,14 +4,14 @@ import java.time.LocalDate; import java.time.LocalTime; import java.util.List; -import lombok.AccessLevel; import lombok.Builder; import org.dateroad.tag.domain.DateTagType; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.web.multipart.MultipartFile; -@Builder(access = AccessLevel.PROTECTED) -public record CourseCreateReq( +//@Builder(access = AccessLevel.PROTECTED) +@Builder +public record CourseCreateReq1( String title, @DateTimeFormat(pattern = "yyyy.MM.dd") @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy.MM.dd", timezone = "Asia/Seoul") @@ -27,12 +27,12 @@ public record CourseCreateReq( int cost, List images ) { - public static CourseCreateReq of(String title, LocalDate date, LocalTime startAt, List tags, - String country, - String city, - List places, String description, int cost, - List images) { - return CourseCreateReq.builder() + public static CourseCreateReq1 of(String title, LocalDate date, LocalTime startAt, List tags, + String country, + String city, + List places, String description, int cost, + List images) { + return CourseCreateReq1.builder() .title(title) .date(date) .startAt(startAt) diff --git a/dateroad-api/src/main/java/org/dateroad/course/facade/CourseFacade.java b/dateroad-api/src/main/java/org/dateroad/course/facade/CourseFacade.java index 5e1efc2b..9fc3a869 100644 --- a/dateroad-api/src/main/java/org/dateroad/course/facade/CourseFacade.java +++ b/dateroad-api/src/main/java/org/dateroad/course/facade/CourseFacade.java @@ -5,11 +5,11 @@ import lombok.RequiredArgsConstructor; import org.dateroad.Image.service.ImageService; import org.dateroad.course.dto.request.CoursePlaceGetReq; +import org.dateroad.course.dto.request.TagCreateReq; import org.dateroad.course.service.CoursePlaceService; import org.dateroad.course.service.CourseTagService; import org.dateroad.date.domain.Course; import org.dateroad.image.domain.Image; -import org.dateroad.tag.domain.DateTagType; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -20,8 +20,8 @@ @Transactional(readOnly = true) public class CourseFacade { private final CoursePlaceService coursePlaceService; - private final ImageService imageService; private final CourseTagService courseTagService; + private final ImageService imageService; public Image findFirstByCourseOrderBySequenceAsc(final Course course) { return imageService.findFirstByCourseOrderBySequenceAsc(course); @@ -31,17 +31,18 @@ public float findTotalDurationByCourseId(final Long id) { return coursePlaceService.findTotalDurationByCourseId(id); } - public void createImage(final List images, final Course course) { - imageService.saveImages(images, course); + @Transactional + public String createImage(final List images, final Course course) { + return imageService.saveImages(images, course); } @Async - public void createCourseTags(final List tags, final Course course) { + public void createCourseTags(final List tags, final Course course) { courseTagService.createCourseTags(tags, course); } @Async - public void createCoursePlaces(final List places,final Course course) { - coursePlaceService.createCoursePlace(places,course); + public void createCoursePlace(final List places, final Course course) { + coursePlaceService.createCoursePlace(places, course); } } diff --git a/dateroad-api/src/main/java/org/dateroad/course/service/CoursePlaceService.java b/dateroad-api/src/main/java/org/dateroad/course/service/CoursePlaceService.java index 6524bc77..3d6d3ee3 100644 --- a/dateroad-api/src/main/java/org/dateroad/course/service/CoursePlaceService.java +++ b/dateroad-api/src/main/java/org/dateroad/course/service/CoursePlaceService.java @@ -8,6 +8,7 @@ import org.dateroad.date.domain.Course; import org.dateroad.place.domain.CoursePlace; import org.dateroad.place.repository.CoursePlaceRepository; +import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -20,16 +21,17 @@ public float findTotalDurationByCourseId(final Long id) { return coursePlaceRepository.findTotalDurationByCourseId(id); } + @Async @Transactional public void createCoursePlace(final List places, final Course course) { List coursePlaces = places.stream() .map(placeReq -> CoursePlace.create( - placeReq.title(), - placeReq.duration(), + placeReq.getTitle(), + placeReq.getDuration(), course, - placeReq.sequence() + placeReq.getSequence() )) .collect(Collectors.toList()); - coursePlaceRepository.saveAll(coursePlaces); + coursePlaceRepository.saveAllAndFlush(coursePlaces); } } 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 a4cd962f..02f6c6e9 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 @@ -5,6 +5,7 @@ import java.util.stream.Collectors; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; +import org.dateroad.code.FailureCode; import org.dateroad.course.dto.request.CourseGetAllReq; import org.dateroad.course.dto.request.CourseCreateReq; import org.dateroad.course.dto.request.CoursePlaceGetReq; @@ -15,11 +16,15 @@ import org.dateroad.date.domain.Course; import org.dateroad.date.repository.CourseRepository; import org.dateroad.dateAccess.repository.DateAccessRepository; +import org.dateroad.exception.DateRoadException; import org.dateroad.image.domain.Image; import org.dateroad.like.repository.LikeRepository; +import org.dateroad.user.domain.User; +import org.dateroad.user.repository.UserRepository; import org.springframework.data.jpa.domain.Specification; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; @Service @RequiredArgsConstructor(access = AccessLevel.PROTECTED) @@ -28,6 +33,7 @@ public class CourseService { private final CourseRepository courseRepository; private final LikeRepository likeRepository; private final DateAccessRepository dateAccessRepository; + private final UserRepository userRepository; private final CourseFacade courseFacade; public CourseGetAllRes getAllCourses(CourseGetAllReq courseGetAllReq) { @@ -68,26 +74,28 @@ public DateAccessGetAllRes getAllDataAccessCourse(Long userId) { } @Transactional - public String createCourse(Long userId, CourseCreateReq courseRegisterReq) { - System.out.println(courseRegisterReq); - final float totalTime = courseRegisterReq.places().stream() - .map(CoursePlaceGetReq::duration) // 각 CoursePlaceGetReq 객체의 duration 값을 추출 - .reduce(0.0f, Float::sum); // 모든 duration 값을 합산 - - final Course course = Course.create( - courseRegisterReq.title(), - courseRegisterReq.description(), - courseRegisterReq.country(), - courseRegisterReq.city(), - courseRegisterReq.cost(), - courseRegisterReq.date(), - courseRegisterReq.startAt(), + 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) + ); + Course course = Course.create( + user, + courseRegisterReq.getTitle(), + courseRegisterReq.getDescription(), + courseRegisterReq.getCountry(), + courseRegisterReq.getCity(), + courseRegisterReq.getCost(), + courseRegisterReq.getDate(), + courseRegisterReq.getStartAt(), totalTime ); - courseFacade.createImage(courseRegisterReq.images(), course); - courseFacade.createCoursePlaces(courseRegisterReq.places(), course); - courseFacade.createCourseTags(courseRegisterReq.tags(), course); - - return courseRepository.save(course).getId().toString(); + Course saveCourse = courseRepository.save(course); + course.setThumbnail(courseFacade.createImage(images, saveCourse)); + return saveCourse; } } diff --git a/dateroad-api/src/main/java/org/dateroad/course/service/CourseTagService.java b/dateroad-api/src/main/java/org/dateroad/course/service/CourseTagService.java index 14744193..d3b625d8 100644 --- a/dateroad-api/src/main/java/org/dateroad/course/service/CourseTagService.java +++ b/dateroad-api/src/main/java/org/dateroad/course/service/CourseTagService.java @@ -4,27 +4,28 @@ import java.util.stream.Collectors; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; +import org.dateroad.course.dto.request.TagCreateReq; import org.dateroad.date.domain.Course; import org.dateroad.tag.domain.CourseTag; -import org.dateroad.tag.domain.DateTagType; import org.dateroad.tag.repository.CourseTagRepository; +import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @Service @RequiredArgsConstructor(access = AccessLevel.PROTECTED) -@Transactional(readOnly = true) public class CourseTagService { private final CourseTagRepository courseTagRepository; + @Async @Transactional - public void createCourseTags(List tags, Course course) { + public void createCourseTags(final List tags, final Course course) { List coursePlaces = tags.stream() .map(tag -> CourseTag.create( course, - tag + tag.getTag() )) .collect(Collectors.toList()); - courseTagRepository.saveAll(coursePlaces); + courseTagRepository.saveAllAndFlush(coursePlaces); } } \ No newline at end of file diff --git a/dateroad-domain/src/main/java/org/dateroad/place/repository/CoursePlaceRepository.java b/dateroad-domain/src/main/java/org/dateroad/place/repository/CoursePlaceRepository.java index c55db46d..63816eb4 100644 --- a/dateroad-domain/src/main/java/org/dateroad/place/repository/CoursePlaceRepository.java +++ b/dateroad-domain/src/main/java/org/dateroad/place/repository/CoursePlaceRepository.java @@ -1,5 +1,6 @@ package org.dateroad.place.repository; +import java.util.List; import org.dateroad.place.domain.CoursePlace; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; @@ -10,4 +11,5 @@ public interface CoursePlaceRepository extends JpaRepository { @Query("SELECT SUM(p.duration) FROM CoursePlace p WHERE p.course.id = :courseId") Float findTotalDurationByCourseId(@Param("courseId") Long courseId); + } diff --git a/dateroad-domain/src/main/java/org/dateroad/user/repository/UserRepository.java b/dateroad-domain/src/main/java/org/dateroad/user/repository/UserRepository.java index 03875f20..782cc0eb 100644 --- a/dateroad-domain/src/main/java/org/dateroad/user/repository/UserRepository.java +++ b/dateroad-domain/src/main/java/org/dateroad/user/repository/UserRepository.java @@ -1,5 +1,6 @@ package org.dateroad.user.repository; +import java.util.List; import org.dateroad.user.domain.Platform; import org.dateroad.user.domain.User; import org.springframework.data.jpa.repository.JpaRepository; From af43ab1948c8f380fd535b8a9ec5c059593d6a19 Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Thu, 11 Jul 2024 09:30:39 +0900 Subject: [PATCH 22/78] =?UTF-8?q?[feat]=20Course=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?=EA=B4=80=EB=A0=A8=20Dto=20=EA=B5=AC=ED=98=84=20-=20#42?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../course/dto/request/CourseCreateReq.java | 65 ++++++++++--------- .../course/dto/request/CoursePlaceGetReq.java | 21 ++++-- .../course/dto/request/TagCreateReq.java | 20 ++++-- .../course/dto/response/CourseDtoGetRes.java | 3 +- .../course/dto/response/CourseGetAllRes.java | 3 +- .../dto/response/DateAccessGetAllRes.java | 3 +- 6 files changed, 68 insertions(+), 47 deletions(-) diff --git a/dateroad-api/src/main/java/org/dateroad/course/dto/request/CourseCreateReq.java b/dateroad-api/src/main/java/org/dateroad/course/dto/request/CourseCreateReq.java index dd7de8d0..ef8b9fc9 100644 --- a/dateroad-api/src/main/java/org/dateroad/course/dto/request/CourseCreateReq.java +++ b/dateroad-api/src/main/java/org/dateroad/course/dto/request/CourseCreateReq.java @@ -3,46 +3,49 @@ import com.fasterxml.jackson.annotation.JsonFormat; import java.time.LocalDate; import java.time.LocalTime; -import java.util.List; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; import lombok.Builder; -import org.dateroad.tag.domain.DateTagType; +import lombok.Data; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.RequiredArgsConstructor; import org.springframework.format.annotation.DateTimeFormat; -import org.springframework.web.multipart.MultipartFile; - -//@Builder(access = AccessLevel.PROTECTED) -@Builder -public record CourseCreateReq1( - String title, - @DateTimeFormat(pattern = "yyyy.MM.dd") - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy.MM.dd", timezone = "Asia/Seoul") - LocalDate date, - @DateTimeFormat(pattern = "HH:mm") - @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm", timezone = "Asia/Seoul") - LocalTime startAt, - List tags, - String country, - String city, - List places, - String description, - int cost, - List images -) { - public static CourseCreateReq1 of(String title, LocalDate date, LocalTime startAt, List tags, - String country, - String city, - List places, String description, int cost, - List images) { - return CourseCreateReq1.builder() + +@Getter +@Builder(access = AccessLevel.PRIVATE) +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public class CourseCreateReq { + private String title; + + @DateTimeFormat(pattern = "yyyy.MM.dd") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy.MM.dd", timezone = "Asia/Seoul") + private LocalDate date; + + @DateTimeFormat(pattern = "HH:mm") + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm", timezone = "Asia/Seoul") + private LocalTime startAt; + + private String country; + + private String city; + + private String description; + + private int cost; + + public static CourseCreateReq of(final String title,final LocalDate date,final LocalTime startAt, + final String country,final String city,final String description, + int cost) { + return CourseCreateReq.builder() .title(title) .date(date) .startAt(startAt) - .tags(tags) .country(country) .city(city) - .places(places) .description(description) .cost(cost) - .images(images) .build(); } } diff --git a/dateroad-api/src/main/java/org/dateroad/course/dto/request/CoursePlaceGetReq.java b/dateroad-api/src/main/java/org/dateroad/course/dto/request/CoursePlaceGetReq.java index d2da6e21..5b29267c 100644 --- a/dateroad-api/src/main/java/org/dateroad/course/dto/request/CoursePlaceGetReq.java +++ b/dateroad-api/src/main/java/org/dateroad/course/dto/request/CoursePlaceGetReq.java @@ -1,15 +1,22 @@ package org.dateroad.course.dto.request; import lombok.AccessLevel; +import lombok.AllArgsConstructor; import lombok.Builder; +import lombok.Data; +import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; -@Builder -public record CoursePlaceGetReq( - String title, - float duration, - int sequence -) { +@Getter +@Builder(access = AccessLevel.PRIVATE) +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public class CoursePlaceGetReq { + private String title; + private float duration; + private int sequence; + public static CoursePlaceGetReq of(String title, float duration, int sequence) { return CoursePlaceGetReq.builder() .title(title) @@ -17,4 +24,4 @@ public static CoursePlaceGetReq of(String title, float duration, int sequence) { .sequence(sequence) .build(); } -} +} \ No newline at end of file diff --git a/dateroad-api/src/main/java/org/dateroad/course/dto/request/TagCreateReq.java b/dateroad-api/src/main/java/org/dateroad/course/dto/request/TagCreateReq.java index 8d37c1fe..e994416d 100644 --- a/dateroad-api/src/main/java/org/dateroad/course/dto/request/TagCreateReq.java +++ b/dateroad-api/src/main/java/org/dateroad/course/dto/request/TagCreateReq.java @@ -1,16 +1,24 @@ package org.dateroad.course.dto.request; +import lombok.AccessLevel; +import lombok.AllArgsConstructor; import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; import org.dateroad.tag.domain.DateTagType; -@Builder -public record TagCreateReq( - DateTagType tag -) { +@Getter +@Setter +@Builder(access = AccessLevel.PRIVATE) +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@AllArgsConstructor(access = AccessLevel.PRIVATE) +public class TagCreateReq{ + private DateTagType tag; + public static TagCreateReq of(DateTagType tag) { - return TagCreateReq.builder().tag(tag).build(); + return TagCreateReq.builder() + .tag(tag).build(); } - } \ No newline at end of file diff --git a/dateroad-api/src/main/java/org/dateroad/course/dto/response/CourseDtoGetRes.java b/dateroad-api/src/main/java/org/dateroad/course/dto/response/CourseDtoGetRes.java index 7f17640a..fe2a6cda 100644 --- a/dateroad-api/src/main/java/org/dateroad/course/dto/response/CourseDtoGetRes.java +++ b/dateroad-api/src/main/java/org/dateroad/course/dto/response/CourseDtoGetRes.java @@ -1,8 +1,9 @@ package org.dateroad.course.dto.response; +import lombok.AccessLevel; import lombok.Builder; -@Builder +@Builder(access = AccessLevel.PRIVATE) public record CourseDtoGetRes( Long courseId, String thumbnail, diff --git a/dateroad-api/src/main/java/org/dateroad/course/dto/response/CourseGetAllRes.java b/dateroad-api/src/main/java/org/dateroad/course/dto/response/CourseGetAllRes.java index 0dd1cb8f..9b95d6be 100644 --- a/dateroad-api/src/main/java/org/dateroad/course/dto/response/CourseGetAllRes.java +++ b/dateroad-api/src/main/java/org/dateroad/course/dto/response/CourseGetAllRes.java @@ -1,9 +1,10 @@ package org.dateroad.course.dto.response; import java.util.List; +import lombok.AccessLevel; import lombok.Builder; -@Builder +@Builder(access = AccessLevel.PRIVATE) public record CourseGetAllRes( List courses ) { diff --git a/dateroad-api/src/main/java/org/dateroad/course/dto/response/DateAccessGetAllRes.java b/dateroad-api/src/main/java/org/dateroad/course/dto/response/DateAccessGetAllRes.java index 5c09f5d0..b4cc9d12 100644 --- a/dateroad-api/src/main/java/org/dateroad/course/dto/response/DateAccessGetAllRes.java +++ b/dateroad-api/src/main/java/org/dateroad/course/dto/response/DateAccessGetAllRes.java @@ -1,9 +1,10 @@ package org.dateroad.course.dto.response; import java.util.List; +import lombok.AccessLevel; import lombok.Builder; -@Builder +@Builder(access = AccessLevel.PRIVATE) public record DateAccessGetAllRes( List courses ) { From 82a61a94ec993e721f9da71d21f75c0a45a693a1 Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Thu, 11 Jul 2024 09:31:26 +0900 Subject: [PATCH 23/78] =?UTF-8?q?[del]=20DateBase=20thumbnail=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0=20-=20#42?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/dateroad/date/domain/DateBase.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/dateroad-domain/src/main/java/org/dateroad/date/domain/DateBase.java b/dateroad-domain/src/main/java/org/dateroad/date/domain/DateBase.java index 7d0c1ff0..0a48e12a 100644 --- a/dateroad-domain/src/main/java/org/dateroad/date/domain/DateBase.java +++ b/dateroad-domain/src/main/java/org/dateroad/date/domain/DateBase.java @@ -47,8 +47,4 @@ public abstract class DateBase extends BaseTimeEntity { @Column(name = "city") @NotNull private String city; - - @Column(name = "thumbnail") - @NotNull - private String thumbnail; } From f289593e5e3c5e9a5ab09e5164614844a471dfe1 Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Thu, 11 Jul 2024 09:31:40 +0900 Subject: [PATCH 24/78] =?UTF-8?q?[feat]=20Course=20=EC=8D=B8=EB=84=A4?= =?UTF-8?q?=EC=9D=BC=20=ED=95=84=EB=93=9C=20=EC=B6=94=EA=B0=80=20-=20#42?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/dateroad/date/domain/Course.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/dateroad-domain/src/main/java/org/dateroad/date/domain/Course.java b/dateroad-domain/src/main/java/org/dateroad/date/domain/Course.java index 4bfe4539..baa1e452 100644 --- a/dateroad-domain/src/main/java/org/dateroad/date/domain/Course.java +++ b/dateroad-domain/src/main/java/org/dateroad/date/domain/Course.java @@ -15,7 +15,9 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.Setter; import lombok.experimental.SuperBuilder; +import org.dateroad.user.domain.User; import org.springframework.data.jpa.domain.support.AuditingEntityListener; @Entity @@ -43,11 +45,16 @@ public class Course extends DateBase { @NotNull private float time; - public static Course create(final String title, final String description, + @Setter + @Column(name = "thumbnail") + private String thumbnail; + + public static Course create(final User user, final String title, final String description, final String country, final String city, final int cost, final LocalDate date, final LocalTime startAt, final float time) { return Course.builder() + .user(user) .title(title) .description(description) .city(city) From 0b26e526da0025358137ca88cff8ca640acb3db3 Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Thu, 11 Jul 2024 15:45:40 +0900 Subject: [PATCH 25/78] =?UTF-8?q?[refactor]=20userId=20=EC=96=B4=EB=85=B8?= =?UTF-8?q?=ED=85=8C=EC=9D=B4=EC=85=98=20=EB=B3=80=EA=B2=BD=20-=20#42?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/dateroad/course/api/CourseController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 e336cc3c..4343635f 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 @@ -50,7 +50,7 @@ public ResponseEntity getAllDataAccesCourse( @PostMapping(value = "/create", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_JSON_VALUE}) public ResponseEntity createCourse( - @RequestHeader final Long userId, + @UserId final Long userId, @RequestPart("course") final CourseCreateReq courseCreateReq, @RequestPart("tags") final List tags, @RequestPart("places") final List places, From 4b3dbf99e6bbf1b62cfaef84a37a7c8b4b38b00f Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Thu, 11 Jul 2024 16:12:25 +0900 Subject: [PATCH 26/78] =?UTF-8?q?[refactor]=20=EB=84=A4=EC=9D=B4=EB=B0=8D?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD=20=EB=B0=8F=20=20=EB=B6=84=EB=A6=AC=20-?= =?UTF-8?q?=20#42?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/dateroad/Image/service/ImageService.java | 4 ++-- .../org/dateroad/course/api/CourseController.java | 9 ++++----- .../facade/{CourseFacade.java => AsyncService.java} | 4 ++-- .../org/dateroad/course/service/CourseService.java | 12 +++++++----- 4 files changed, 15 insertions(+), 14 deletions(-) rename dateroad-api/src/main/java/org/dateroad/course/facade/{CourseFacade.java => AsyncService.java} (93%) diff --git a/dateroad-api/src/main/java/org/dateroad/Image/service/ImageService.java b/dateroad-api/src/main/java/org/dateroad/Image/service/ImageService.java index d24965fa..a8f3092b 100644 --- a/dateroad-api/src/main/java/org/dateroad/Image/service/ImageService.java +++ b/dateroad-api/src/main/java/org/dateroad/Image/service/ImageService.java @@ -27,7 +27,7 @@ public class ImageService { @Value("${cloudfront.domain}") private String cachePath; - public String saveImages(final List images, final Course course) { + public List saveImages(final List images, final Course course) { AtomicInteger sequence = new AtomicInteger(); List courseimages = images.stream() .map(img -> { @@ -42,7 +42,7 @@ public String saveImages(final List images, final Course course) } }) .toList(); - return imageRepository.saveAll(courseimages).getFirst().getImageUrl(); + return imageRepository.saveAll(courseimages); } public Image findFirstByCourseOrderBySequenceAsc(Course course) { 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 4343635f..b7459e82 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 @@ -11,7 +11,7 @@ import org.dateroad.course.dto.request.TagCreateReq; import org.dateroad.course.dto.response.CourseGetAllRes; import org.dateroad.course.dto.response.DateAccessGetAllRes; -import org.dateroad.course.facade.CourseFacade; +import org.dateroad.course.facade.AsyncService; import org.dateroad.course.service.CourseService; import org.dateroad.date.domain.Course; import org.springframework.http.MediaType; @@ -19,7 +19,6 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PostMapping; -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; @@ -30,7 +29,7 @@ @RequiredArgsConstructor public class CourseController { private final CourseService courseService; - private final CourseFacade courseFacade; + private final AsyncService asyncService; @GetMapping public ResponseEntity getAllCourse( @@ -57,8 +56,8 @@ public ResponseEntity createCourse( @RequestPart("images") final List images ) { Course course = courseService.createCourse(userId, courseCreateReq, places, images); - courseFacade.createCoursePlace(places, course); - courseFacade.createCourseTags(tags, course); + asyncService.createCoursePlace(places, course); + asyncService.createCourseTags(tags, course); return ResponseEntity.created( URI.create(course.getId().toString())).build(); } diff --git a/dateroad-api/src/main/java/org/dateroad/course/facade/CourseFacade.java b/dateroad-api/src/main/java/org/dateroad/course/facade/AsyncService.java similarity index 93% rename from dateroad-api/src/main/java/org/dateroad/course/facade/CourseFacade.java rename to dateroad-api/src/main/java/org/dateroad/course/facade/AsyncService.java index 9fc3a869..2ee4eaed 100644 --- a/dateroad-api/src/main/java/org/dateroad/course/facade/CourseFacade.java +++ b/dateroad-api/src/main/java/org/dateroad/course/facade/AsyncService.java @@ -18,7 +18,7 @@ @Service @RequiredArgsConstructor(access = AccessLevel.PROTECTED) @Transactional(readOnly = true) -public class CourseFacade { +public class AsyncService { private final CoursePlaceService coursePlaceService; private final CourseTagService courseTagService; private final ImageService imageService; @@ -32,7 +32,7 @@ public float findTotalDurationByCourseId(final Long id) { } @Transactional - public String createImage(final List images, final Course course) { + public List createImage(final List images, final Course course) { return imageService.saveImages(images, course); } 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 02f6c6e9..abd10e66 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 @@ -12,7 +12,7 @@ import org.dateroad.course.dto.response.CourseDtoGetRes; import org.dateroad.course.dto.response.CourseGetAllRes; import org.dateroad.course.dto.response.DateAccessGetAllRes; -import org.dateroad.course.facade.CourseFacade; +import org.dateroad.course.facade.AsyncService; import org.dateroad.date.domain.Course; import org.dateroad.date.repository.CourseRepository; import org.dateroad.dateAccess.repository.DateAccessRepository; @@ -34,7 +34,7 @@ public class CourseService { private final LikeRepository likeRepository; private final DateAccessRepository dateAccessRepository; private final UserRepository userRepository; - private final CourseFacade courseFacade; + private final AsyncService asyncService; public CourseGetAllRes getAllCourses(CourseGetAllReq courseGetAllReq) { Specification spec = CourseSpecifications.filterByCriteria(courseGetAllReq); @@ -53,9 +53,9 @@ private List convertToDtoList(List entities, Function imageList = asyncService.createImage(images, saveCourse); + String thumnailUrl = imageList.getLast().getImageUrl(); + course.setThumbnail(thumnailUrl); return saveCourse; } } From b7c559fc6196c1404d41aeb27b644b5714af3319 Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Thu, 11 Jul 2024 16:23:10 +0900 Subject: [PATCH 27/78] =?UTF-8?q?[refactor]=20CourseId=20=EB=B0=98?= =?UTF-8?q?=ED=99=98=20=EB=A1=9C=EC=A7=81=EC=9C=BC=EB=A1=9C=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20-=20#42?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dateroad/Image/dto/request/ImageReq.java | 22 ------------------- .../dateroad/course/api/CourseController.java | 9 +++++--- .../course/dto/response/CourseCreateRes.java | 15 +++++++++++++ 3 files changed, 21 insertions(+), 25 deletions(-) delete mode 100644 dateroad-api/src/main/java/org/dateroad/Image/dto/request/ImageReq.java create mode 100644 dateroad-api/src/main/java/org/dateroad/course/dto/response/CourseCreateRes.java diff --git a/dateroad-api/src/main/java/org/dateroad/Image/dto/request/ImageReq.java b/dateroad-api/src/main/java/org/dateroad/Image/dto/request/ImageReq.java deleted file mode 100644 index 5832320c..00000000 --- a/dateroad-api/src/main/java/org/dateroad/Image/dto/request/ImageReq.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.dateroad.Image.dto.request; - -import io.swagger.v3.oas.annotations.Parameter; -import io.swagger.v3.oas.annotations.media.Content; -import lombok.AccessLevel; -import lombok.Builder; -import lombok.Setter; -import org.springframework.http.MediaType; -import org.springframework.web.multipart.MultipartFile; - -@Builder(access = AccessLevel.PRIVATE) -public record ImageReq( - MultipartFile image, - int sequence -) { - public static ImageReq of(MultipartFile image, int sequence) { - return ImageReq.builder() - .image(image) - .sequence(sequence) - .build(); - } -} 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 b7459e82..b04144af 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 @@ -9,11 +9,13 @@ import org.dateroad.course.dto.request.CourseCreateReq; import org.dateroad.course.dto.request.CoursePlaceGetReq; import org.dateroad.course.dto.request.TagCreateReq; +import org.dateroad.course.dto.response.CourseCreateRes; import org.dateroad.course.dto.response.CourseGetAllRes; import org.dateroad.course.dto.response.DateAccessGetAllRes; import org.dateroad.course.facade.AsyncService; import org.dateroad.course.service.CourseService; import org.dateroad.date.domain.Course; +import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; @@ -48,7 +50,7 @@ public ResponseEntity getAllDataAccesCourse( } @PostMapping(value = "/create", consumes = {MediaType.MULTIPART_FORM_DATA_VALUE, MediaType.APPLICATION_JSON_VALUE}) - public ResponseEntity createCourse( + public ResponseEntity createCourse( @UserId final Long userId, @RequestPart("course") final CourseCreateReq courseCreateReq, @RequestPart("tags") final List tags, @@ -58,7 +60,8 @@ public ResponseEntity createCourse( Course course = courseService.createCourse(userId, courseCreateReq, places, images); asyncService.createCoursePlace(places, course); asyncService.createCourseTags(tags, course); - return ResponseEntity.created( - URI.create(course.getId().toString())).build(); + return ResponseEntity.status( + HttpStatus.CREATED + ).body(CourseCreateRes.of(course.getId())); } } diff --git a/dateroad-api/src/main/java/org/dateroad/course/dto/response/CourseCreateRes.java b/dateroad-api/src/main/java/org/dateroad/course/dto/response/CourseCreateRes.java new file mode 100644 index 00000000..cb8cf0ac --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/course/dto/response/CourseCreateRes.java @@ -0,0 +1,15 @@ +package org.dateroad.course.dto.response; + +import lombok.AccessLevel; +import lombok.Builder; + +@Builder(access = AccessLevel.PROTECTED) +public record CourseCreateRes( + Long courseId +) { + public static CourseCreateRes of(Long courseId) { + return CourseCreateRes.builder() + .courseId(courseId) + .build(); + } +} From ea7ac69c75bba0560c29fe1fb6f6edf427c5dc5a Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Thu, 11 Jul 2024 16:45:55 +0900 Subject: [PATCH 28/78] =?UTF-8?q?[feat]=20merge=20=EC=B6=A9=EB=8F=8C=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0=20-=20#42?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/dateroad/date/domain/Course.java | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/dateroad-domain/src/main/java/org/dateroad/date/domain/Course.java b/dateroad-domain/src/main/java/org/dateroad/date/domain/Course.java index 1191c69d..baa1e452 100644 --- a/dateroad-domain/src/main/java/org/dateroad/date/domain/Course.java +++ b/dateroad-domain/src/main/java/org/dateroad/date/domain/Course.java @@ -41,7 +41,6 @@ public class Course extends DateBase { @NotNull private int cost; -<<<<<<< HEAD @Column(name = "time") @NotNull private float time; @@ -54,16 +53,6 @@ public static Course create(final User user, final String title, final String de final String country, final String city, final int cost, final LocalDate date, final LocalTime startAt, final float time) { -======= - @Column(name = "thumbnail") - @NotNull - private String thumbnail; - - public static Course create(final String title, final String description, - final String country, final String city, - final int cost, final LocalDate date, - final LocalTime startAt) { ->>>>>>> develop return Course.builder() .user(user) .title(title) From 2eced5a83b3a426a1a74257f9c33b6c182846182 Mon Sep 17 00:00:00 2001 From: Kihoon KIM <40743105+rlarlgnszx@users.noreply.github.com> Date: Thu, 11 Jul 2024 16:59:35 +0900 Subject: [PATCH 29/78] =?UTF-8?q?[fix]=20merge=20=EC=B6=A9=EB=8F=8C=20?= =?UTF-8?q?=ED=95=B4=EA=B2=B0=20-=20#42?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/dateroad/date/domain/Date.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/dateroad-domain/src/main/java/org/dateroad/date/domain/Date.java b/dateroad-domain/src/main/java/org/dateroad/date/domain/Date.java index 2dede850..42360067 100644 --- a/dateroad-domain/src/main/java/org/dateroad/date/domain/Date.java +++ b/dateroad-domain/src/main/java/org/dateroad/date/domain/Date.java @@ -27,15 +27,9 @@ public class Date extends DateBase { @Column(name = "date_id") private Long id; -<<<<<<< HEAD - public static Date create(final String title, final String country, - final String city, LocalDate date, - final LocalTime startAt) { -======= public static Date create(final User user, final String title, final LocalDate date, final LocalTime startAt, final String country, final String city) { ->>>>>>> develop return Date.builder() .user(user) .title(title) From 416b32369068ce9b16b4ea731445706a6d92cca1 Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Thu, 11 Jul 2024 18:37:24 +0900 Subject: [PATCH 30/78] =?UTF-8?q?[fix]=20=EC=82=AD=EC=A0=9C=20=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20rebase=20-=20#63?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/CICD-dev.yml | 10 +- .gitignore | 5 +- .../dto/response/AdvGetAllRes.java | 22 +++- .../dateroad/auth/config/SecurityConfig.java | 1 - .../course/service/CourseSpecifications.java | 33 +++--- .../org/dateroad/date/api/DateController.java | 38 ++++++ .../date/dto/request/DateCreateReq.java | 20 ++++ .../date/dto/request/PlaceCreateReq.java | 8 ++ .../date/dto/request/TagCreateReq.java | 8 ++ .../date/dto/response/DateDetailRes.java | 43 +++++++ .../date/dto/response/PlaceGetRes.java | 21 ++++ .../dateroad/date/dto/response/TagGetRes.java | 17 +++ .../dateroad/date/service/DateRepository.java | 7 ++ .../dateroad/date/service/DateService.java | 108 ++++++++++++++++++ .../org/dateroad/user/api/UserController.java | 19 +++ .../dto/request/AppleWithdrawAuthCodeReq.java | 6 + .../dateroad/user/service/AuthService.java | 72 +++++++++--- .../java/org/dateroad/code/FailureCode.java | 10 +- .../dateroad/common/ObjectMapperConfig.java | 2 +- .../exception/BadRequestException.java | 13 +++ .../exception/ForbiddenException.java | 13 +++ .../date/repository/DatePlaceRepository.java | 12 ++ .../date/repository/DateTagRepository.java | 12 ++ ...ository.java => DataAccessRepository.java} | 2 +- .../org/dateroad/place/domain/DatePlace.java | 2 +- .../repository/CoursePlaceRepository.java | 4 +- .../repository/RefreshTokenRepository.java | 2 +- .../java/org/dateroad/tag/domain/DateTag.java | 6 +- .../java/org/dateroad/user/domain/User.java | 16 +-- .../user/repository/UserRepository.java | 1 - dateroad-external/build.gradle | 4 + .../apple/AppleClientPublicKeyGenerator.java | 2 - .../apple/AppleClientSecretGenerator.java | 57 +++++++++ .../dateroad/feign/apple/AppleFeignApi.java | 15 +++ ...dProvider.java => AppleFeignProvider.java} | 30 ++++- .../apple/AppleIdentityJWTValidator.java | 11 +- .../dateroad/feign/apple/AppleProperties.java | 19 +++ .../dateroad/feign/apple/AppleTokenRes.java | 10 ++ .../dateroad/feign/kakao/KakaoErrorRes.java | 11 -- .../dateroad/feign/kakao/KakaoFeignApi.java | 12 +- .../feign/kakao/KakaoFeignProvider.java | 80 +++++++++++++ .../dateroad/feign/kakao/KakaoHeaderType.java | 14 +++ .../kakao/KakaoPlatformUserIdProvider.java | 60 ---------- .../dateroad/feign/kakao/KakaoProperties.java | 15 +++ .../feign/kakao/KakaoRequestType.java | 6 + .../kakao/dto/response/KaKaoErrorRes.java | 9 ++ .../kakao/dto/response/KaKaoUnlinkRes.java | 6 + .../response}/KakaoAccessTokenInfoRes.java | 2 +- 48 files changed, 752 insertions(+), 144 deletions(-) create mode 100644 dateroad-api/src/main/java/org/dateroad/date/api/DateController.java create mode 100644 dateroad-api/src/main/java/org/dateroad/date/dto/request/DateCreateReq.java create mode 100644 dateroad-api/src/main/java/org/dateroad/date/dto/request/PlaceCreateReq.java create mode 100644 dateroad-api/src/main/java/org/dateroad/date/dto/request/TagCreateReq.java create mode 100644 dateroad-api/src/main/java/org/dateroad/date/dto/response/DateDetailRes.java create mode 100644 dateroad-api/src/main/java/org/dateroad/date/dto/response/PlaceGetRes.java create mode 100644 dateroad-api/src/main/java/org/dateroad/date/dto/response/TagGetRes.java create mode 100644 dateroad-api/src/main/java/org/dateroad/date/service/DateRepository.java create mode 100644 dateroad-api/src/main/java/org/dateroad/date/service/DateService.java create mode 100644 dateroad-api/src/main/java/org/dateroad/user/dto/request/AppleWithdrawAuthCodeReq.java create mode 100644 dateroad-common/src/main/java/org/dateroad/exception/BadRequestException.java create mode 100644 dateroad-common/src/main/java/org/dateroad/exception/ForbiddenException.java create mode 100644 dateroad-domain/src/main/java/org/dateroad/date/repository/DatePlaceRepository.java create mode 100644 dateroad-domain/src/main/java/org/dateroad/date/repository/DateTagRepository.java rename dateroad-domain/src/main/java/org/dateroad/dateAccess/repository/{DateAccessRepository.java => DataAccessRepository.java} (88%) create mode 100644 dateroad-external/src/main/java/org/dateroad/feign/apple/AppleClientSecretGenerator.java rename dateroad-external/src/main/java/org/dateroad/feign/apple/{ApplePlatformUserIdProvider.java => AppleFeignProvider.java} (55%) create mode 100644 dateroad-external/src/main/java/org/dateroad/feign/apple/AppleProperties.java create mode 100644 dateroad-external/src/main/java/org/dateroad/feign/apple/AppleTokenRes.java delete mode 100644 dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoErrorRes.java create mode 100644 dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoFeignProvider.java create mode 100644 dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoHeaderType.java delete mode 100644 dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoPlatformUserIdProvider.java create mode 100644 dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoProperties.java create mode 100644 dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoRequestType.java create mode 100644 dateroad-external/src/main/java/org/dateroad/feign/kakao/dto/response/KaKaoErrorRes.java create mode 100644 dateroad-external/src/main/java/org/dateroad/feign/kakao/dto/response/KaKaoUnlinkRes.java rename dateroad-external/src/main/java/org/dateroad/feign/kakao/{ => dto/response}/KakaoAccessTokenInfoRes.java (78%) diff --git a/.github/workflows/CICD-dev.yml b/.github/workflows/CICD-dev.yml index f98254cd..a27ee0b6 100644 --- a/.github/workflows/CICD-dev.yml +++ b/.github/workflows/CICD-dev.yml @@ -27,7 +27,15 @@ jobs: echo "${{ secrets.CD_APPLICATION }}" > ./application.yml cat ./application.yml working-directory: ${{ env.working-directory }} - + + - name: AuthKey_39CUV6ST46.p8 생성 + run: | + mkdir -p dateroad-external/src/main/resources/static && cd $_ + touch ./AuthKey_39CUV6ST46.p8 + echo "${{ secrets.CD_APPLICATION }}" > ./AuthKey_39CUV6ST46.p8 + cat ./AuthKey_39CUV6ST46.p8 + working-directory: ${{ env.working-directory }} + - name: 빌드 run: | chmod +x gradlew diff --git a/.gitignore b/.gitignore index d157e19f..6b15a3d7 100644 --- a/.gitignore +++ b/.gitignore @@ -43,4 +43,7 @@ out/ ### Yml ### dateroad-api/src/main/resources/application.yml -dateroad-api/src/test/resources/application.yml \ No newline at end of file +dateroad-api/src/test/resources/application.yml + +### File ### +**/static/*.p8 \ No newline at end of file diff --git a/dateroad-api/src/main/java/org/dateroad/advertisment/dto/response/AdvGetAllRes.java b/dateroad-api/src/main/java/org/dateroad/advertisment/dto/response/AdvGetAllRes.java index f6c70650..7565ab40 100644 --- a/dateroad-api/src/main/java/org/dateroad/advertisment/dto/response/AdvGetAllRes.java +++ b/dateroad-api/src/main/java/org/dateroad/advertisment/dto/response/AdvGetAllRes.java @@ -1,23 +1,35 @@ package org.dateroad.advertisment.dto.response; import java.util.List; +import lombok.AccessLevel; +import lombok.Builder; import org.dateroad.advertisement.domain.AdTagType; import org.dateroad.advertisement.domain.Advertisment; +@Builder(access = AccessLevel.PRIVATE) public record AdvGetAllRes( List advertismentDtoResList ) { + public static AdvGetAllRes of(List advertismentDtoResList) { + return AdvGetAllRes.builder() + .advertismentDtoResList(advertismentDtoResList) + .build(); + } + + @Builder(access = AccessLevel.PRIVATE) public record AdvertismentDtoRes( Long advertismentId, String thumbnail, String title, AdTagType tag - ){ + ) { public static AdvertismentDtoRes of(Advertisment advertisment) { - return new AdvertismentDtoRes(advertisment.getId(), advertisment.getTitle(), advertisment.getThumbnail(), advertisment.getTag()); + return AdvertismentDtoRes.builder() + .advertismentId(advertisment.getId()) + .thumbnail(advertisment.getThumbnail()) + .title(advertisment.getTitle()) + .tag(advertisment.getTag()) + .build(); } } - public static AdvGetAllRes of(List advertismentDtoResList) { - return new AdvGetAllRes(advertismentDtoResList); - } } diff --git a/dateroad-api/src/main/java/org/dateroad/auth/config/SecurityConfig.java b/dateroad-api/src/main/java/org/dateroad/auth/config/SecurityConfig.java index a2ade14e..a57fabc7 100644 --- a/dateroad-api/src/main/java/org/dateroad/auth/config/SecurityConfig.java +++ b/dateroad-api/src/main/java/org/dateroad/auth/config/SecurityConfig.java @@ -6,7 +6,6 @@ import org.dateroad.auth.filter.JwtAuthenticationFilter; import org.dateroad.auth.jwt.JwtProvider; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; diff --git a/dateroad-api/src/main/java/org/dateroad/course/service/CourseSpecifications.java b/dateroad-api/src/main/java/org/dateroad/course/service/CourseSpecifications.java index 4d26f6c7..8e3cd2d1 100644 --- a/dateroad-api/src/main/java/org/dateroad/course/service/CourseSpecifications.java +++ b/dateroad-api/src/main/java/org/dateroad/course/service/CourseSpecifications.java @@ -1,33 +1,34 @@ package org.dateroad.course.service; +import jakarta.persistence.criteria.CriteriaBuilder; +import jakarta.persistence.criteria.Path; import jakarta.persistence.criteria.Predicate; +import jakarta.persistence.criteria.Root; import java.util.ArrayList; import java.util.List; +import java.util.Optional; +import java.util.function.BiFunction; import org.dateroad.course.dto.request.CourseGetAllReq; import org.dateroad.date.domain.Course; import org.springframework.data.jpa.domain.Specification; public class CourseSpecifications { public static Specification filterByCriteria(CourseGetAllReq courseGetAllReq) { - String city = courseGetAllReq.city(); - String country = courseGetAllReq.country(); - Integer cost = courseGetAllReq.cost(); return (root, query, criteriaBuilder) -> { List predicates = new ArrayList<>(); - - if (city != null && !city.isEmpty()) { - predicates.add(criteriaBuilder.equal(root.get("city"), city)); - } - - if (country != null && !country.isEmpty()) { - predicates.add(criteriaBuilder.equal(root.get("country"), country)); - } - - if (cost != null) { - predicates.add(criteriaBuilder.lessThanOrEqualTo(root.get("cost"), cost)); - } - + addPredicate(predicates, criteriaBuilder, root, "city", courseGetAllReq.city(), criteriaBuilder::equal); + addPredicate(predicates, criteriaBuilder, root, "country", courseGetAllReq.country(), criteriaBuilder::equal); + addPredicate(predicates, criteriaBuilder, root, "cost", courseGetAllReq.cost(), criteriaBuilder::lessThanOrEqualTo); return criteriaBuilder.and(predicates.toArray(new Predicate[0])); }; } + + private static void addPredicate(List predicates, CriteriaBuilder criteriaBuilder, Root root, + String attributeName, T value, + BiFunction, T, Predicate> predicateFunction) { + Optional.ofNullable(value) + .ifPresent(val -> predicates.add( + predicateFunction.apply(root.get(attributeName), val)) + ); + } } 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 new file mode 100644 index 00000000..4374aff9 --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/date/api/DateController.java @@ -0,0 +1,38 @@ +package org.dateroad.date.api; + +import lombok.RequiredArgsConstructor; +import org.dateroad.auth.argumentresolve.UserId; +import org.dateroad.date.dto.request.DateCreateReq; +import org.dateroad.date.dto.response.DateDetailRes; +import org.dateroad.date.service.DateService; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RequiredArgsConstructor +@RequestMapping("/api/v1/dates") +@RestController +public class DateController { + private final DateService dateService; + + @PostMapping + public ResponseEntity createDate(@UserId final Long userId, + @RequestBody final DateCreateReq dateCreateReq) { + dateService.createDate(userId, dateCreateReq); + return ResponseEntity.status(HttpStatus.CREATED).build(); + } + + @GetMapping("/{dateId}") + public ResponseEntity getDateDetail(@RequestHeader final Long userId, + @PathVariable final Long dateId) { + DateDetailRes dateDetailRes = dateService.getDateDetail(userId, dateId); + return ResponseEntity.ok(dateDetailRes); + } + + @DeleteMapping("/{dateId}") + public ResponseEntity deleteDate(@UserId final Long userId, + @PathVariable final Long dateId) { + dateService.deleteDate(userId, dateId); + return ResponseEntity.ok().build(); + } +} diff --git a/dateroad-api/src/main/java/org/dateroad/date/dto/request/DateCreateReq.java b/dateroad-api/src/main/java/org/dateroad/date/dto/request/DateCreateReq.java new file mode 100644 index 00000000..57832b3f --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/date/dto/request/DateCreateReq.java @@ -0,0 +1,20 @@ +package org.dateroad.date.dto.request; + +import com.fasterxml.jackson.annotation.JsonFormat; + +import java.time.LocalDate; +import java.time.LocalTime; +import java.util.List; + +public record DateCreateReq( + String title, + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy.MM.dd", timezone = "Asia/Seoul") + LocalDate date, + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm", timezone = "Asia/Seoul") + LocalTime startAt, + List tags, + String country, + String city, + List places +) { +} diff --git a/dateroad-api/src/main/java/org/dateroad/date/dto/request/PlaceCreateReq.java b/dateroad-api/src/main/java/org/dateroad/date/dto/request/PlaceCreateReq.java new file mode 100644 index 00000000..a44533e6 --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/date/dto/request/PlaceCreateReq.java @@ -0,0 +1,8 @@ +package org.dateroad.date.dto.request; + +public record PlaceCreateReq( + String name, + float duration, + int sequence +) { +} diff --git a/dateroad-api/src/main/java/org/dateroad/date/dto/request/TagCreateReq.java b/dateroad-api/src/main/java/org/dateroad/date/dto/request/TagCreateReq.java new file mode 100644 index 00000000..d20b7ae3 --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/date/dto/request/TagCreateReq.java @@ -0,0 +1,8 @@ +package org.dateroad.date.dto.request; + +import org.dateroad.tag.domain.DateTagType; + +public record TagCreateReq( + DateTagType tag +) { +} 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 new file mode 100644 index 00000000..bea522ee --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/date/dto/response/DateDetailRes.java @@ -0,0 +1,43 @@ +package org.dateroad.date.dto.response; + +import lombok.AccessLevel; +import lombok.Builder; +import org.dateroad.date.domain.Date; +import org.dateroad.place.domain.DatePlace; +import org.dateroad.tag.domain.DateTag; + +import java.time.LocalDate; +import java.time.LocalTime; +import java.util.List; + +@Builder(access = AccessLevel.PRIVATE) +public record DateDetailRes( + Long dateId, + String title, + LocalTime startAt, + String city, + List tags, + LocalDate date, + List places +) { + + public static DateDetailRes of(Date date, List tags, List places) { + + List tagGetRes = tags.stream() + .map(TagGetRes::of) + .toList(); + + List placeGetRes = places.stream() + .map(PlaceGetRes::of) + .toList(); + + return DateDetailRes.builder() + .dateId(date.getId()) + .title(date.getTitle()) + .startAt(date.getStartAt()) + .tags(tagGetRes) + .date(date.getDate()) + .places(placeGetRes) + .build(); + } +} diff --git a/dateroad-api/src/main/java/org/dateroad/date/dto/response/PlaceGetRes.java b/dateroad-api/src/main/java/org/dateroad/date/dto/response/PlaceGetRes.java new file mode 100644 index 00000000..78051056 --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/date/dto/response/PlaceGetRes.java @@ -0,0 +1,21 @@ +package org.dateroad.date.dto.response; + +import lombok.AccessLevel; +import lombok.Builder; +import org.dateroad.place.domain.DatePlace; + +@Builder(access = AccessLevel.PRIVATE) + +public record PlaceGetRes( + String name, + float duration, + int sequence +) { + public static PlaceGetRes of(DatePlace datePlace) { + return PlaceGetRes.builder() + .name(datePlace.getName()) + .duration(datePlace.getDuration()) + .sequence(datePlace.getSequence()) + .build(); + } +} diff --git a/dateroad-api/src/main/java/org/dateroad/date/dto/response/TagGetRes.java b/dateroad-api/src/main/java/org/dateroad/date/dto/response/TagGetRes.java new file mode 100644 index 00000000..6bb1b9da --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/date/dto/response/TagGetRes.java @@ -0,0 +1,17 @@ +package org.dateroad.date.dto.response; + +import lombok.AccessLevel; +import lombok.Builder; +import org.dateroad.tag.domain.DateTag; +import org.dateroad.tag.domain.DateTagType; + +@Builder(access = AccessLevel.PRIVATE) +public record TagGetRes( + DateTagType tag +) { + public static TagGetRes of(DateTag dateTag) { + return TagGetRes.builder() + .tag(dateTag.getDateTagType()) + .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 new file mode 100644 index 00000000..e723c8b3 --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/date/service/DateRepository.java @@ -0,0 +1,7 @@ +package org.dateroad.date.service; + +import org.dateroad.date.domain.Date; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface DateRepository extends JpaRepository { +} 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 new file mode 100644 index 00000000..b78a6c53 --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/date/service/DateService.java @@ -0,0 +1,108 @@ +package org.dateroad.date.service; + +import lombok.RequiredArgsConstructor; +import org.dateroad.code.FailureCode; +import org.dateroad.date.domain.Date; +import org.dateroad.date.dto.request.DateCreateReq; +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.repository.DatePlaceRepository; +import org.dateroad.date.repository.DateTagRepository; +import org.dateroad.exception.EntityNotFoundException; +import org.dateroad.exception.ForbiddenException; +import org.dateroad.place.domain.DatePlace; +import org.dateroad.tag.domain.DateTag; +import org.dateroad.user.domain.User; +import org.dateroad.user.repository.UserRepository; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@RequiredArgsConstructor +@Transactional(readOnly = true) +@Service +public class DateService { + private final DateRepository dateRepository; + private final UserRepository userRepository; + private final DateTagRepository dateTagRepository; + private final DatePlaceRepository datePlaceRepository; + + @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()); + } + + public DateDetailRes getDateDetail(final Long userId, final Long dateId) { + User findUser = getUser(userId); + Date findDate = getDate(dateId); + validateDate(findUser, findDate); + List findDateTags = getDateTag(findDate); + List findDatePlaces = getDatePlace(findDate); + return DateDetailRes.of(findDate, findDateTags, findDatePlaces); + } + + @Transactional + public void deleteDate(final Long userId, final Long dateId) { + User findUser = getUser(userId); + Date findDate = getDate(dateId); + validateDate(findUser, findDate); + datePlaceRepository.deleteByDateId(dateId); + dateTagRepository.deleteByDateId(dateId); + dateRepository.deleteById(dateId); + } + + private User getUser(Long userId) { + return userRepository.findById(userId) + .orElseThrow(() -> new EntityNotFoundException(FailureCode.USER_NOT_FOUND)); + } + + private Date createDate(User findUser, 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) { + List dateTags = tags.stream() + .map(t -> DateTag.create(date, t.tag())).toList(); + dateTagRepository.saveAll(dateTags); + } + + private void createDatePlace(Date date, 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) { + return dateRepository.findById(dateId) + .orElseThrow(() -> new EntityNotFoundException(FailureCode.DATE_NOT_FOUND)); + } + + private void validateDate(User findUser, Date findDate) { + if (!findUser.equals(findDate.getUser())) { + throw new ForbiddenException(FailureCode.DATE_DELETE_ACCESS_DENIED); + } + } + + private List getDateTag(Date date) { + List dateTags = dateTagRepository.findByDate(date); + if (dateTags == null | dateTags.isEmpty()) { + throw new EntityNotFoundException(FailureCode.DATE_TAG_NOT_FOUND); + } + return dateTags; + } + + private List getDatePlace(Date date) { + List datePlaces = datePlaceRepository.findByDate(date); + if (datePlaces == null | datePlaces.isEmpty()) { + throw new EntityNotFoundException(FailureCode.DATE_PLACE_NOT_FOUND); + } + return datePlaces; + } +} 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 26ac423a..d78723e5 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 @@ -1,6 +1,8 @@ package org.dateroad.user.api; import lombok.RequiredArgsConstructor; +import org.dateroad.auth.argumentresolve.UserId; +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; @@ -35,6 +37,14 @@ public ResponseEntity signIn(@RequestHeader(AUTHORIZATION) final .ok(userSignInRes); } + @DeleteMapping("/signout") + public ResponseEntity signout(@UserId final Long userId) { + authService.signout(userId); + return ResponseEntity + .ok() + .build(); + } + @GetMapping("/check") public ResponseEntity checkNickname(@RequestParam("name") final String nickname) { authService.checkNickname(nickname); @@ -42,4 +52,13 @@ public ResponseEntity checkNickname(@RequestParam("name") final String nic .ok() .build(); } + + @DeleteMapping("/withdraw") + public ResponseEntity withdraw(@UserId final Long userId, + @RequestBody final AppleWithdrawAuthCodeReq appleWithdrawAuthCodeReq) { + authService.withdraw(userId, appleWithdrawAuthCodeReq); + return ResponseEntity + .ok() + .build(); + } } diff --git a/dateroad-api/src/main/java/org/dateroad/user/dto/request/AppleWithdrawAuthCodeReq.java b/dateroad-api/src/main/java/org/dateroad/user/dto/request/AppleWithdrawAuthCodeReq.java new file mode 100644 index 00000000..9732fcc2 --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/user/dto/request/AppleWithdrawAuthCodeReq.java @@ -0,0 +1,6 @@ +package org.dateroad.user.dto.request; + +public record AppleWithdrawAuthCodeReq( + String authCode +) { +} 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 11a1546d..57364959 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 @@ -4,17 +4,17 @@ import org.dateroad.auth.jwt.JwtProvider; import org.dateroad.auth.jwt.Token; import org.dateroad.code.FailureCode; -import org.dateroad.exception.ConflictException; -import org.dateroad.exception.EntityNotFoundException; -import org.dateroad.exception.InvalidValueException; -import org.dateroad.feign.apple.ApplePlatformUserIdProvider; -import org.dateroad.feign.kakao.KakaoPlatformUserIdProvider; +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.refreshtoken.repository.RefreshTokenRepository; import org.dateroad.tag.domain.DateTagType; import org.dateroad.tag.domain.UserTag; import org.dateroad.tag.repository.UserTagRepository; import org.dateroad.user.domain.Platform; import org.dateroad.user.domain.User; +import org.dateroad.user.dto.request.AppleWithdrawAuthCodeReq; import org.dateroad.user.dto.request.UserSignInReq; import org.dateroad.user.repository.UserRepository; import org.dateroad.user.dto.request.UserSignUpReq; @@ -26,14 +26,16 @@ import java.util.List; @RequiredArgsConstructor +@Transactional(readOnly = true) @Service public class AuthService { private final UserRepository userRepository; - private final KakaoPlatformUserIdProvider kakaoPlatformUserIdProvider; - private final ApplePlatformUserIdProvider applePlatformUserIdProvider; + private final KakaoFeignProvider kakaoFeignProvider; + private final AppleFeignProvider appleFeignProvider; private final UserTagRepository userTagRepository; private final JwtProvider jwtProvider; private final RefreshTokenRepository refreshTokenRepository; + private final KakaoFeignApi kakaoFeignApi; @Transactional public UsersignUpRes signUp(final String token, final UserSignUpReq userSignUpReq) { @@ -51,27 +53,53 @@ public UsersignUpRes signUp(final String token, final UserSignUpReq userSignUpRe @Transactional public UserSignInRes signIn(final String token, final UserSignInReq userSignInReq) { String platformUserId = getUserPlatformId(userSignInReq.platform(), token); - User foundUser = getUser(userSignInReq.platform(), platformUserId); + User foundUser = getUserByPlatformAndPlatformUserId(userSignInReq.platform(), platformUserId); Token issuedToken = jwtProvider.issueToken(foundUser.getId()); return UserSignInRes.of(foundUser.getId(), issuedToken.accessToken(), issuedToken.refreshToken()); } + @Transactional + public void withdraw(final Long userId, final AppleWithdrawAuthCodeReq AppleWithdrawAuthCodeReq) { + + //todo: #45브랜치 머지후, 메서드 이용 + User foundUser = userRepository.findById(userId).orElseThrow(EntityNotFoundException::new); + + if (foundUser.getPlatForm() == Platform.KAKAO) { //카카오 유저면 카카오와 연결 끊기 + kakaoFeignProvider.unLinkWithKakao(foundUser.getPlatformUserId()); + } else if (foundUser.getPlatForm() == Platform.APPLE) { //애플 유저면 애플이랑 연결 끊기 + appleFeignProvider.revokeUser(AppleWithdrawAuthCodeReq.authCode()); + } else { + throw new BadRequestException(FailureCode.INVALID_PLATFORM_TYPE); + } + + //todo: #45브랜치 머지후, 메서드 이용 + refreshTokenRepository.deleteByUserId(foundUser.getId()); + userRepository.deleteById(foundUser.getId()); + } + //닉네임 중복체크 public void checkNickname(final String nickname) { if (!userRepository.existsByName(nickname)) { return; } else { throw new ConflictException(FailureCode.DUPLICATE_NICKNAME); } + } + + @Transactional + public void signout(final long userId) { + User foundUser = getUserByUserId(userId); + deleteRefreshToken(foundUser.getId()); } + //플랫폼 유저 아이디 가져오기 (카카오 or 애플) private String getUserPlatformId(final Platform platform, final String token) { if (platform == Platform.APPLE) { - return applePlatformUserIdProvider.getApplePlatformUserId(token); + return appleFeignProvider.getApplePlatformUserId(token); } else if (platform == Platform.KAKAO) { - return kakaoPlatformUserIdProvider.getKakaoPlatformUserId(token); + return kakaoFeignProvider.getKakaoPlatformUserId(token); } else { - throw new InvalidValueException(FailureCode.INVALID_PLATFORM_TYPE); + throw new BadRequestException(FailureCode.INVALID_PLATFORM_TYPE); } } @@ -96,15 +124,29 @@ private void saveUserTag(final User savedUser, final List userTags) .toList(); } - //유저 가져오기(검색) - private User getUser(final Platform platform, final String platformUserId) { + //유저 가져오기(platform이랑 platformUserId 사용) + private User getUserByPlatformAndPlatformUserId(final Platform platform, final String platformUserId) { return userRepository.findUserByPlatFormAndPlatformUserId(platform, platformUserId) - .orElseThrow(() -> new EntityNotFoundException(FailureCode.USER_NOT_FOUND)); + .orElseThrow(() -> new EntityNotFoundException(FailureCode.USER_NOT_FOUND) + ); + } + + //유저 가져오기(userId 사용) + private User getUserByUserId(final long userId) { + return userRepository.findById(userId).orElseThrow( + () -> new EntityNotFoundException(FailureCode.USER_NOT_FOUND) + ); } + //태그 리스트 사이즈 검증 private void validateUserTagSize(final List userTags) { if (userTags.isEmpty() || userTags.size() > 3) { - throw new InvalidValueException((FailureCode.WRONG_USER_TAG_SIZE)); + throw new BadRequestException((FailureCode.WRONG_USER_TAG_SIZE)); } } + + //refreshToken 삭제 + private void deleteRefreshToken(final long userId) { + refreshTokenRepository.deleteByUserId(userId); + } } 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 683dcdf2..ee6f5c1a 100644 --- a/dateroad-common/src/main/java/org/dateroad/code/FailureCode.java +++ b/dateroad-common/src/main/java/org/dateroad/code/FailureCode.java @@ -3,7 +3,6 @@ import lombok.AccessLevel; import lombok.Getter; import lombok.RequiredArgsConstructor; -import org.springframework.boot.actuate.autoconfigure.observation.ObservationProperties; import org.springframework.http.HttpStatus; @Getter @@ -36,19 +35,26 @@ public enum FailureCode { INVALID_REFRESH_TOKEN_VALUE(HttpStatus.UNAUTHORIZED, "e4024", "잘못된 리프레시토큰입니다."), EXPIRED_REFRESH_TOKEN(HttpStatus.UNAUTHORIZED, "e4025", "리프레시 토큰 기간이 만료되었습니다. 재로그인 해주세요"), + INVALID_KAKAO_ACCESS(HttpStatus.UNAUTHORIZED, "e4026", "잘못된 카카오 통신 접근입니다."), + UN_LINK_WITH_KAKAO_UNAUTHORIZED(HttpStatus.UNAUTHORIZED, "e4027", "카카오 연결 끊기 통신에 실패했습니다"), + INVALID_APPLE_TOKEN_ACCESS(HttpStatus.UNAUTHORIZED, "e4028", "잘못된 애플 토큰 통신 접근입니다."), /** * 403 Forbidden */ FORBIDDEN(HttpStatus.FORBIDDEN, "e4030", "리소스 접근 권한이 없습니다."), + DATE_DELETE_ACCESS_DENIED(HttpStatus.FORBIDDEN, "e4032", "해당 일정에 권한이 없습니다."), /** * 404 Not Found */ ENTITY_NOT_FOUND(HttpStatus.NOT_FOUND, "e4040", "대상을 찾을 수 없습니다."), TOKEN_TYPE_NOT_FOUND(HttpStatus.NOT_FOUND, "e4041", "찾을 수 없는 토큰 타입입니다."), + USER_NOT_FOUND(HttpStatus.NOT_FOUND, "e4042", "유저를 찾을 수 없습니다."), COURSE_THUMBNAIL_NOT_FOUND(HttpStatus.NOT_FOUND, "e4043", "코스 썸네일을 찾을수 없습니다."), - USER_NOT_FOUND(HttpStatus.NOT_FOUND, "e4042", "존재하지 않는 회원입니다."), + DATE_NOT_FOUND(HttpStatus.NOT_FOUND, "e4044", "데이트를 찾을 수 없습니다."), + DATE_TAG_NOT_FOUND(HttpStatus.NOT_FOUND, "e4045", "데이트 태그를 찾을 수 없습니다."), + DATE_PLACE_NOT_FOUND(HttpStatus.NOT_FOUND, "e4046", "데이트 장소를 찾을 수 없습니다."), /** * 405 Method Not Allowed diff --git a/dateroad-common/src/main/java/org/dateroad/common/ObjectMapperConfig.java b/dateroad-common/src/main/java/org/dateroad/common/ObjectMapperConfig.java index d01d1ef9..e6e59f9e 100644 --- a/dateroad-common/src/main/java/org/dateroad/common/ObjectMapperConfig.java +++ b/dateroad-common/src/main/java/org/dateroad/common/ObjectMapperConfig.java @@ -17,4 +17,4 @@ public ObjectMapper objectMapper() { return mapper; } -} +} \ No newline at end of file diff --git a/dateroad-common/src/main/java/org/dateroad/exception/BadRequestException.java b/dateroad-common/src/main/java/org/dateroad/exception/BadRequestException.java new file mode 100644 index 00000000..9be3090d --- /dev/null +++ b/dateroad-common/src/main/java/org/dateroad/exception/BadRequestException.java @@ -0,0 +1,13 @@ +package org.dateroad.exception; + +import org.dateroad.code.FailureCode; + +public class BadRequestException extends DateRoadException { + public BadRequestException() { + super(FailureCode.BAD_REQUEST); + } + + public BadRequestException(FailureCode failureCode) { + super(failureCode); + } +} diff --git a/dateroad-common/src/main/java/org/dateroad/exception/ForbiddenException.java b/dateroad-common/src/main/java/org/dateroad/exception/ForbiddenException.java new file mode 100644 index 00000000..f9fa3a58 --- /dev/null +++ b/dateroad-common/src/main/java/org/dateroad/exception/ForbiddenException.java @@ -0,0 +1,13 @@ +package org.dateroad.exception; + +import org.dateroad.code.FailureCode; + +public class ForbiddenException extends DateRoadException { + public ForbiddenException() { + super(FailureCode.FORBIDDEN); + } + + public ForbiddenException(FailureCode failureCode) { + super(failureCode); + } +} diff --git a/dateroad-domain/src/main/java/org/dateroad/date/repository/DatePlaceRepository.java b/dateroad-domain/src/main/java/org/dateroad/date/repository/DatePlaceRepository.java new file mode 100644 index 00000000..2af22e97 --- /dev/null +++ b/dateroad-domain/src/main/java/org/dateroad/date/repository/DatePlaceRepository.java @@ -0,0 +1,12 @@ +package org.dateroad.date.repository; + +import org.dateroad.date.domain.Date; +import org.dateroad.place.domain.DatePlace; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +public interface DatePlaceRepository extends JpaRepository { + void deleteByDateId(Long dateId); + List findByDate(Date date); +} diff --git a/dateroad-domain/src/main/java/org/dateroad/date/repository/DateTagRepository.java b/dateroad-domain/src/main/java/org/dateroad/date/repository/DateTagRepository.java new file mode 100644 index 00000000..d94e1669 --- /dev/null +++ b/dateroad-domain/src/main/java/org/dateroad/date/repository/DateTagRepository.java @@ -0,0 +1,12 @@ +package org.dateroad.date.repository; + +import org.dateroad.date.domain.Date; +import org.dateroad.tag.domain.DateTag; +import org.springframework.data.jpa.repository.JpaRepository; + +import java.util.List; + +public interface DateTagRepository extends JpaRepository { + void deleteByDateId(Long dateId); + List findByDate(Date date); +} diff --git a/dateroad-domain/src/main/java/org/dateroad/dateAccess/repository/DateAccessRepository.java b/dateroad-domain/src/main/java/org/dateroad/dateAccess/repository/DataAccessRepository.java similarity index 88% rename from dateroad-domain/src/main/java/org/dateroad/dateAccess/repository/DateAccessRepository.java rename to dateroad-domain/src/main/java/org/dateroad/dateAccess/repository/DataAccessRepository.java index caacedbd..2edf845e 100644 --- a/dateroad-domain/src/main/java/org/dateroad/dateAccess/repository/DateAccessRepository.java +++ b/dateroad-domain/src/main/java/org/dateroad/dateAccess/repository/DataAccessRepository.java @@ -7,7 +7,7 @@ import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -public interface DateAccessRepository extends JpaRepository { +public interface DataAccessRepository extends JpaRepository { @Query("SELECT da.course FROM DateAccess da WHERE da.user.id = :userId") List findCoursesByUserId(@Param("userId") Long userId); } diff --git a/dateroad-domain/src/main/java/org/dateroad/place/domain/DatePlace.java b/dateroad-domain/src/main/java/org/dateroad/place/domain/DatePlace.java index edff585c..787f1bf2 100644 --- a/dateroad-domain/src/main/java/org/dateroad/place/domain/DatePlace.java +++ b/dateroad-domain/src/main/java/org/dateroad/place/domain/DatePlace.java @@ -23,7 +23,7 @@ public class DatePlace extends Place { @NotNull private Date date; - public static DatePlace create(final String name, float duration, final Date date, final int sequence) { + public static DatePlace create(final Date date, final String name, final float duration, final int sequence) { return DatePlace.builder() .name(name) .duration(duration) diff --git a/dateroad-domain/src/main/java/org/dateroad/place/repository/CoursePlaceRepository.java b/dateroad-domain/src/main/java/org/dateroad/place/repository/CoursePlaceRepository.java index 63816eb4..7037d6c2 100644 --- a/dateroad-domain/src/main/java/org/dateroad/place/repository/CoursePlaceRepository.java +++ b/dateroad-domain/src/main/java/org/dateroad/place/repository/CoursePlaceRepository.java @@ -1,6 +1,7 @@ package org.dateroad.place.repository; import java.util.List; +import org.dateroad.date.domain.Course; import org.dateroad.place.domain.CoursePlace; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; @@ -10,6 +11,5 @@ @Repository public interface CoursePlaceRepository extends JpaRepository { @Query("SELECT SUM(p.duration) FROM CoursePlace p WHERE p.course.id = :courseId") - Float findTotalDurationByCourseId(@Param("courseId") Long courseId); - + Integer findTotalDurationByCourseId(@Param("courseId") Long courseId); } 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 a8e5b970..be8a9c17 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 @@ -6,7 +6,7 @@ import org.springframework.stereotype.Repository; public interface RefreshTokenRepository extends JpaRepository { - public RefreshToken findUserIdByToken(@NotNull byte[] token); + RefreshToken findUserIdByToken(@NotNull byte[] token); void deleteByUserId(final Long userId); } diff --git a/dateroad-domain/src/main/java/org/dateroad/tag/domain/DateTag.java b/dateroad-domain/src/main/java/org/dateroad/tag/domain/DateTag.java index e17cd0cc..a789dedf 100644 --- a/dateroad-domain/src/main/java/org/dateroad/tag/domain/DateTag.java +++ b/dateroad-domain/src/main/java/org/dateroad/tag/domain/DateTag.java @@ -13,14 +13,12 @@ import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; import jakarta.validation.constraints.NotNull; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.NoArgsConstructor; +import lombok.*; import org.dateroad.common.BaseTimeEntity; import org.dateroad.date.domain.Date; @Entity +@Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor(access = AccessLevel.PRIVATE) @Builder(access = AccessLevel.PRIVATE) diff --git a/dateroad-domain/src/main/java/org/dateroad/user/domain/User.java b/dateroad-domain/src/main/java/org/dateroad/user/domain/User.java index e7c0b7e8..2a089682 100644 --- a/dateroad-domain/src/main/java/org/dateroad/user/domain/User.java +++ b/dateroad-domain/src/main/java/org/dateroad/user/domain/User.java @@ -1,13 +1,6 @@ package org.dateroad.user.domain; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.EnumType; -import jakarta.persistence.Enumerated; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.Table; +import jakarta.persistence.*; import jakarta.validation.constraints.NotNull; import lombok.AccessLevel; import lombok.AllArgsConstructor; @@ -15,6 +8,10 @@ import lombok.Getter; import lombok.NoArgsConstructor; import org.dateroad.common.BaseTimeEntity; +import org.dateroad.tag.domain.UserTag; + +import java.util.HashSet; +import java.util.Set; @NoArgsConstructor(access = AccessLevel.PROTECTED) @@ -55,6 +52,9 @@ public class User extends BaseTimeEntity { @NotNull private int totalPoint = 0; + @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) + private Set userTags; + public static User create(final String name, final String platformUserId, final Platform platForm, final String imageUrl) { return User.builder() .name(name) diff --git a/dateroad-domain/src/main/java/org/dateroad/user/repository/UserRepository.java b/dateroad-domain/src/main/java/org/dateroad/user/repository/UserRepository.java index 782cc0eb..03875f20 100644 --- a/dateroad-domain/src/main/java/org/dateroad/user/repository/UserRepository.java +++ b/dateroad-domain/src/main/java/org/dateroad/user/repository/UserRepository.java @@ -1,6 +1,5 @@ package org.dateroad.user.repository; -import java.util.List; import org.dateroad.user.domain.Platform; import org.dateroad.user.domain.User; import org.springframework.data.jpa.repository.JpaRepository; diff --git a/dateroad-external/build.gradle b/dateroad-external/build.gradle index ddbb2545..c440be1b 100644 --- a/dateroad-external/build.gradle +++ b/dateroad-external/build.gradle @@ -14,6 +14,10 @@ dependencies { implementation("software.amazon.awssdk:bom:2.21.0") implementation("software.amazon.awssdk:s3:2.21.0") + // apple secretKey + implementation 'org.bouncycastle:bcprov-jdk18on:1.75' + implementation 'org.bouncycastle:bcpkix-jdk18on:1.75' + implementation 'org.springframework.boot:spring-boot-starter-web' } diff --git a/dateroad-external/src/main/java/org/dateroad/feign/apple/AppleClientPublicKeyGenerator.java b/dateroad-external/src/main/java/org/dateroad/feign/apple/AppleClientPublicKeyGenerator.java index 97cb5565..f5ef8cf2 100644 --- a/dateroad-external/src/main/java/org/dateroad/feign/apple/AppleClientPublicKeyGenerator.java +++ b/dateroad-external/src/main/java/org/dateroad/feign/apple/AppleClientPublicKeyGenerator.java @@ -22,7 +22,6 @@ public PublicKey generateClientPublicKeyWithApplePublicKeys(final Map jwtHeader = new HashMap<>(); + jwtHeader.put("kid", appleProperties.getKid()); // kid + jwtHeader.put("alg", appleProperties.getAlg()); // alg + return Jwts.builder() + .setHeaderParams(jwtHeader) + .setIssuer(appleProperties.getIss()) // issuer + .setIssuedAt(new Date(System.currentTimeMillis())) // 발행 시간 + .setExpiration(expirationDate) // 만료 시간 + .setAudience(appleProperties.getAud()) // aud + .setSubject(appleProperties.getClientId()) // sub + .signWith(SignatureAlgorithm.ES256, getPrivateKey()) + .compact(); + } + + public PrivateKey getPrivateKey() throws IOException { + ClassPathResource resource = new ClassPathResource("static/AuthKey_39CUV6ST46.p8"); // .p8 key파일 위치 + String privateKey = new String(Files.readAllBytes(Paths.get(resource.getURI()))); + + Reader pemReader = new StringReader(privateKey); + PEMParser pemParser = new PEMParser(pemReader); + JcaPEMKeyConverter converter = new JcaPEMKeyConverter(); + PrivateKeyInfo object = (PrivateKeyInfo) pemParser.readObject(); + return converter.getPrivateKey(object); + } +} diff --git a/dateroad-external/src/main/java/org/dateroad/feign/apple/AppleFeignApi.java b/dateroad-external/src/main/java/org/dateroad/feign/apple/AppleFeignApi.java index ec279c9e..374ab369 100644 --- a/dateroad-external/src/main/java/org/dateroad/feign/apple/AppleFeignApi.java +++ b/dateroad-external/src/main/java/org/dateroad/feign/apple/AppleFeignApi.java @@ -1,11 +1,26 @@ package org.dateroad.feign.apple; +import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestParam; @FeignClient(name = "${feign.apple.name}", url = "${feign.apple.url}") public interface AppleFeignApi { @GetMapping("/keys") ApplePublicKeys getApplePublicKeys(); + + @PostMapping(value = "/token", consumes = "application/x-www-form-urlencoded") + AppleTokenRes getAppleToken(@RequestParam("client_secret") String clientSecret, + @RequestParam("code") String authCode, + @RequestParam("grant_type") String grantType, + @RequestParam("client_id") String clientId); + + @PostMapping(value = "/revoke", consumes = "application/x-www-form-urlencoded") + void revokeUser(@RequestParam("client_id") String clientId, + @RequestParam("client_secret") String clientSecret, + @RequestParam("token") String accessToken, + @RequestParam("token_type_hint") String tokenTypeHint); } diff --git a/dateroad-external/src/main/java/org/dateroad/feign/apple/ApplePlatformUserIdProvider.java b/dateroad-external/src/main/java/org/dateroad/feign/apple/AppleFeignProvider.java similarity index 55% rename from dateroad-external/src/main/java/org/dateroad/feign/apple/ApplePlatformUserIdProvider.java rename to dateroad-external/src/main/java/org/dateroad/feign/apple/AppleFeignProvider.java index 872b13c8..3e772f2e 100644 --- a/dateroad-external/src/main/java/org/dateroad/feign/apple/ApplePlatformUserIdProvider.java +++ b/dateroad-external/src/main/java/org/dateroad/feign/apple/AppleFeignProvider.java @@ -2,20 +2,25 @@ import io.jsonwebtoken.Claims; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.dateroad.code.FailureCode; import org.dateroad.exception.UnauthorizedException; import org.springframework.stereotype.Component; +import java.io.IOException; import java.security.PublicKey; import java.util.Map; @RequiredArgsConstructor @Component -public class ApplePlatformUserIdProvider { +@Slf4j +public class AppleFeignProvider { private final AppleIdentityJWTParser appleIdentityJWTParser; private final AppleFeignApi appleFeignApi; private final AppleClientPublicKeyGenerator appleClientPublicKeyGenerator; private final AppleIdentityJWTValidator appleIdentityJWTValidator; + private final AppleClientSecretGenerator appleClientSecretGenerator; + private final AppleProperties appleProperties; public String getApplePlatformUserId(final String identityToken) { Map tokenHeaders = appleIdentityJWTParser.parseHeader(identityToken); @@ -26,9 +31,32 @@ public String getApplePlatformUserId(final String identityToken) { return claims.getSubject(); } + public void revokeUser(final String authCode) { + try { + String secretKey = appleClientSecretGenerator.createClientSecret(); + String appleAccessToken = getAppleAccess(secretKey, authCode); + appleFeignApi.revokeUser(secretKey, appleAccessToken, appleProperties.getClientId(), "access_token"); + } catch (IOException e) { + System.out.println(e); + throw new UnauthorizedException(FailureCode.INVALID_APPLE_TOKEN_ACCESS); + } + } + + private String getAppleAccess(final String secretKey, final String authCode) { + AppleTokenRes appleTokenRes = appleFeignApi + .getAppleToken( + secretKey, + authCode, + appleProperties.getType(), + appleProperties.getClientId() + ); + return appleTokenRes.access_token(); + } + private void validateClaims(final Claims claims) { if (!appleIdentityJWTValidator.isValidAppleIdentityToken(claims)) { throw new UnauthorizedException(FailureCode.INVALID_APPLE_IDENTITY_TOKEN_CLAIMS); } } + } diff --git a/dateroad-external/src/main/java/org/dateroad/feign/apple/AppleIdentityJWTValidator.java b/dateroad-external/src/main/java/org/dateroad/feign/apple/AppleIdentityJWTValidator.java index 756c07d9..d719510a 100644 --- a/dateroad-external/src/main/java/org/dateroad/feign/apple/AppleIdentityJWTValidator.java +++ b/dateroad-external/src/main/java/org/dateroad/feign/apple/AppleIdentityJWTValidator.java @@ -1,18 +1,17 @@ package org.dateroad.feign.apple; import io.jsonwebtoken.Claims; +import lombok.RequiredArgsConstructor; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component +@RequiredArgsConstructor public class AppleIdentityJWTValidator { - @Value("${feign.apple.iss}") - private String iss; - @Value("${feign.apple.client-id}") - private String clientId; + private final AppleProperties appleProperties; public boolean isValidAppleIdentityToken(final Claims claims) { - return claims.getIssuer().contains(iss) - && claims.getAudience().equals(clientId); + return claims.getIssuer().contains(appleProperties.getAud()) + && claims.getAudience().equals(appleProperties.getClientId()); } } diff --git a/dateroad-external/src/main/java/org/dateroad/feign/apple/AppleProperties.java b/dateroad-external/src/main/java/org/dateroad/feign/apple/AppleProperties.java new file mode 100644 index 00000000..fcc77df4 --- /dev/null +++ b/dateroad-external/src/main/java/org/dateroad/feign/apple/AppleProperties.java @@ -0,0 +1,19 @@ +package org.dateroad.feign.apple; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Getter +@Setter +@ConfigurationProperties(prefix = "feign.apple") +@Component +public class AppleProperties { + private String iss; + private String aud; + private String clientId; + private String kid; + private String alg; + private String type; +} diff --git a/dateroad-external/src/main/java/org/dateroad/feign/apple/AppleTokenRes.java b/dateroad-external/src/main/java/org/dateroad/feign/apple/AppleTokenRes.java new file mode 100644 index 00000000..0bf0ca54 --- /dev/null +++ b/dateroad-external/src/main/java/org/dateroad/feign/apple/AppleTokenRes.java @@ -0,0 +1,10 @@ +package org.dateroad.feign.apple; + +public record AppleTokenRes( + String access_token, + String token_type, + Integer expires_in, + String refresh_token, + String id_token +) { +} diff --git a/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoErrorRes.java b/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoErrorRes.java deleted file mode 100644 index ba62619c..00000000 --- a/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoErrorRes.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.dateroad.feign.kakao; - -import lombok.*; - -@Getter -@NoArgsConstructor(access = AccessLevel.PROTECTED) -@AllArgsConstructor(access = AccessLevel.PRIVATE) -public class KakaoErrorRes { - private String error; - private int code; -} diff --git a/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoFeignApi.java b/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoFeignApi.java index e2db7ba1..814c1eb1 100644 --- a/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoFeignApi.java +++ b/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoFeignApi.java @@ -1,11 +1,17 @@ package org.dateroad.feign.kakao; +import org.dateroad.feign.kakao.dto.response.KaKaoUnlinkRes; +import org.dateroad.feign.kakao.dto.response.KakaoAccessTokenInfoRes; import org.springframework.cloud.openfeign.FeignClient; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.*; @FeignClient(name = "${feign.kakao.name}", url = "${feign.kakao.url}") public interface KakaoFeignApi { - @GetMapping + @GetMapping("/access_token_info") KakaoAccessTokenInfoRes getKakaoPlatformUserId(@RequestHeader("Authorization") String accessTokenWithTokenType); + + @PostMapping("/unlink") + KaKaoUnlinkRes unlink(@RequestHeader("Authorization") String appAdminKey, + @RequestParam("target_id_type") String targetIdType, + @RequestParam("target_id") Long tagerId); } 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 new file mode 100644 index 00000000..375d7c48 --- /dev/null +++ b/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoFeignProvider.java @@ -0,0 +1,80 @@ +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 KakaoFeignProvider { + private final KakaoProperties kakaoProperties; + private final KakaoFeignApi kakaoFeignApi; + private final ObjectMapper objectMapper; + + private final String TARGETIDTYPE = "user_id"; + + //AuthService에서 호출 : 카카오에서 주는 userId 받아오기 + public String getKakaoPlatformUserId(final String kakaoAccessToken) { + String kakaoRequestHeader = getKakaoRequestHeader(KakaoRequestType.ACCESS_TOKEN_INFO, kakaoAccessToken); + KakaoAccessTokenInfoRes kakaoAccessTokenInfoRes = getKakaoAccessTokenInfoFeign(kakaoRequestHeader); + return String.valueOf(kakaoAccessTokenInfoRes.id()); + } + + //AuthService에서 호출 : 회원탈퇴 할 때, 카카오톡과 연결 끊기 + public void unLinkWithKakao(final String kakaoPlatformUserId) { + String kakaoRequestHeader = getKakaoRequestHeader(KakaoRequestType.UN_LINK, kakaoPlatformUserId); + try { + kakaoFeignApi.unlink(kakaoRequestHeader, TARGETIDTYPE, Long.valueOf(kakaoPlatformUserId)); + } catch (FeignException e) { + throw new UnauthorizedException(FailureCode.UN_LINK_WITH_KAKAO_UNAUTHORIZED); + } + } + + private KakaoAccessTokenInfoRes getKakaoAccessTokenInfoFeign(final String accessTokenWithTokenType) { + try { + return kakaoFeignApi.getKakaoPlatformUserId(accessTokenWithTokenType); + } 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 getKakaoRequestHeader(final KakaoRequestType kakaoRequestType, final String accessToken) { + if (kakaoRequestType == KakaoRequestType.ACCESS_TOKEN_INFO) { + return KakaoHeaderType.BEARER.getTokenType() + accessToken; + } else if (kakaoRequestType == KakaoRequestType.UN_LINK) { + return KakaoHeaderType.KAKAOAK.getTokenType() + kakaoProperties.getAdminKey(); + } else { + throw new UnauthorizedException(FailureCode.INVALID_KAKAO_ACCESS); + } + } + + 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.INVALID_KAKAO_TOKEN); + } + } +} diff --git a/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoHeaderType.java b/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoHeaderType.java new file mode 100644 index 00000000..be7869a1 --- /dev/null +++ b/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoHeaderType.java @@ -0,0 +1,14 @@ +package org.dateroad.feign.kakao; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public enum KakaoHeaderType { + BEARER("Bearer "), + KAKAOAK("KakaoAK "), + ; + + private final String tokenType; +} 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 deleted file mode 100644 index eb91bf0c..00000000 --- a/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoPlatformUserIdProvider.java +++ /dev/null @@ -1,60 +0,0 @@ -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.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.getCode() == -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.INVALID_KAKAO_TOKEN); - } - } -} diff --git a/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoProperties.java b/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoProperties.java new file mode 100644 index 00000000..7d401922 --- /dev/null +++ b/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoProperties.java @@ -0,0 +1,15 @@ +package org.dateroad.feign.kakao; + + +import lombok.Getter; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +@Getter +@Setter +@ConfigurationProperties("feign.kakao") +@Component +public class KakaoProperties { + private String adminKey; +} diff --git a/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoRequestType.java b/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoRequestType.java new file mode 100644 index 00000000..a2b62039 --- /dev/null +++ b/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoRequestType.java @@ -0,0 +1,6 @@ +package org.dateroad.feign.kakao; + +public enum KakaoRequestType { + ACCESS_TOKEN_INFO, + UN_LINK +} 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 new file mode 100644 index 00000000..5852a410 --- /dev/null +++ b/dateroad-external/src/main/java/org/dateroad/feign/kakao/dto/response/KaKaoErrorRes.java @@ -0,0 +1,9 @@ +package org.dateroad.feign.kakao.dto.response; + +import lombok.Getter; + +public record KaKaoErrorRes( + String error, + int code +) { +} diff --git a/dateroad-external/src/main/java/org/dateroad/feign/kakao/dto/response/KaKaoUnlinkRes.java b/dateroad-external/src/main/java/org/dateroad/feign/kakao/dto/response/KaKaoUnlinkRes.java new file mode 100644 index 00000000..ba1d490e --- /dev/null +++ b/dateroad-external/src/main/java/org/dateroad/feign/kakao/dto/response/KaKaoUnlinkRes.java @@ -0,0 +1,6 @@ +package org.dateroad.feign.kakao.dto.response; + +public record KaKaoUnlinkRes( + Long id +) { +} diff --git a/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoAccessTokenInfoRes.java b/dateroad-external/src/main/java/org/dateroad/feign/kakao/dto/response/KakaoAccessTokenInfoRes.java similarity index 78% rename from dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoAccessTokenInfoRes.java rename to dateroad-external/src/main/java/org/dateroad/feign/kakao/dto/response/KakaoAccessTokenInfoRes.java index d5f5194e..c7906b54 100644 --- a/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoAccessTokenInfoRes.java +++ b/dateroad-external/src/main/java/org/dateroad/feign/kakao/dto/response/KakaoAccessTokenInfoRes.java @@ -1,4 +1,4 @@ -package org.dateroad.feign.kakao; +package org.dateroad.feign.kakao.dto.response; public record KakaoAccessTokenInfoRes( Long id, From 75a0d5d8deed6f46ebf04f054ff3b0a4cd702240 Mon Sep 17 00:00:00 2001 From: Kwak Seong Joon Date: Thu, 11 Jul 2024 18:43:45 +0900 Subject: [PATCH 31/78] =?UTF-8?q?[chore]=20=EC=BD=94=EB=93=9C=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC=20-=20#54?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/dateroad/auth/jwt/JwtProvider.java | 3 --- .../java/org/dateroad/tag/repository/UserTagRepository.java | 1 + 2 files changed, 1 insertion(+), 3 deletions(-) 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 4701c56a..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 @@ -19,7 +19,6 @@ public class JwtProvider { private final JwtGenerator jwtGenerator; private final RefreshTokenGenerator refreshTokenGenerator; - private final RefreshTokenRepository refreshTokenRepository; public Token issueToken(final long userId) { return Token.of( @@ -28,7 +27,6 @@ public Token issueToken(final long userId) { ); } - //refreshToken 재발급할 때 검증 public void validateRefreshToken(LocalDateTime expireDate) { if (expireDate.isBefore(LocalDateTime.now())) { @@ -36,7 +34,6 @@ public void validateRefreshToken(LocalDateTime expireDate) { } } - //Base64 인코딩된 리프레시 토큰 문자열을 바이트 배열 private byte[] toBinary(String refreshToken) { return Base64.getDecoder().decode(refreshToken); 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 { + } From 7ec15134a04419edf8476ae93785da1fa50a62b1 Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Thu, 11 Jul 2024 18:52:05 +0900 Subject: [PATCH 32/78] =?UTF-8?q?[fix]=20repository=20=EC=96=B4=EB=85=B8?= =?UTF-8?q?=ED=85=8C=EC=9D=B4=EC=85=98=20=EC=B6=94=EA=B0=80=20-=20#63?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dateroad/dateAccess/repository/DataAccessRepository.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dateroad-domain/src/main/java/org/dateroad/dateAccess/repository/DataAccessRepository.java b/dateroad-domain/src/main/java/org/dateroad/dateAccess/repository/DataAccessRepository.java index 2edf845e..4db6ca25 100644 --- a/dateroad-domain/src/main/java/org/dateroad/dateAccess/repository/DataAccessRepository.java +++ b/dateroad-domain/src/main/java/org/dateroad/dateAccess/repository/DataAccessRepository.java @@ -6,7 +6,9 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; +@Repository public interface DataAccessRepository extends JpaRepository { @Query("SELECT da.course FROM DateAccess da WHERE da.user.id = :userId") List findCoursesByUserId(@Param("userId") Long userId); From b045f6f7720a5213ddfa85c6dd8c261aa90afe47 Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Thu, 11 Jul 2024 18:58:12 +0900 Subject: [PATCH 33/78] =?UTF-8?q?[fix]=20import=20error=20=ED=95=B4?= =?UTF-8?q?=EA=B2=B0=20-=20#63?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{DataAccessRepository.java => DateAccessRepository.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename dateroad-domain/src/main/java/org/dateroad/dateAccess/repository/{DataAccessRepository.java => DateAccessRepository.java} (89%) diff --git a/dateroad-domain/src/main/java/org/dateroad/dateAccess/repository/DataAccessRepository.java b/dateroad-domain/src/main/java/org/dateroad/dateAccess/repository/DateAccessRepository.java similarity index 89% rename from dateroad-domain/src/main/java/org/dateroad/dateAccess/repository/DataAccessRepository.java rename to dateroad-domain/src/main/java/org/dateroad/dateAccess/repository/DateAccessRepository.java index 4db6ca25..13030509 100644 --- a/dateroad-domain/src/main/java/org/dateroad/dateAccess/repository/DataAccessRepository.java +++ b/dateroad-domain/src/main/java/org/dateroad/dateAccess/repository/DateAccessRepository.java @@ -9,7 +9,7 @@ import org.springframework.stereotype.Repository; @Repository -public interface DataAccessRepository extends JpaRepository { +public interface DateAccessRepository extends JpaRepository { @Query("SELECT da.course FROM DateAccess da WHERE da.user.id = :userId") List findCoursesByUserId(@Param("userId") Long userId); } From a815ac05a34ddb8c01fd21c84cc0688ae00abb43 Mon Sep 17 00:00:00 2001 From: Kwak Seong Joon Date: Thu, 11 Jul 2024 22:18:14 +0900 Subject: [PATCH 34/78] =?UTF-8?q?[chore]=20=EC=BD=94=EB=93=9C=EB=A6=AC?= =?UTF-8?q?=EB=B7=B0=20=EB=B0=98=EC=98=81=20-=20#54?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/dateroad/auth/filter/JwtAuthenticationFilter.java | 3 +++ .../src/main/java/org/dateroad/user/service/AuthService.java | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) 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/user/service/AuthService.java b/dateroad-api/src/main/java/org/dateroad/user/service/AuthService.java index 45260681..09750e0e 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 @@ -145,8 +145,8 @@ public RefreshToken getRefreshTokenByToken(final String refreshToken) { log.error(e.getMessage()); throw new UnauthorizedException(FailureCode.INVALID_REFRESH_TOKEN_VALUE); } catch (Exception e) { - log.info(e.getMessage()); - throw new RuntimeException("An unexpected error occurred", e); + log.error(e.getMessage()); + throw new UnauthorizedException((FailureCode.UNAUTHORIZED)); } } From ccfdd2117c9d4775925a756ed9351f91f36f65df Mon Sep 17 00:00:00 2001 From: gardening-y Date: Fri, 12 Jul 2024 00:19:31 +0900 Subject: [PATCH 35/78] =?UTF-8?q?[fix]=20ArgumentResolver=20=EC=96=B4?= =?UTF-8?q?=EB=85=B8=ED=85=8C=EC=9D=B4=EC=85=98=20=EC=97=B0=EA=B2=B0=20-?= =?UTF-8?q?=20#38?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/dateroad/date/api/DateController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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..206bc181 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 @@ -23,7 +23,7 @@ public ResponseEntity createDate(@UserId final Long userId, } @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); From 87516839e8f68421e4395c471ab8a1fda064eba0 Mon Sep 17 00:00:00 2001 From: gardening-y Date: Fri, 12 Jul 2024 00:20:21 +0900 Subject: [PATCH 36/78] =?UTF-8?q?[feat]=20getDates=20Controller=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20-=20#38?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/dateroad/date/api/DateController.java | 8 ++++++++ 1 file changed, 8 insertions(+) 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 206bc181..8a2d1b9f 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,7 @@ 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.service.DateService; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -22,6 +23,13 @@ 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(@UserId final Long userId, @PathVariable final Long dateId) { From 7846f7454c876d267b0ce0b3783391b28ce2a596 Mon Sep 17 00:00:00 2001 From: gardening-y Date: Fri, 12 Jul 2024 00:20:47 +0900 Subject: [PATCH 37/78] =?UTF-8?q?[feat]=20getDates=20dto=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20-=20#38?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/dateroad/date/dto/response/DateDetailRes.java | 3 +++ 1 file changed, 3 insertions(+) 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 ) { From 3a356a93c7592c88f404f0e9c56a7605cb3de5b1 Mon Sep 17 00:00:00 2001 From: gardening-y Date: Fri, 12 Jul 2024 00:23:50 +0900 Subject: [PATCH 38/78] =?UTF-8?q?[feat]=20getDates=20dto=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20-=20#38?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../date/dto/response/DateGetRes.java | 34 +++++++++++++++++++ .../date/dto/response/DatesGetRes.java | 17 ++++++++++ 2 files changed, 51 insertions(+) create mode 100644 dateroad-api/src/main/java/org/dateroad/date/dto/response/DateGetRes.java create mode 100644 dateroad-api/src/main/java/org/dateroad/date/dto/response/DatesGetRes.java 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(); + } +} From 2de4ff57083cc9d936a147b3073aac59b9328fd8 Mon Sep 17 00:00:00 2001 From: gardening-y Date: Fri, 12 Jul 2024 00:26:43 +0900 Subject: [PATCH 39/78] =?UTF-8?q?[feat]=20getDates=20Service=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20-=20#38?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dateroad/date/service/DateService.java | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) 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..97a45ba2 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,13 @@ 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.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 +21,8 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import java.time.LocalDate; +import java.time.temporal.ChronoUnit; import java.util.List; @RequiredArgsConstructor @@ -37,6 +42,15 @@ public void createDate(final Long userId, final DateCreateReq dateCreateReq) { createDatePlace(date, dateCreateReq.places()); } + public DatesGetRes getDates(Long userId, 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) { User findUser = getUser(userId); Date findDate = getDate(dateId); @@ -79,6 +93,28 @@ private void createDatePlace(Date date, List places) { datePlaceRepository.saveAll(datePlaces); } + private List fetchDatesByUserIdAndTime(Long userId, String time, 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(Date date, LocalDate currentDate) { + int dDay = calculateDday(date.getDate(), currentDate); + List dateTags = getDateTag(date); + return DateGetRes.of(date, dateTags, dDay); + } + + private int calculateDday(LocalDate date, LocalDate currentDate) { + return (int) ChronoUnit.DAYS.between(currentDate, date); + } + private Date getDate(Long dateId) { return dateRepository.findById(dateId) .orElseThrow(() -> new EntityNotFoundException(FailureCode.DATE_NOT_FOUND)); From e2cb9580e3689e8e250b9ebff54046909dc6ddcd Mon Sep 17 00:00:00 2001 From: gardening-y Date: Fri, 12 Jul 2024 00:26:56 +0900 Subject: [PATCH 40/78] =?UTF-8?q?[feat]=20getDates=20=EC=98=88=EC=99=B8=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20=EA=B5=AC=ED=98=84=20-=20#38?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dateroad-common/src/main/java/org/dateroad/code/FailureCode.java | 1 + 1 file changed, 1 insertion(+) 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 ee6f5c1a..bc642b88 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 From aba68107180ee37a6efecf48db1d477d7b0692bf Mon Sep 17 00:00:00 2001 From: gardening-y Date: Fri, 12 Jul 2024 00:27:44 +0900 Subject: [PATCH 41/78] =?UTF-8?q?[feat]=20getDates=20Repository=20?= =?UTF-8?q?=EA=B2=80=EC=83=89=20=EC=BF=BC=EB=A6=AC=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?-=20#38?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/dateroad/date/service/DateRepository.java | 10 ++++++++++ 1 file changed, 10 insertions(+) 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..a9488067 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,16 @@ 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; public interface DateRepository extends JpaRepository { + @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); } From 5fa621514e128b134f4fa02bd7867b9efb9892ec Mon Sep 17 00:00:00 2001 From: gardening-y Date: Fri, 12 Jul 2024 00:34:33 +0900 Subject: [PATCH 42/78] =?UTF-8?q?[del]=20=EC=A0=95=EB=A0=AC=20=EB=A7=9E?= =?UTF-8?q?=EC=B6=A4=20-=20#38?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/dateroad/date/api/DateController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 8a2d1b9f..52f51541 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 @@ -25,7 +25,7 @@ public ResponseEntity createDate(@UserId final Long userId, @GetMapping public ResponseEntity getDates(@UserId final Long userId, - @RequestParam final String time) { + @RequestParam final String time) { DatesGetRes datesGetRes = dateService.getDates(userId, time); return ResponseEntity.ok(datesGetRes); } From 9e09a1074d41426b3cd06806c6f1dc0681f50aef Mon Sep 17 00:00:00 2001 From: gardening-y Date: Fri, 12 Jul 2024 01:25:07 +0900 Subject: [PATCH 43/78] =?UTF-8?q?[refactor]=20final=20=EC=84=A0=EC=96=B8?= =?UTF-8?q?=20-=20#38?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dateroad/date/service/DateService.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) 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 97a45ba2..84d5d04c 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 @@ -42,7 +42,7 @@ public void createDate(final Long userId, final DateCreateReq dateCreateReq) { createDatePlace(date, dateCreateReq.places()); } - public DatesGetRes getDates(Long userId, String time) { + public DatesGetRes getDates(final Long userId, final String time) { LocalDate currentDate = LocalDate.now(); List dates = fetchDatesByUserIdAndTime(userId, time, currentDate); List dateGetResList = dates.stream() @@ -70,30 +70,30 @@ public void deleteDate(final Long userId, final Long dateId) { dateRepository.deleteById(dateId); } - private User getUser(Long userId) { + private User getUser(final Long userId) { return userRepository.findById(userId) .orElseThrow(() -> new EntityNotFoundException(FailureCode.USER_NOT_FOUND)); } - private Date createDate(User findUser, DateCreateReq dateCreateReq) { + private Date createDate(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 createDateTag(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 createDatePlace(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 List fetchDatesByUserIdAndTime(Long userId, String time, LocalDate currentDate) { + private List fetchDatesByUserIdAndTime(final Long userId, final String time, final LocalDate currentDate) { if (time.equalsIgnoreCase("PAST")) { return dateRepository.findPastDatesByUserId(userId, currentDate); } @@ -105,28 +105,28 @@ else if (time.equalsIgnoreCase("FUTURE")) { } } - private DateGetRes createDateGetRes(Date date, LocalDate currentDate) { + 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(LocalDate date, LocalDate currentDate) { + private int calculateDday(final LocalDate date, final LocalDate currentDate) { return (int) ChronoUnit.DAYS.between(currentDate, date); } - private Date getDate(Long dateId) { + 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); @@ -134,7 +134,7 @@ 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); From c820238787f427390d2f711e501e7e5cd0448f57 Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Fri, 12 Jul 2024 01:45:46 +0900 Subject: [PATCH 44/78] =?UTF-8?q?[chore]=20Redis=20=EC=9D=98=EC=A1=B4?= =?UTF-8?q?=EC=84=B1=20=EC=B6=94=EA=B0=80=20-=20#65?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dateroad-api/build.gradle | 1 + .../dateroad/config/RedisStreamConfig.java | 125 ++++++++++++++++++ .../course/dto/request/PointUseReq.java | 20 +++ .../course/service/CoursePaymentType.java | 5 + .../point/event/pointEventListener.java | 32 +++++ 5 files changed, 183 insertions(+) create mode 100644 dateroad-api/src/main/java/org/dateroad/config/RedisStreamConfig.java create mode 100644 dateroad-api/src/main/java/org/dateroad/course/dto/request/PointUseReq.java create mode 100644 dateroad-api/src/main/java/org/dateroad/course/service/CoursePaymentType.java create mode 100644 dateroad-api/src/main/java/org/dateroad/point/event/pointEventListener.java diff --git a/dateroad-api/build.gradle b/dateroad-api/build.gradle index 6fa0c7b4..731a49d5 100644 --- a/dateroad-api/build.gradle +++ b/dateroad-api/build.gradle @@ -2,6 +2,7 @@ dependencies { implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-data-jpa' implementation 'org.springframework.boot:spring-boot-starter-security' + implementation 'org.springframework.boot:spring-boot-starter-data-redis' runtimeOnly 'org.postgresql:postgresql' implementation project(path: ':dateroad-common') diff --git a/dateroad-api/src/main/java/org/dateroad/config/RedisStreamConfig.java b/dateroad-api/src/main/java/org/dateroad/config/RedisStreamConfig.java new file mode 100644 index 00000000..bcbe3630 --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/config/RedisStreamConfig.java @@ -0,0 +1,125 @@ +package org.dateroad.config; + + +import io.lettuce.core.api.async.RedisAsyncCommands; +import io.lettuce.core.codec.StringCodec; +import io.lettuce.core.output.StatusOutput; +import io.lettuce.core.protocol.CommandArgs; +import io.lettuce.core.protocol.CommandKeyword; +import io.lettuce.core.protocol.CommandType; +import lombok.RequiredArgsConstructor; +import org.dateroad.date.repository.CourseRepository; +import org.dateroad.point.event.FreeEventListener; +import org.dateroad.point.event.pointEventListener; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; +import org.springframework.data.redis.connection.stream.*; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.StringRedisSerializer; +import org.springframework.data.redis.stream.StreamMessageListenerContainer; +import org.springframework.data.redis.stream.Subscription; + +import java.time.Duration; +import java.util.Iterator; +import java.util.Objects; + +@Configuration +@RequiredArgsConstructor +public class RedisStreamConfig { + private final pointEventListener pointEventListener; + private final FreeEventListener freeEventListener; + @Value("${spring.data.redis.host}") + private String host; + @Value("${spring.data.redis.port}") + private int port; + + @Bean + public RedisTemplate redisTemplate() { + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setConnectionFactory(redisConnectionFactory()); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setValueSerializer(new StringRedisSerializer()); + return redisTemplate; + } + + @Bean + public RedisConnectionFactory redisConnectionFactory() { + return new LettuceConnectionFactory(host, port); + } + + public void createStreamConsumerGroup(String streamKey, String consumerGroupName) { + // Stream이 존재 하지 않으면, MKSTREAM 옵션을 통해 만들고, ConsumerGroup또한 생성한다 + System.out.println(streamKey + consumerGroupName); + // Stream이 존재하지 않으면, MKSTREAM 옵션을 통해 스트림과 소비자 그룹을 생성 + if (Boolean.FALSE.equals(redisTemplate().hasKey(streamKey))) { + RedisAsyncCommands commands = (RedisAsyncCommands) Objects.requireNonNull( + redisTemplate() + .getConnectionFactory()) + .getConnection() + .getNativeConnection(); + + CommandArgs args = new CommandArgs<>(StringCodec.UTF8) + .add(CommandKeyword.CREATE) + .add(streamKey) + .add(consumerGroupName) + .add("0") + .add("MKSTREAM"); + // MKSTREAM 옵션을 사용하여 스트림과 그룹을 생성 + commands.dispatch(CommandType.XGROUP, new StatusOutput<>(StringCodec.UTF8), args).toCompletableFuture() + .join(); + } + // Stream 존재 시, ConsumerGroup 존재 여부 확인 후 ConsumerGroup을 생성 + else { + if (!isStreamConsumerGroupExist(streamKey, consumerGroupName)) { + redisTemplate().opsForStream().createGroup(streamKey, ReadOffset.from("0"), consumerGroupName); + } + } + } + // ConsumerGroup 존재 여부 확인 + public boolean isStreamConsumerGroupExist(String streamKey, String consumerGroupName) { + Iterator iterator = redisTemplate() + .opsForStream().groups(streamKey).stream().iterator(); + + while (iterator.hasNext()) { + StreamInfo.XInfoGroup xInfoGroup = iterator.next(); + if (xInfoGroup.groupName().equals(consumerGroupName)) { + return true; + } + } + return false; + } + + @Bean + public Subscription PointSubscription() { + createStreamConsumerGroup("coursePoint", "courseGroup"); + StreamMessageListenerContainer.StreamMessageListenerContainerOptions> containerOptions = StreamMessageListenerContainer.StreamMessageListenerContainerOptions + .builder().pollTimeout(Duration.ofMillis(100)).build(); + + StreamMessageListenerContainer> container = StreamMessageListenerContainer.create( + redisConnectionFactory(), + containerOptions); + + Subscription subscription = container.receiveAutoAck(Consumer.from("courseGroup", "instance-1"), + StreamOffset.create("course", ReadOffset.lastConsumed()), pointEventListener); + container.start(); + return subscription; + } + + @Bean + public Subscription FreeSubscription() { + createStreamConsumerGroup("courseFree", "courseGroup"); + StreamMessageListenerContainer.StreamMessageListenerContainerOptions> containerOptions = StreamMessageListenerContainer.StreamMessageListenerContainerOptions + .builder().pollTimeout(Duration.ofMillis(100)).build(); + StreamMessageListenerContainer> container = StreamMessageListenerContainer.create( + redisConnectionFactory(), + containerOptions); + Subscription subscription = container.receiveAutoAck(Consumer.from("courseGroup", "instance-2"), + StreamOffset.create("courseFree", ReadOffset.lastConsumed()), freeEventListener); + container.start(); + return subscription; + } +} + diff --git a/dateroad-api/src/main/java/org/dateroad/course/dto/request/PointUseReq.java b/dateroad-api/src/main/java/org/dateroad/course/dto/request/PointUseReq.java new file mode 100644 index 00000000..3581a04b --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/course/dto/request/PointUseReq.java @@ -0,0 +1,20 @@ +package org.dateroad.course.dto.request; + +import lombok.AccessLevel; +import lombok.Builder; +import org.dateroad.point.domain.TransactionType; + +@Builder(access = AccessLevel.PROTECTED) +public record PointUseReq( + int point, + TransactionType type, + String description +) { + public static PointUseReq of(int point, TransactionType type, String description) { + return PointUseReq.builder() + .point(point) + .type(type) + .description(description) + .build(); + } +} diff --git a/dateroad-api/src/main/java/org/dateroad/course/service/CoursePaymentType.java b/dateroad-api/src/main/java/org/dateroad/course/service/CoursePaymentType.java new file mode 100644 index 00000000..28b51694 --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/course/service/CoursePaymentType.java @@ -0,0 +1,5 @@ +package org.dateroad.course.service; + +public enum CoursePaymentType { + FREE,POINT +} diff --git a/dateroad-api/src/main/java/org/dateroad/point/event/pointEventListener.java b/dateroad-api/src/main/java/org/dateroad/point/event/pointEventListener.java new file mode 100644 index 00000000..28a4bbfe --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/point/event/pointEventListener.java @@ -0,0 +1,32 @@ +package org.dateroad.point.event; + +import java.util.Map; +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import org.dateroad.code.FailureCode; +import org.dateroad.exception.DateRoadException; +import org.dateroad.user.domain.User; +import org.dateroad.user.repository.UserRepository; +import org.springframework.data.redis.connection.stream.MapRecord; +import org.springframework.data.redis.stream.StreamListener; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +@RequiredArgsConstructor(access = AccessLevel.PROTECTED) +public class pointEventListener implements StreamListener> { + private final UserRepository userRepository; + + @Override + @Transactional + public void onMessage(MapRecord message) { + Map map = message.getValue(); + Long userId = Long.valueOf(map.get("userId")); + User user = userRepository.findById(userId).orElseThrow( + () -> new DateRoadException(FailureCode.USER_NOT_FOUND) + ); + int point = Integer.parseInt(map.get("point")); // 감소시킬 포인트 + user.setTotalPoint(user.getTotalPoint() + point); + userRepository.save(user); + } +} From 6dac86cc5b5b31886e9670b754a5372c4670a651 Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Fri, 12 Jul 2024 01:46:12 +0900 Subject: [PATCH 45/78] =?UTF-8?q?[feat]=20RedisStream=20Config=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20-=20#65?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/dateroad/config/RedisStreamConfig.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/dateroad-api/src/main/java/org/dateroad/config/RedisStreamConfig.java b/dateroad-api/src/main/java/org/dateroad/config/RedisStreamConfig.java index bcbe3630..d3b47bba 100644 --- a/dateroad-api/src/main/java/org/dateroad/config/RedisStreamConfig.java +++ b/dateroad-api/src/main/java/org/dateroad/config/RedisStreamConfig.java @@ -50,14 +50,14 @@ public RedisConnectionFactory redisConnectionFactory() { return new LettuceConnectionFactory(host, port); } - public void createStreamConsumerGroup(String streamKey, String consumerGroupName) { + public void createStreamConsumerGroup(final String streamKey, final String consumerGroupName) { // Stream이 존재 하지 않으면, MKSTREAM 옵션을 통해 만들고, ConsumerGroup또한 생성한다 System.out.println(streamKey + consumerGroupName); // Stream이 존재하지 않으면, MKSTREAM 옵션을 통해 스트림과 소비자 그룹을 생성 if (Boolean.FALSE.equals(redisTemplate().hasKey(streamKey))) { RedisAsyncCommands commands = (RedisAsyncCommands) Objects.requireNonNull( - redisTemplate() - .getConnectionFactory()) + redisTemplate() + .getConnectionFactory()) .getConnection() .getNativeConnection(); @@ -78,8 +78,9 @@ public void createStreamConsumerGroup(String streamKey, String consumerGroupName } } } + // ConsumerGroup 존재 여부 확인 - public boolean isStreamConsumerGroupExist(String streamKey, String consumerGroupName) { + public boolean isStreamConsumerGroupExist(final String streamKey, final String consumerGroupName) { Iterator iterator = redisTemplate() .opsForStream().groups(streamKey).stream().iterator(); @@ -103,7 +104,7 @@ public Subscription PointSubscription() { containerOptions); Subscription subscription = container.receiveAutoAck(Consumer.from("courseGroup", "instance-1"), - StreamOffset.create("course", ReadOffset.lastConsumed()), pointEventListener); + StreamOffset.create("coursePoint", ReadOffset.lastConsumed()), pointEventListener); container.start(); return subscription; } From 24b575f64495c731702bfb35a327fa3d4b0a4f39 Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Fri, 12 Jul 2024 01:47:41 +0900 Subject: [PATCH 46/78] =?UTF-8?q?[feat]=20Point=20=EC=82=AC=EC=9A=A9=20?= =?UTF-8?q?=EB=B0=8F=20=EA=B2=80=EC=A6=9D=20=EB=A1=9C=EC=A7=81=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20-=20#65?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dateroad/course/api/CourseController.java | 14 ++++++ .../dateroad/course/facade/AsyncService.java | 21 +++++++++ .../course/service/CourseService.java | 43 ++++++++++++++++++- 3 files changed, 77 insertions(+), 1 deletion(-) 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 b04144af..0116ac15 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 @@ -8,6 +8,7 @@ import org.dateroad.course.dto.request.CourseGetAllReq; import org.dateroad.course.dto.request.CourseCreateReq; import org.dateroad.course.dto.request.CoursePlaceGetReq; +import org.dateroad.course.dto.request.PointUseReq; import org.dateroad.course.dto.request.TagCreateReq; import org.dateroad.course.dto.response.CourseCreateRes; import org.dateroad.course.dto.response.CourseGetAllRes; @@ -20,7 +21,10 @@ 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; @@ -64,4 +68,14 @@ public ResponseEntity createCourse( HttpStatus.CREATED ).body(CourseCreateRes.of(course.getId())); } + + @PostMapping("/{courseId}/date-access") + public ResponseEntity openCourse( + @UserId final Long userId, + @PathVariable final Long courseId, + @RequestBody final PointUseReq pointUseReq + ) { + courseService.openCourse(userId,courseId,pointUseReq); + return ResponseEntity.ok().build(); + } } diff --git a/dateroad-api/src/main/java/org/dateroad/course/facade/AsyncService.java b/dateroad-api/src/main/java/org/dateroad/course/facade/AsyncService.java index 2ee4eaed..d3d3c3b8 100644 --- a/dateroad-api/src/main/java/org/dateroad/course/facade/AsyncService.java +++ b/dateroad-api/src/main/java/org/dateroad/course/facade/AsyncService.java @@ -1,15 +1,20 @@ package org.dateroad.course.facade; +import java.util.HashMap; import java.util.List; +import java.util.Map; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import org.dateroad.Image.service.ImageService; import org.dateroad.course.dto.request.CoursePlaceGetReq; +import org.dateroad.course.dto.request.PointUseReq; import org.dateroad.course.dto.request.TagCreateReq; import org.dateroad.course.service.CoursePlaceService; import org.dateroad.course.service.CourseTagService; import org.dateroad.date.domain.Course; import org.dateroad.image.domain.Image; +import org.dateroad.user.domain.User; +import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -22,6 +27,8 @@ public class AsyncService { private final CoursePlaceService coursePlaceService; private final CourseTagService courseTagService; private final ImageService imageService; + private final StringRedisTemplate redisTemplate; + public Image findFirstByCourseOrderBySequenceAsc(final Course course) { return imageService.findFirstByCourseOrderBySequenceAsc(course); @@ -45,4 +52,18 @@ public void createCourseTags(final List tags, final Course course) public void createCoursePlace(final List places, final Course course) { coursePlaceService.createCoursePlace(places, course); } + + public void publishEvenUserPoint(User user, PointUseReq pointUseReq) { + Map fieldMap = new HashMap<>(); + fieldMap.put("userId", user.getId().toString()); + fieldMap.put("point", Integer.toString(pointUseReq.point())); + fieldMap.put("type", pointUseReq.type().toString()); + redisTemplate.opsForStream().add("coursePoint", fieldMap); + } + + public void publishEventUserFree(User user) { + Map fieldMap = new HashMap<>(); + fieldMap.put("userId", user.getId().toString()); + redisTemplate.opsForStream().add("courseFree", fieldMap); + } } 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 abd10e66..70d7a8d4 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 @@ -9,16 +9,20 @@ import org.dateroad.course.dto.request.CourseGetAllReq; import org.dateroad.course.dto.request.CourseCreateReq; import org.dateroad.course.dto.request.CoursePlaceGetReq; +import org.dateroad.course.dto.request.PointUseReq; import org.dateroad.course.dto.response.CourseDtoGetRes; import org.dateroad.course.dto.response.CourseGetAllRes; import org.dateroad.course.dto.response.DateAccessGetAllRes; import org.dateroad.course.facade.AsyncService; import org.dateroad.date.domain.Course; 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.image.domain.Image; import org.dateroad.like.repository.LikeRepository; +import org.dateroad.point.domain.Point; +import org.dateroad.point.repository.PointRepository; import org.dateroad.user.domain.User; import org.dateroad.user.repository.UserRepository; import org.springframework.data.jpa.domain.Specification; @@ -35,6 +39,7 @@ public class CourseService { private final DateAccessRepository dateAccessRepository; private final UserRepository userRepository; private final AsyncService asyncService; + private final PointRepository pointRepository; public CourseGetAllRes getAllCourses(CourseGetAllReq courseGetAllReq) { Specification spec = CourseSpecifications.filterByCriteria(courseGetAllReq); @@ -67,7 +72,7 @@ private CourseDtoGetRes convertToDto(Course course) { ); } - public DateAccessGetAllRes getAllDataAccessCourse(Long userId) { + public DateAccessGetAllRes getAllDataAccessCourse(final Long userId) { List accesses = dateAccessRepository.findCoursesByUserId(userId); List courseDtoGetResList = convertToDtoList(accesses, Function.identity()); return DateAccessGetAllRes.of(courseDtoGetResList); @@ -100,4 +105,40 @@ public Course createCourse(final Long userId, final CourseCreateReq courseRegist course.setThumbnail(thumnailUrl); return saveCourse; } + + @Transactional + public void openCourse(final Long userId, final Long courseId, final PointUseReq pointUseReq) { + User user = userRepository.findById(userId).orElseThrow( + () -> new DateRoadException(FailureCode.USER_NOT_FOUND) + ); + Course course = courseRepository.findById(courseId).orElseThrow( + () -> new DateRoadException(FailureCode.COURSE_NOT_FOUND) + ); + Point point = Point.create(user, pointUseReq.point(), pointUseReq.type(), pointUseReq.description()); + CoursePaymentType coursePaymentType = validateUserFreeOrPoint(user, pointUseReq.point()); + processCoursePayment(coursePaymentType, user, point, pointUseReq); + dateAccessRepository.save(DateAccess.create(course, user)); + } + + private CoursePaymentType validateUserFreeOrPoint(final User user, final int requiredPoints) { + if (user.getFree() > 0) { + return CoursePaymentType.FREE; // User가 free를 갖고 있으면 true를 반환 + } else if (user.getTotalPoint() < requiredPoints) { + throw new DateRoadException(FailureCode.INSUFFICIENT_USER_POINTS); + } + return CoursePaymentType.POINT; + } + + public void processCoursePayment(final CoursePaymentType coursePaymentType, User user, final Point point, + final PointUseReq pointUseReq) { + switch (coursePaymentType) { + case FREE -> { + asyncService.publishEventUserFree(user); + } + case POINT -> { + pointRepository.save(point); + asyncService.publishEvenUserPoint(user, pointUseReq); + } + } + } } From 0415ab478a96b530fedf9f02af5bb575398f15a2 Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Fri, 12 Jul 2024 01:48:46 +0900 Subject: [PATCH 47/78] =?UTF-8?q?[del]=20dateAccess=20id=20=ED=95=84?= =?UTF-8?q?=EB=93=9C=20NotNull=20=EC=A0=9C=EA=B1=B0=20-=20#65?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/dateroad/dateAccess/domain/DateAccess.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dateroad-domain/src/main/java/org/dateroad/dateAccess/domain/DateAccess.java b/dateroad-domain/src/main/java/org/dateroad/dateAccess/domain/DateAccess.java index 272b9624..15602e50 100644 --- a/dateroad-domain/src/main/java/org/dateroad/dateAccess/domain/DateAccess.java +++ b/dateroad-domain/src/main/java/org/dateroad/dateAccess/domain/DateAccess.java @@ -13,6 +13,7 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.ToString; import lombok.experimental.SuperBuilder; import org.dateroad.common.BaseTimeEntity; import org.dateroad.date.domain.Course; @@ -28,7 +29,6 @@ public class DateAccess extends BaseTimeEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "date_access_id") - @NotNull private Long id; @OneToOne From 9c1ada00064bd9f24710f9cfc4365a14a9682897 Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Fri, 12 Jul 2024 01:49:28 +0900 Subject: [PATCH 48/78] =?UTF-8?q?[feat]=20Point,=20Free=EC=97=90=20?= =?UTF-8?q?=EB=8C=80=ED=95=9C=20EventListener=20=EA=B5=AC=ED=98=84=20-=20#?= =?UTF-8?q?65?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../point/event/FreeEventListener.java | 32 +++++++++++++++++++ .../point/event/pointEventListener.java | 4 +-- 2 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 dateroad-api/src/main/java/org/dateroad/point/event/FreeEventListener.java diff --git a/dateroad-api/src/main/java/org/dateroad/point/event/FreeEventListener.java b/dateroad-api/src/main/java/org/dateroad/point/event/FreeEventListener.java new file mode 100644 index 00000000..c4f7ae2a --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/point/event/FreeEventListener.java @@ -0,0 +1,32 @@ +package org.dateroad.point.event; + +import java.util.Map; +import lombok.AccessLevel; +import lombok.RequiredArgsConstructor; +import org.dateroad.code.FailureCode; +import org.dateroad.exception.DateRoadException; +import org.dateroad.user.domain.User; +import org.dateroad.user.repository.UserRepository; +import org.springframework.data.redis.connection.stream.MapRecord; +import org.springframework.data.redis.stream.StreamListener; +import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; + +@Component +@RequiredArgsConstructor(access = AccessLevel.PROTECTED) +public class FreeEventListener implements StreamListener> { + private final UserRepository userRepository; + + @Override + @Transactional + public void onMessage(final MapRecord message) { + Map map = message.getValue(); + Long userId = Long.valueOf(map.get("userId")); + User user = userRepository.findById(userId).orElseThrow( + () -> new DateRoadException(FailureCode.USER_NOT_FOUND) + ); + int userPoint = user.getFree(); + user.setFree(userPoint -1); + userRepository.save(user); + } +} diff --git a/dateroad-api/src/main/java/org/dateroad/point/event/pointEventListener.java b/dateroad-api/src/main/java/org/dateroad/point/event/pointEventListener.java index 28a4bbfe..30997df9 100644 --- a/dateroad-api/src/main/java/org/dateroad/point/event/pointEventListener.java +++ b/dateroad-api/src/main/java/org/dateroad/point/event/pointEventListener.java @@ -19,14 +19,14 @@ public class pointEventListener implements StreamListener message) { + public void onMessage(final MapRecord message) { Map map = message.getValue(); Long userId = Long.valueOf(map.get("userId")); User user = userRepository.findById(userId).orElseThrow( () -> new DateRoadException(FailureCode.USER_NOT_FOUND) ); int point = Integer.parseInt(map.get("point")); // 감소시킬 포인트 - user.setTotalPoint(user.getTotalPoint() + point); + user.setTotalPoint(user.getTotalPoint() - point); userRepository.save(user); } } From 3e7ce1f1641cd7edc131e6cf9b9a201414a01e9d Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Fri, 12 Jul 2024 01:49:48 +0900 Subject: [PATCH 49/78] =?UTF-8?q?[feat]=20=EC=97=90=EB=9F=AC=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20=EB=A9=94=EC=84=B8=EC=A7=80=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?-=20#65?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/dateroad/code/FailureCode.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 ee6f5c1a..6f3530af 100644 --- a/dateroad-common/src/main/java/org/dateroad/code/FailureCode.java +++ b/dateroad-common/src/main/java/org/dateroad/code/FailureCode.java @@ -56,6 +56,8 @@ public enum FailureCode { DATE_TAG_NOT_FOUND(HttpStatus.NOT_FOUND, "e4045", "데이트 태그를 찾을 수 없습니다."), DATE_PLACE_NOT_FOUND(HttpStatus.NOT_FOUND, "e4046", "데이트 장소를 찾을 수 없습니다."), + COURSE_NOT_FOUND(HttpStatus.NOT_FOUND, "e4047", "코스를 찾을수 없습니다."), + INSUFFICIENT_USER_POINTS(HttpStatus.NOT_FOUND, "e4048", "유저의 포인트가 부족합니다."), /** * 405 Method Not Allowed */ @@ -68,11 +70,11 @@ public enum FailureCode { DUPLICATE_USER(HttpStatus.CONFLICT, "e4091", "이미 존재하는 유저입니다."), DUPLICATE_NICKNAME(HttpStatus.CONFLICT, "e4092", "이미 존재하는 닉네임입니다."), - + INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "e5000", "서버 내부 오류입니다."); /** * 500 Internal Server Error */ - INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "e5000", "서버 내부 오류입니다."); + private final HttpStatus httpStatus; private final String code; From 5c82f2aeafeac68707ef6350beab82de07d4e62a Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Fri, 12 Jul 2024 01:50:19 +0900 Subject: [PATCH 50/78] =?UTF-8?q?[chore]=20=EB=9D=84=EC=96=B4=EC=93=B0?= =?UTF-8?q?=EA=B8=B0=20=EC=A0=9C=EA=B1=B0=20-=20#65?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/dateroad/point/service/PointService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dateroad-api/src/main/java/org/dateroad/point/service/PointService.java b/dateroad-api/src/main/java/org/dateroad/point/service/PointService.java index 303ca134..ca29baf8 100644 --- a/dateroad-api/src/main/java/org/dateroad/point/service/PointService.java +++ b/dateroad-api/src/main/java/org/dateroad/point/service/PointService.java @@ -14,7 +14,6 @@ @RequiredArgsConstructor public class PointService { private final PointRepository pointRepository; - public PointGetAllRes getAllPoints(Long userId) { List points = pointRepository.findAllByUserId(userId) .stream().map(PointDto::of) @@ -29,4 +28,5 @@ public PointsDto pointTypeChecktoList(List points, TransactionType typ .map(PointDtoRes::of) .toList()); } + } From e3e7691928fa5dd9ab2cc5a91be11a11cc3bb127 Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Fri, 12 Jul 2024 01:50:53 +0900 Subject: [PATCH 51/78] =?UTF-8?q?[feat]=20User=20free,=20totalPoint=20?= =?UTF-8?q?=EC=97=90=20Setter=20=EC=B6=94=EA=B0=80=20-=20#65?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/dateroad/user/domain/User.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/dateroad-domain/src/main/java/org/dateroad/user/domain/User.java b/dateroad-domain/src/main/java/org/dateroad/user/domain/User.java index 2a089682..bb372156 100644 --- a/dateroad-domain/src/main/java/org/dateroad/user/domain/User.java +++ b/dateroad-domain/src/main/java/org/dateroad/user/domain/User.java @@ -7,6 +7,7 @@ import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.Setter; import org.dateroad.common.BaseTimeEntity; import org.dateroad.tag.domain.UserTag; @@ -45,11 +46,13 @@ public class User extends BaseTimeEntity { @Builder.Default @Column(name = "free") @NotNull + @Setter private int free = 3; @Builder.Default @Column(name = "total_point") @NotNull + @Setter private int totalPoint = 0; @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY) From e0648838ff4cad4d1dcc0c325defcceb7c0adc28 Mon Sep 17 00:00:00 2001 From: gardening-y Date: Fri, 12 Jul 2024 02:33:25 +0900 Subject: [PATCH 52/78] =?UTF-8?q?[fix]=20course=20Controller=20url=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20-=20#38?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/dateroad/course/api/CourseController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 b04144af..2118945d 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 @@ -49,7 +49,7 @@ public ResponseEntity getAllDataAccesCourse( 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, From 114c63f1479d511fe4657c9f03817573505acc19 Mon Sep 17 00:00:00 2001 From: gardening-y Date: Fri, 12 Jul 2024 02:33:42 +0900 Subject: [PATCH 53/78] =?UTF-8?q?[fix]=20course=20Controller=20url=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20-=20#68?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/dateroad/course/api/CourseController.java | 1 - 1 file changed, 1 deletion(-) 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 2118945d..4b6f6be9 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; From e7dc109f1cd957cbe380b1a7025eeeff92d5f10a Mon Sep 17 00:00:00 2001 From: Kwak Seong Joon Date: Fri, 12 Jul 2024 03:15:47 +0900 Subject: [PATCH 54/78] =?UTF-8?q?[feat]=20=EC=BD=94=EC=8A=A4=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20=EC=A1=B0=ED=9A=8C=20dto=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?=EB=B0=8F=20=EC=BD=94=EB=93=9C=20=EC=A0=95=EB=A6=AC=20-=20#66?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../date/dto/response/CourseGetDetailRes.java | 105 ++++++++++++++++++ .../java/org/dateroad/code/FailureCode.java | 4 + .../date/repository/CourseRepository.java | 3 + .../repository/DateAccessRepository.java | 2 + .../java/org/dateroad/image/domain/Image.java | 1 + .../image/repository/ImageRepository.java | 3 + .../like/repository/LikeRepository.java | 2 +- .../repository/CoursePlaceRepository.java | 2 + .../org/dateroad/tag/domain/CourseTag.java | 6 +- .../tag/repository/CourseTagRepository.java | 3 + dateroad-external/build.gradle | 3 +- .../apple/AppleClientSecretGenerator.java | 2 - .../kakao/dto/response/KaKaoErrorRes.java | 2 +- 13 files changed, 128 insertions(+), 10 deletions(-) create mode 100644 dateroad-api/src/main/java/org/dateroad/date/dto/response/CourseGetDetailRes.java diff --git a/dateroad-api/src/main/java/org/dateroad/date/dto/response/CourseGetDetailRes.java b/dateroad-api/src/main/java/org/dateroad/date/dto/response/CourseGetDetailRes.java new file mode 100644 index 00000000..3d617ec9 --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/date/dto/response/CourseGetDetailRes.java @@ -0,0 +1,105 @@ +package org.dateroad.date.dto.response; + +import lombok.AccessLevel; +import lombok.Builder; +import org.dateroad.date.domain.Course; +import org.dateroad.tag.domain.CourseTag; +import org.dateroad.tag.domain.DateTag; +import org.dateroad.tag.domain.DateTagType; + +import java.time.LocalDate; +import java.time.LocalTime; +import java.util.List; + +@Builder(access = AccessLevel.PRIVATE) +public record CourseGetDetailRes( + Long courseId, + List images, + int like, + float totalTime, + LocalDate date, + String city, + String title, + String description, + LocalTime startAt, + List places, + int totalCost, + List tags, + boolean isAccess, + int free, + int totalPoint +) { + + public static CourseGetDetailRes of(Long courseId, + List images, + int like, + float totalTime, + LocalDate date, + String city, + String title, + String description, + LocalTime startAt, + List places, + int totalCost, + List tags, + boolean isAccess, + int free, + int totalPoint) { + return CourseGetDetailRes.builder() + .courseId(courseId) + .images(images) + .like(like) + .totalTime(totalTime) + .date(date) + .city(city) + .title(title) + .description(description) + .startAt(startAt) + .places(places) + .totalCost(totalCost) + .tags(tags) + .isAccess(isAccess) + .free(free) + .totalPoint(totalPoint) + .build(); + } + + @Builder(access = AccessLevel.PRIVATE) + public record ImagesList( + String imageUrl, + int sequence + ) { + public static ImagesList of(final String imageUrl, final int sequence) { + return ImagesList.builder() + .imageUrl(imageUrl) + .sequence(sequence) + .build(); + } + } + + @Builder(access = AccessLevel.PRIVATE) + public record Places( + int sequence, + String title, + float duration + ) { + public static Places of(final int sequence, final String title, final float duration) { + return Places.builder() + .sequence(sequence) + .title(title) + .duration(duration) + .build(); + } + } + + @Builder(access = AccessLevel.PRIVATE) + public record CourseTag( + DateTagType tag + ) { + public static CourseTag of(final DateTagType tag) { + return CourseTag.builder() + .tag(tag) + .build(); + } + } +} 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 ee6f5c1a..79e814c9 100644 --- a/dateroad-common/src/main/java/org/dateroad/code/FailureCode.java +++ b/dateroad-common/src/main/java/org/dateroad/code/FailureCode.java @@ -55,6 +55,10 @@ 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", "데이트 코스를 찾을 수 없습니다."), + IMAGE_NOT_FOUND(HttpStatus.NOT_FOUND, "e4048", "이미지를 찾을 수 없습니다."), + COURSE_PLACE_NOT_FOUND(HttpStatus.NOT_FOUND, "e4049", "코스 장소를 찾을 수 없습니다."), + COURSE_TAG_NOT_FOUND(HttpStatus.NOT_FOUND, "e40410", "데이트 태그를 찾을 수 없습니다."), /** * 405 Method Not Allowed diff --git a/dateroad-domain/src/main/java/org/dateroad/date/repository/CourseRepository.java b/dateroad-domain/src/main/java/org/dateroad/date/repository/CourseRepository.java index 4526879f..5fd92091 100644 --- a/dateroad-domain/src/main/java/org/dateroad/date/repository/CourseRepository.java +++ b/dateroad-domain/src/main/java/org/dateroad/date/repository/CourseRepository.java @@ -1,6 +1,8 @@ package org.dateroad.date.repository; import java.util.List; +import java.util.Optional; + import org.dateroad.date.domain.Course; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; @@ -10,5 +12,6 @@ // CourseRepository.java @Repository public interface CourseRepository extends JpaRepository , JpaSpecificationExecutor { + Optional findCourseByUserId(Long userId); } diff --git a/dateroad-domain/src/main/java/org/dateroad/dateAccess/repository/DateAccessRepository.java b/dateroad-domain/src/main/java/org/dateroad/dateAccess/repository/DateAccessRepository.java index 13030509..3f6c90f9 100644 --- a/dateroad-domain/src/main/java/org/dateroad/dateAccess/repository/DateAccessRepository.java +++ b/dateroad-domain/src/main/java/org/dateroad/dateAccess/repository/DateAccessRepository.java @@ -12,4 +12,6 @@ public interface DateAccessRepository extends JpaRepository { @Query("SELECT da.course FROM DateAccess da WHERE da.user.id = :userId") List findCoursesByUserId(@Param("userId") Long userId); + + boolean existsDateAccessByUserIdAndCourseId(Long userId, Long courseId); } diff --git a/dateroad-domain/src/main/java/org/dateroad/image/domain/Image.java b/dateroad-domain/src/main/java/org/dateroad/image/domain/Image.java index 8b306247..ae551f2a 100644 --- a/dateroad-domain/src/main/java/org/dateroad/image/domain/Image.java +++ b/dateroad-domain/src/main/java/org/dateroad/image/domain/Image.java @@ -23,6 +23,7 @@ @NoArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor(access = AccessLevel.PRIVATE) @Builder(access = AccessLevel.PRIVATE) +@Getter @Table(name = "images") public class Image extends BaseTimeEntity { @Id diff --git a/dateroad-domain/src/main/java/org/dateroad/image/repository/ImageRepository.java b/dateroad-domain/src/main/java/org/dateroad/image/repository/ImageRepository.java index cec914c1..b1be1af1 100644 --- a/dateroad-domain/src/main/java/org/dateroad/image/repository/ImageRepository.java +++ b/dateroad-domain/src/main/java/org/dateroad/image/repository/ImageRepository.java @@ -1,5 +1,6 @@ package org.dateroad.image.repository; +import java.util.List; import java.util.Optional; import org.dateroad.date.domain.Course; import org.dateroad.image.domain.Image; @@ -9,4 +10,6 @@ @Repository public interface ImageRepository extends JpaRepository { Optional findFirstByCourseOrderBySequenceAsc(Course course); + + List findAllByCourseId(Long courseId); } 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..481f3e16 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 @@ -8,5 +8,5 @@ @Repository public interface LikeRepository extends JpaRepository { - Optional countByCourse(Course course); + int countByCourse(Course course); } diff --git a/dateroad-domain/src/main/java/org/dateroad/place/repository/CoursePlaceRepository.java b/dateroad-domain/src/main/java/org/dateroad/place/repository/CoursePlaceRepository.java index 7037d6c2..cd54c147 100644 --- a/dateroad-domain/src/main/java/org/dateroad/place/repository/CoursePlaceRepository.java +++ b/dateroad-domain/src/main/java/org/dateroad/place/repository/CoursePlaceRepository.java @@ -12,4 +12,6 @@ public interface CoursePlaceRepository extends JpaRepository { @Query("SELECT SUM(p.duration) FROM CoursePlace p WHERE p.course.id = :courseId") Integer findTotalDurationByCourseId(@Param("courseId") Long courseId); + + List findAllCoursePlacesByCourseId(Long courseId); } diff --git a/dateroad-domain/src/main/java/org/dateroad/tag/domain/CourseTag.java b/dateroad-domain/src/main/java/org/dateroad/tag/domain/CourseTag.java index 2e158420..efe25352 100644 --- a/dateroad-domain/src/main/java/org/dateroad/tag/domain/CourseTag.java +++ b/dateroad-domain/src/main/java/org/dateroad/tag/domain/CourseTag.java @@ -13,14 +13,12 @@ import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; import jakarta.validation.constraints.NotNull; -import lombok.AccessLevel; -import lombok.AllArgsConstructor; -import lombok.Builder; -import lombok.NoArgsConstructor; +import lombok.*; import org.dateroad.common.BaseTimeEntity; import org.dateroad.date.domain.Course; @Entity +@Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor(access = AccessLevel.PRIVATE) @Builder(access = AccessLevel.PRIVATE) diff --git a/dateroad-domain/src/main/java/org/dateroad/tag/repository/CourseTagRepository.java b/dateroad-domain/src/main/java/org/dateroad/tag/repository/CourseTagRepository.java index f834f0ef..b286990f 100644 --- a/dateroad-domain/src/main/java/org/dateroad/tag/repository/CourseTagRepository.java +++ b/dateroad-domain/src/main/java/org/dateroad/tag/repository/CourseTagRepository.java @@ -4,6 +4,9 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; +import java.util.List; + @Repository public interface CourseTagRepository extends JpaRepository { + List findAllCourseTagByCourseId(Long courseId); } diff --git a/dateroad-external/build.gradle b/dateroad-external/build.gradle index c440be1b..8562be2c 100644 --- a/dateroad-external/build.gradle +++ b/dateroad-external/build.gradle @@ -15,11 +15,10 @@ dependencies { implementation("software.amazon.awssdk:s3:2.21.0") // apple secretKey - implementation 'org.bouncycastle:bcprov-jdk18on:1.75' + implementation 'org.bouncycastle:bcprov-jdk15on:1.70' implementation 'org.bouncycastle:bcpkix-jdk18on:1.75' implementation 'org.springframework.boot:spring-boot-starter-web' - } bootJar.enabled = false diff --git a/dateroad-external/src/main/java/org/dateroad/feign/apple/AppleClientSecretGenerator.java b/dateroad-external/src/main/java/org/dateroad/feign/apple/AppleClientSecretGenerator.java index 541de0bb..65097096 100644 --- a/dateroad-external/src/main/java/org/dateroad/feign/apple/AppleClientSecretGenerator.java +++ b/dateroad-external/src/main/java/org/dateroad/feign/apple/AppleClientSecretGenerator.java @@ -6,8 +6,6 @@ import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import org.bouncycastle.openssl.PEMParser; import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; -import org.dateroad.code.FailureCode; -import org.dateroad.exception.UnauthorizedException; import org.springframework.core.io.ClassPathResource; import org.springframework.stereotype.Component; 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 index 5852a410..553d7867 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 @@ -3,7 +3,7 @@ import lombok.Getter; public record KaKaoErrorRes( - String error, + String msg, int code ) { } From ce27fade0b5eb656a6a3cccbd2e0653127207258 Mon Sep 17 00:00:00 2001 From: Kwak Seong Joon Date: Fri, 12 Jul 2024 03:16:05 +0900 Subject: [PATCH 55/78] =?UTF-8?q?[feat]=20Controller=EC=97=90=20=EC=BD=94?= =?UTF-8?q?=EC=8A=A4=20=EC=83=81=EC=84=B8=20=EC=A1=B0=ED=9A=8C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20-=20#66?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dateroad/Image/service/ImageService.java | 2 +- .../dateroad/course/api/CourseController.java | 17 +++++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/dateroad-api/src/main/java/org/dateroad/Image/service/ImageService.java b/dateroad-api/src/main/java/org/dateroad/Image/service/ImageService.java index a8f3092b..1ebd4c26 100644 --- a/dateroad-api/src/main/java/org/dateroad/Image/service/ImageService.java +++ b/dateroad-api/src/main/java/org/dateroad/Image/service/ImageService.java @@ -22,7 +22,7 @@ public class ImageService { private final ImageRepository imageRepository; private final S3Service s3Service; - @Value("${s3.bucket.path}") + @Value("${aws-property.s3-bucket-name}") private String path; @Value("${cloudfront.domain}") private String cachePath; 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 b04144af..6e36382e 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 @@ -4,6 +4,7 @@ import java.net.URI; import java.util.List; import lombok.RequiredArgsConstructor; +import org.apache.coyote.Response; import org.dateroad.auth.argumentresolve.UserId; import org.dateroad.course.dto.request.CourseGetAllReq; import org.dateroad.course.dto.request.CourseCreateReq; @@ -15,15 +16,11 @@ import org.dateroad.course.facade.AsyncService; import org.dateroad.course.service.CourseService; import org.dateroad.date.domain.Course; +import org.dateroad.date.dto.response.CourseGetDetailRes; 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.PostMapping; -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 @@ -64,4 +61,12 @@ public ResponseEntity createCourse( HttpStatus.CREATED ).body(CourseCreateRes.of(course.getId())); } + + @GetMapping("/{courseId}") + public ResponseEntity getCourseDetail(@UserId Long userId, + @PathVariable("courseId") Long courseId) { + CourseGetDetailRes courseGetDetailRes = courseService.getCourseDetail(userId, courseId); + + return ResponseEntity.ok(courseGetDetailRes); + } } From a06720a007dcaad1bfb90de7b28c126b01020f05 Mon Sep 17 00:00:00 2001 From: Kwak Seong Joon Date: Fri, 12 Jul 2024 03:16:27 +0900 Subject: [PATCH 56/78] =?UTF-8?q?[feat]=20CourseService=20=EC=BD=94?= =?UTF-8?q?=EC=8A=A4=20=EC=83=81=EC=84=B8=20=EC=A1=B0=ED=9A=8C=20API=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20-=20#66?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../course/service/CourseService.java | 107 +++++++++++++++++- 1 file changed, 105 insertions(+), 2 deletions(-) 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 abd10e66..6200daaf 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 @@ -3,6 +3,8 @@ import java.util.List; import java.util.function.Function; import java.util.stream.Collectors; + +import io.micrometer.core.instrument.Tags; import lombok.AccessLevel; import lombok.RequiredArgsConstructor; import org.dateroad.code.FailureCode; @@ -14,11 +16,21 @@ import org.dateroad.course.dto.response.DateAccessGetAllRes; import org.dateroad.course.facade.AsyncService; import org.dateroad.date.domain.Course; +import org.dateroad.date.dto.response.CourseGetDetailRes; 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.EntityNotFoundException; import org.dateroad.image.domain.Image; +import org.dateroad.image.repository.ImageRepository; import org.dateroad.like.repository.LikeRepository; +import org.dateroad.place.domain.CoursePlace; +import org.dateroad.place.domain.Place; +import org.dateroad.place.repository.CoursePlaceRepository; +import org.dateroad.tag.domain.CourseTag; +import org.dateroad.tag.domain.DateTagType; +import org.dateroad.tag.repository.CourseTagRepository; import org.dateroad.user.domain.User; import org.dateroad.user.repository.UserRepository; import org.springframework.data.jpa.domain.Specification; @@ -35,6 +47,10 @@ public class CourseService { private final DateAccessRepository dateAccessRepository; private final UserRepository userRepository; private final AsyncService asyncService; + private final ImageRepository imageRepository; + private final CoursePlaceRepository coursePlaceRepository; + private final CourseTagRepository courseTagRepository; + public CourseGetAllRes getAllCourses(CourseGetAllReq courseGetAllReq) { Specification spec = CourseSpecifications.filterByCriteria(courseGetAllReq); @@ -51,8 +67,7 @@ private List convertToDtoList(List entities, Function foundImages = imageRepository.findAllByCourseId(foundCourse.getId()); + validateImage(foundImages); + + List images = foundImages.stream() + .map(imageList -> CourseGetDetailRes.ImagesList.of( + imageList.getImageUrl(), + imageList.getSequence()) + ).toList(); + + List foundCoursePlaces = coursePlaceRepository.findAllCoursePlacesByCourseId(courseId); + validateCoursePlace(foundCoursePlaces); + + List places = foundCoursePlaces.stream() + .map(placesList -> CourseGetDetailRes.Places.of( + placesList.getSequence(), + placesList.getName(), + placesList.getDuration()) + ).toList(); + + List foundTags = courseTagRepository.findAllCourseTagByCourseId(foundCourse.getId()); + validateCourseTag(foundTags); + + List tags = foundTags.stream() + .map(tagList -> CourseGetDetailRes.CourseTag.of( + tagList.getDateTagType()) + ).toList(); + + boolean isAccess = dateAccessRepository.existsDateAccessByUserIdAndCourseId(foundUser.getId(), foundCourse.getId()); + + int likesCount = likeRepository.countByCourse(foundCourse); + + return CourseGetDetailRes.of( + foundCourse.getId(), + images, + likesCount, + foundCourse.getTime(), + foundCourse.getDate(), + foundCourse.getCity(), + foundCourse.getTitle(), + foundCourse.getDescription(), + foundCourse.getStartAt(), + places, + foundCourse.getCost(), + tags, + isAccess, + foundUser.getFree(), + foundUser.getTotalPoint() + ); + } + + private User findUserById(final Long userId) { + return userRepository.findById(userId).orElseThrow( + () -> new EntityNotFoundException(FailureCode.USER_NOT_FOUND) + ); + } + + private Course findCourseByUserId(final Long userId) { + return courseRepository.findCourseByUserId(userId).orElseThrow( + () -> new EntityNotFoundException(FailureCode.COURSE_NOT_FOUND) + ); + } + + private void validateCoursePlace(final List coursePlaces) { + if (coursePlaces.isEmpty()) { + throw new EntityNotFoundException(FailureCode.COURSE_PLACE_NOT_FOUND); + } + } + + private void validateImage(final List images) { + if (images.isEmpty()) { + throw new EntityNotFoundException(FailureCode.IMAGE_NOT_FOUND); + } + } + + private void validateCourseTag(final List courseTags) { + if (courseTags.isEmpty()) { + throw new EntityNotFoundException(FailureCode.COURSE_TAG_NOT_FOUND); + } + } } From 922b219d6f7c1561e9b0a64a1de16715d632d573 Mon Sep 17 00:00:00 2001 From: Kwak Seong Joon Date: Fri, 12 Jul 2024 03:36:08 +0900 Subject: [PATCH 57/78] =?UTF-8?q?[chore]=20=EC=BD=94=EB=93=9C=20=EC=A0=95?= =?UTF-8?q?=EB=A6=AC=20-=20#54?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/dateroad/feign/kakao/KakaoFeignProvider.java | 8 ++++---- .../dateroad/feign/kakao/KakaoPlatformUserIdProvider.java | 4 +++- .../response/{KaKaoErrorRes.java => KakaoErrorRes.java} | 4 ++-- 3 files changed, 9 insertions(+), 7 deletions(-) rename dateroad-external/src/main/java/org/dateroad/feign/kakao/dto/response/{KaKaoErrorRes.java => KakaoErrorRes.java} (65%) 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 index 31c6dd35..6753486d 100644 --- a/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoPlatformUserIdProvider.java +++ b/dateroad-external/src/main/java/org/dateroad/feign/kakao/KakaoPlatformUserIdProvider.java @@ -6,6 +6,8 @@ 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; @@ -35,7 +37,7 @@ private KakaoAccessTokenInfoRes getKakaoAccessTokenInfo(final String token) { KakaoErrorRes errorResponse = convertToKakaoErrorResponse(e.contentUTF8()); //카카오에서 주는 에러 코드가 -1이면 카카오 내부 에러, 나머지는 카카오 액세스 토큰 에러 - if (errorResponse.getCode() == -1) { + if (errorResponse.code() == -1) { log.error("Kakao feign exception : ", e); throw new UnauthorizedException(FailureCode.KAKAO_INTERNER_ERROR); } else { 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 ) { } From 1142441a19d2cb556727012f90d277d0e3e8fcb3 Mon Sep 17 00:00:00 2001 From: gardening-y Date: Fri, 12 Jul 2024 04:03:40 +0900 Subject: [PATCH 58/78] =?UTF-8?q?[feat]=20createLike=20Controller=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20-=20#68?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/dateroad/course/api/CourseController.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) 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 4b6f6be9..24be1adc 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 @@ -17,12 +17,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.PostMapping; -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 @@ -63,4 +58,11 @@ public ResponseEntity createCourse( HttpStatus.CREATED ).body(CourseCreateRes.of(course.getId())); } + + @PostMapping("/{courseId}/likes") + public ResponseEntity createCourseLlike(@UserId final Long userId, + @PathVariable final Long courseId) { + courseService.createCourseLike(userId, courseId); + return ResponseEntity.ok().build(); + } } From c50f06575f2c4742d960ae002e4095c7b06c4c5d Mon Sep 17 00:00:00 2001 From: gardening-y Date: Fri, 12 Jul 2024 04:04:19 +0900 Subject: [PATCH 59/78] =?UTF-8?q?[feat]=20createLike=20Service=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20-=20#68?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../course/service/CourseService.java | 42 +++++++++++++++---- 1 file changed, 35 insertions(+), 7 deletions(-) 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 abd10e66..f72c9a61 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 @@ -16,8 +16,10 @@ import org.dateroad.date.domain.Course; import org.dateroad.date.repository.CourseRepository; 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.user.domain.User; import org.dateroad.user.repository.UserRepository; @@ -43,6 +45,14 @@ public CourseGetAllRes getAllCourses(CourseGetAllReq courseGetAllReq) { return CourseGetAllRes.of(courseDtoGetResList); } + @Transactional + public void createCourseLike(Long userId, Long courseId) { + User findUser = getUser(userId); + Course findCourse = getCourse(courseId); + validateCourseLike(findUser, findCourse); + saveCourseLike(findUser, findCourse); + } + private List convertToDtoList(List entities, Function converter) { return entities.stream() .map(converter) @@ -73,16 +83,34 @@ public DateAccessGetAllRes getAllDataAccessCourse(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(), @@ -96,8 +124,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; } } From 1765af4cc9a510adc800252941a72e43f2b9d8df Mon Sep 17 00:00:00 2001 From: gardening-y Date: Fri, 12 Jul 2024 04:05:47 +0900 Subject: [PATCH 60/78] =?UTF-8?q?[refactor]=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?UTF-8?q?=20=EB=AA=85=20=EB=B3=80=EA=B2=BD=20-=20#68?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/dateroad/date/service/DateService.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) 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 84d5d04c..eb4c597a 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 @@ -37,9 +37,9 @@ 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) { @@ -75,19 +75,19 @@ private User getUser(final Long userId) { .orElseThrow(() -> new EntityNotFoundException(FailureCode.USER_NOT_FOUND)); } - private Date createDate(final User findUser, final 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(final Date date, final 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(final Date date, final 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); From 69e6cda96194db6baae47b9745a43497edf0137e Mon Sep 17 00:00:00 2001 From: Kwak Seong Joon Date: Fri, 12 Jul 2024 04:06:36 +0900 Subject: [PATCH 61/78] =?UTF-8?q?[chore]=20final=20=EB=B6=99=EC=9D=B4?= =?UTF-8?q?=EA=B8=B0=20-=20#57?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/dateroad/user/service/UserService.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 index 46dd79e0..3af924dc 100644 --- a/dateroad-api/src/main/java/org/dateroad/user/service/UserService.java +++ b/dateroad-api/src/main/java/org/dateroad/user/service/UserService.java @@ -20,9 +20,8 @@ public UserInfoMainRes getUserInfoMain(final Long userId) { return UserInfoMainRes.of(foundUser.getName(), foundUser.getTotalPoint(), foundUser.getImageUrl()); } - private User findUserById(Long userId) { + private User findUserById(final Long userId) { return userRepository.findById(userId) .orElseThrow(() -> new EntityNotFoundException(FailureCode.USER_NOT_FOUND)); } - } From 8e7f051925cddb9ee6745d6f707b3080302f89dd Mon Sep 17 00:00:00 2001 From: gardening-y Date: Fri, 12 Jul 2024 04:14:43 +0900 Subject: [PATCH 62/78] =?UTF-8?q?[feat]=20createLike=20=EC=98=88=EC=99=B8?= =?UTF-8?q?=20=EC=B2=98=EB=A6=AC=20=EA=B5=AC=ED=98=84=20-=20#68?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/dateroad/code/FailureCode.java | 2 ++ 1 file changed, 2 insertions(+) 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 bc642b88..1762714b 100644 --- a/dateroad-common/src/main/java/org/dateroad/code/FailureCode.java +++ b/dateroad-common/src/main/java/org/dateroad/code/FailureCode.java @@ -56,6 +56,7 @@ 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", "데이트 코스를 찾을 수 없습니다."), /** * 405 Method Not Allowed @@ -68,6 +69,7 @@ public enum FailureCode { CONFLICT(HttpStatus.CONFLICT, "e4090", "이미 존재하는 리소스입니다."), DUPLICATE_USER(HttpStatus.CONFLICT, "e4091", "이미 존재하는 유저입니다."), DUPLICATE_NICKNAME(HttpStatus.CONFLICT, "e4092", "이미 존재하는 닉네임입니다."), + DUPLICATE_COURSE_LIKE(HttpStatus.CONFLICT, "e4093", "해당 데이트 코스에 좋아요가 이미 존재합니다."), /** From b2918393fbd461063e8f27fa1719b661399d4eb8 Mon Sep 17 00:00:00 2001 From: gardening-y Date: Fri, 12 Jul 2024 04:15:01 +0900 Subject: [PATCH 63/78] =?UTF-8?q?[feat]=20createLike=20Repository=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20-=20#68?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/dateroad/like/repository/LikeRepository.java | 2 ++ 1 file changed, 2 insertions(+) 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); } From 2533f8ebb7f5371f88f81b08f2c74ee497a59b5e Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Fri, 12 Jul 2024 04:30:17 +0900 Subject: [PATCH 64/78] =?UTF-8?q?[setting]=20docker-compose=20=EB=B0=8F=20?= =?UTF-8?q?deploy.sh=20=EB=B0=B0=ED=8F=AC=20+=20CI/CD=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docker-compose.yml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 docker-compose.yml diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 00000000..34b671b2 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,28 @@ +services: + redis: + container_name: redis + image: redis:alpine + ports: + - "6379:6379" + blue: + container_name: blue + image: dateroad/dateroad-server + expose: + - 8080 + ports: + - "8081:8080" + environment: + - TZ=Asia/Seoul + depends_on: + - redis + green: + container_name: green + image: dateroad/dateroad-server + expose: + - 8080 + ports: + - "8082:8080" + environment: + - TZ=Asia/Seoul + depends_on: + - redis \ No newline at end of file From 6bcd96225dfebecfd04345ae7821f107a22eb36f Mon Sep 17 00:00:00 2001 From: Kwak Seong Joon Date: Fri, 12 Jul 2024 04:45:30 +0900 Subject: [PATCH 65/78] =?UTF-8?q?[fix]=20=EA=B0=99=EC=9D=80=20=EC=96=B4?= =?UTF-8?q?=EB=85=B8=ED=85=8C=EC=9D=B4=EC=85=98=20=EC=82=AD=EC=A0=9C=20-?= =?UTF-8?q?=20#58?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dateroad-domain/src/main/java/org/dateroad/date/domain/Date.java | 1 - 1 file changed, 1 deletion(-) diff --git a/dateroad-domain/src/main/java/org/dateroad/date/domain/Date.java b/dateroad-domain/src/main/java/org/dateroad/date/domain/Date.java index 5fd26215..42360067 100644 --- a/dateroad-domain/src/main/java/org/dateroad/date/domain/Date.java +++ b/dateroad-domain/src/main/java/org/dateroad/date/domain/Date.java @@ -20,7 +20,6 @@ @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @AllArgsConstructor(access = AccessLevel.PRIVATE) -@Getter @Table(name = "dates") public class Date extends DateBase { @Id From 36c23ba31a56d59412efe0fecc086dead763c05c Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Fri, 12 Jul 2024 05:14:06 +0900 Subject: [PATCH 66/78] =?UTF-8?q?[refactor]=20=EB=A9=94=EC=86=8C=EB=93=9C?= =?UTF-8?q?=20=EB=B6=84=EB=A6=AC=20-=20#65?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../course/service/CourseService.java | 28 ++++++++++++------- .../point/event/FreeEventListener.java | 10 +++++-- .../point/event/pointEventListener.java | 10 +++++-- 3 files changed, 32 insertions(+), 16 deletions(-) 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 70d7a8d4..74dbb154 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 @@ -41,21 +41,21 @@ public class CourseService { private final AsyncService asyncService; private final PointRepository pointRepository; - public CourseGetAllRes getAllCourses(CourseGetAllReq courseGetAllReq) { + public CourseGetAllRes getAllCourses(final CourseGetAllReq courseGetAllReq) { Specification spec = CourseSpecifications.filterByCriteria(courseGetAllReq); List courses = courseRepository.findAll(spec); List courseDtoGetResList = convertToDtoList(courses, Function.identity()); return CourseGetAllRes.of(courseDtoGetResList); } - private List convertToDtoList(List entities, Function converter) { + private List convertToDtoList(final List entities, final Function converter) { return entities.stream() .map(converter) .map(this::convertToDto) .collect(Collectors.toList()); } - private CourseDtoGetRes convertToDto(Course course) { + private CourseDtoGetRes convertToDto(final Course course) { int likeCount = likeRepository.countByCourse(course) .orElse(0); Image thumbnailImage = asyncService.findFirstByCourseOrderBySequenceAsc(course); @@ -108,18 +108,26 @@ public Course createCourse(final Long userId, final CourseCreateReq courseRegist @Transactional public void openCourse(final Long userId, final Long courseId, final PointUseReq pointUseReq) { - User user = userRepository.findById(userId).orElseThrow( - () -> new DateRoadException(FailureCode.USER_NOT_FOUND) - ); - Course course = courseRepository.findById(courseId).orElseThrow( - () -> new DateRoadException(FailureCode.COURSE_NOT_FOUND) - ); + User user = getUser(userId); + Course course = getCourse(courseId); Point point = Point.create(user, pointUseReq.point(), pointUseReq.type(), pointUseReq.description()); CoursePaymentType coursePaymentType = validateUserFreeOrPoint(user, pointUseReq.point()); processCoursePayment(coursePaymentType, user, point, pointUseReq); dateAccessRepository.save(DateAccess.create(course, user)); } + private Course getCourse(final Long courseId) { + return courseRepository.findById(courseId).orElseThrow( + () -> new DateRoadException(FailureCode.COURSE_NOT_FOUND) + ); + } + + private User getUser(final Long userId) { + return userRepository.findById(userId).orElseThrow( + () -> new DateRoadException(FailureCode.USER_NOT_FOUND) + ); + } + private CoursePaymentType validateUserFreeOrPoint(final User user, final int requiredPoints) { if (user.getFree() > 0) { return CoursePaymentType.FREE; // User가 free를 갖고 있으면 true를 반환 @@ -129,7 +137,7 @@ private CoursePaymentType validateUserFreeOrPoint(final User user, final int req return CoursePaymentType.POINT; } - public void processCoursePayment(final CoursePaymentType coursePaymentType, User user, final Point point, + public void processCoursePayment(final CoursePaymentType coursePaymentType, final User user, final Point point, final PointUseReq pointUseReq) { switch (coursePaymentType) { case FREE -> { diff --git a/dateroad-api/src/main/java/org/dateroad/point/event/FreeEventListener.java b/dateroad-api/src/main/java/org/dateroad/point/event/FreeEventListener.java index c4f7ae2a..8966766a 100644 --- a/dateroad-api/src/main/java/org/dateroad/point/event/FreeEventListener.java +++ b/dateroad-api/src/main/java/org/dateroad/point/event/FreeEventListener.java @@ -22,11 +22,15 @@ public class FreeEventListener implements StreamListener message) { Map map = message.getValue(); Long userId = Long.valueOf(map.get("userId")); - User user = userRepository.findById(userId).orElseThrow( - () -> new DateRoadException(FailureCode.USER_NOT_FOUND) - ); + User user = getUser(userId); int userPoint = user.getFree(); user.setFree(userPoint -1); userRepository.save(user); } + + private User getUser(Long userId) { + return userRepository.findById(userId).orElseThrow( + () -> new DateRoadException(FailureCode.USER_NOT_FOUND) + ); + } } diff --git a/dateroad-api/src/main/java/org/dateroad/point/event/pointEventListener.java b/dateroad-api/src/main/java/org/dateroad/point/event/pointEventListener.java index 30997df9..ddff2aff 100644 --- a/dateroad-api/src/main/java/org/dateroad/point/event/pointEventListener.java +++ b/dateroad-api/src/main/java/org/dateroad/point/event/pointEventListener.java @@ -22,11 +22,15 @@ public class pointEventListener implements StreamListener message) { Map map = message.getValue(); Long userId = Long.valueOf(map.get("userId")); - User user = userRepository.findById(userId).orElseThrow( - () -> new DateRoadException(FailureCode.USER_NOT_FOUND) - ); + User user = getUser(userId); int point = Integer.parseInt(map.get("point")); // 감소시킬 포인트 user.setTotalPoint(user.getTotalPoint() - point); userRepository.save(user); } + + private User getUser(Long userId) { + return userRepository.findById(userId).orElseThrow( + () -> new DateRoadException(FailureCode.USER_NOT_FOUND) + ); + } } From bee040c322f4f82c0ec971fd019c5b8b3407adf7 Mon Sep 17 00:00:00 2001 From: Kwak Seong Joon Date: Fri, 12 Jul 2024 05:21:16 +0900 Subject: [PATCH 67/78] =?UTF-8?q?[feat]=20=EC=9C=A0=EC=A0=80=EA=B0=80=20?= =?UTF-8?q?=EB=A7=8C=EB=93=A0=20=EC=BD=94=EC=8A=A4=EC=9D=B8=EC=A7=80=20?= =?UTF-8?q?=ED=99=95=EC=9D=B8=20=EA=B5=AC=ED=98=84=20-=20#66?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../main/java/org/dateroad/course/api/CourseController.java | 2 -- .../java/org/dateroad/date/repository/CourseRepository.java | 3 ++- 2 files changed, 2 insertions(+), 3 deletions(-) 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 6e36382e..a74610c7 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,10 +1,8 @@ package org.dateroad.course.api; -import java.net.URI; import java.util.List; import lombok.RequiredArgsConstructor; -import org.apache.coyote.Response; import org.dateroad.auth.argumentresolve.UserId; import org.dateroad.course.dto.request.CourseGetAllReq; import org.dateroad.course.dto.request.CourseCreateReq; diff --git a/dateroad-domain/src/main/java/org/dateroad/date/repository/CourseRepository.java b/dateroad-domain/src/main/java/org/dateroad/date/repository/CourseRepository.java index 5fd92091..97a00821 100644 --- a/dateroad-domain/src/main/java/org/dateroad/date/repository/CourseRepository.java +++ b/dateroad-domain/src/main/java/org/dateroad/date/repository/CourseRepository.java @@ -12,6 +12,7 @@ // CourseRepository.java @Repository public interface CourseRepository extends JpaRepository , JpaSpecificationExecutor { - Optional findCourseByUserId(Long userId); + boolean existsByUserId(Long userId); + } From 6af843dd109bba4d46db9eb5249660173b38b49d Mon Sep 17 00:00:00 2001 From: Kwak Seong Joon Date: Fri, 12 Jul 2024 05:21:54 +0900 Subject: [PATCH 68/78] =?UTF-8?q?[feat]=20=ED=95=84=EB=93=9C=20=EB=91=90?= =?UTF-8?q?=EA=B0=9C=20=EC=B6=94=EA=B0=80=20=EB=B0=98=EC=98=81=20=EB=A1=9C?= =?UTF-8?q?=EC=A7=81=20=EB=B3=80=EA=B2=BD=20-=20#66?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../course/service/CourseService.java | 27 ++++++++++++++----- .../date/dto/response/CourseGetDetailRes.java | 10 +++++-- .../like/repository/LikeRepository.java | 1 + 3 files changed, 29 insertions(+), 9 deletions(-) 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 6200daaf..2a07636b 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,6 +18,7 @@ import org.dateroad.date.domain.Course; import org.dateroad.date.dto.response.CourseGetDetailRes; import org.dateroad.date.repository.CourseRepository; +import org.dateroad.date.service.DateRepository; import org.dateroad.dateAccess.domain.DateAccess; import org.dateroad.dateAccess.repository.DateAccessRepository; import org.dateroad.exception.DateRoadException; @@ -50,6 +51,7 @@ public class CourseService { private final ImageRepository imageRepository; private final CoursePlaceRepository coursePlaceRepository; private final CourseTagRepository courseTagRepository; + private final DateRepository dateRepository; public CourseGetAllRes getAllCourses(CourseGetAllReq courseGetAllReq) { @@ -117,11 +119,12 @@ public Course createCourse(final Long userId, final CourseCreateReq courseRegist } public CourseGetDetailRes getCourseDetail(final Long userId, final Long courseId) { - //user - userId, free, totalPoint, - User foundUser = findUserById(userId); //course - courseId, title, date, start_at, description, totalCost, city, totalTime - Course foundCourse = findCourseByUserId(foundUser.getId()); + Course foundCourse = findCourseById(courseId); + + //user - userId, free, totalPoint, + User foundUser = findUserById(userId); //나머지 - images, places, tags, isAccess, likes List foundImages = imageRepository.findAllByCourseId(foundCourse.getId()); @@ -133,7 +136,7 @@ public CourseGetDetailRes getCourseDetail(final Long userId, final Long courseId imageList.getSequence()) ).toList(); - List foundCoursePlaces = coursePlaceRepository.findAllCoursePlacesByCourseId(courseId); + List foundCoursePlaces = coursePlaceRepository.findAllCoursePlacesByCourseId(foundCourse.getId()); validateCoursePlace(foundCoursePlaces); List places = foundCoursePlaces.stream() @@ -155,6 +158,14 @@ public CourseGetDetailRes getCourseDetail(final Long userId, final Long courseId int likesCount = likeRepository.countByCourse(foundCourse); + boolean isCourseMine = courseRepository.existsByUserId(foundUser.getId()); + + boolean isUserLiked = likeRepository.existsByUserIdAndCourseId(foundUser.getId(), foundCourse.getId()); + + if (isCourseMine) { + isUserLiked = false; + } + return CourseGetDetailRes.of( foundCourse.getId(), images, @@ -170,7 +181,9 @@ public CourseGetDetailRes getCourseDetail(final Long userId, final Long courseId tags, isAccess, foundUser.getFree(), - foundUser.getTotalPoint() + foundUser.getTotalPoint(), + isCourseMine, + isUserLiked ); } @@ -180,8 +193,8 @@ private User findUserById(final Long userId) { ); } - private Course findCourseByUserId(final Long userId) { - return courseRepository.findCourseByUserId(userId).orElseThrow( + private Course findCourseById(final Long courseId) { + return courseRepository.findById(courseId).orElseThrow( () -> new EntityNotFoundException(FailureCode.COURSE_NOT_FOUND) ); } diff --git a/dateroad-api/src/main/java/org/dateroad/date/dto/response/CourseGetDetailRes.java b/dateroad-api/src/main/java/org/dateroad/date/dto/response/CourseGetDetailRes.java index 3d617ec9..4e35479d 100644 --- a/dateroad-api/src/main/java/org/dateroad/date/dto/response/CourseGetDetailRes.java +++ b/dateroad-api/src/main/java/org/dateroad/date/dto/response/CourseGetDetailRes.java @@ -27,7 +27,9 @@ public record CourseGetDetailRes( List tags, boolean isAccess, int free, - int totalPoint + int totalPoint, + boolean isCourseMine, + boolean isUserLiked ) { public static CourseGetDetailRes of(Long courseId, @@ -44,7 +46,9 @@ public static CourseGetDetailRes of(Long courseId, List tags, boolean isAccess, int free, - int totalPoint) { + int totalPoint, + boolean isCourseMine, + boolean isUserLiked) { return CourseGetDetailRes.builder() .courseId(courseId) .images(images) @@ -61,6 +65,8 @@ public static CourseGetDetailRes of(Long courseId, .isAccess(isAccess) .free(free) .totalPoint(totalPoint) + .isCourseMine(isCourseMine) + .isUserLiked(isUserLiked) .build(); } 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 481f3e16..19b6ccf9 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 @@ -9,4 +9,5 @@ @Repository public interface LikeRepository extends JpaRepository { int countByCourse(Course course); + boolean existsByUserIdAndCourseId(Long userId, Long courseId); } From 9863722ddc79c0a49a53873bb2010fdeef7149ba Mon Sep 17 00:00:00 2001 From: Kwak Seong Joon Date: Fri, 12 Jul 2024 06:41:56 +0900 Subject: [PATCH 69/78] =?UTF-8?q?[fix]=20=EB=B9=88=20=EC=A3=BC=EC=9E=85=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20-=20#66?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/dateroad/auth/filter/JwtAuthenticationFilter.java | 1 - 1 file changed, 1 deletion(-) 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 a9eadb48..bbb3cf65 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 @@ -22,7 +22,6 @@ @RequiredArgsConstructor -@Component public class JwtAuthenticationFilter extends OncePerRequestFilter { private final JwtProvider jwtProvider; From 34effafd80f96c5b589a92879d71b41277ed2f60 Mon Sep 17 00:00:00 2001 From: gardening-y Date: Fri, 12 Jul 2024 06:47:15 +0900 Subject: [PATCH 70/78] =?UTF-8?q?[fix]=20=EB=A6=AC=EC=86=8C=EC=8A=A4=20?= =?UTF-8?q?=EA=B6=8C=ED=95=9C=20=EC=97=90=EB=9F=AC=20=EC=88=98=EC=A0=95=20?= =?UTF-8?q?-=20#68?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/dateroad/auth/filter/JwtAuthenticationFilter.java | 3 --- 1 file changed, 3 deletions(-) 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 a9eadb48..6d4de96a 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,10 +9,8 @@ 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; @@ -22,7 +20,6 @@ @RequiredArgsConstructor -@Component public class JwtAuthenticationFilter extends OncePerRequestFilter { private final JwtProvider jwtProvider; From aa1786b45a100662a4a6f754ed89f8fc0f5f8696 Mon Sep 17 00:00:00 2001 From: gardening-y Date: Fri, 12 Jul 2024 06:48:10 +0900 Subject: [PATCH 71/78] =?UTF-8?q?[feat]=20deleteLike=20Controller=20?= =?UTF-8?q?=EA=B5=AC=ED=98=84=20-=20#69?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/dateroad/course/api/CourseController.java | 7 +++++++ 1 file changed, 7 insertions(+) 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 24be1adc..40971014 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 @@ -65,4 +65,11 @@ public ResponseEntity createCourseLlike(@UserId final Long userId, courseService.createCourseLike(userId, courseId); return ResponseEntity.ok().build(); } + + @DeleteMapping("/{courseId}/likes") + public ResponseEntity deleteCourseLike(@RequestHeader final Long userId, + @PathVariable final Long courseId) { + courseService.deleteCourseLike(userId, courseId); + return ResponseEntity.ok().build(); + } } From d19801b9e0316c764f9a7d9d665aca97c1e40a5c Mon Sep 17 00:00:00 2001 From: gardening-y Date: Fri, 12 Jul 2024 06:48:56 +0900 Subject: [PATCH 72/78] =?UTF-8?q?[fix]=20=EB=A9=94=EC=84=9C=EB=93=9C?= =?UTF-8?q?=EB=AA=85=20=EB=B3=80=EA=B2=BD=20-=20#69?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/dateroad/course/api/CourseController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 40971014..edd636a5 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 @@ -60,7 +60,7 @@ public ResponseEntity createCourse( } @PostMapping("/{courseId}/likes") - public ResponseEntity createCourseLlike(@UserId final Long userId, + public ResponseEntity createCourseLike(@UserId final Long userId, @PathVariable final Long courseId) { courseService.createCourseLike(userId, courseId); return ResponseEntity.ok().build(); From 5897760f0cd6510fe8e1dee86b45e2cf45ffef18 Mon Sep 17 00:00:00 2001 From: gardening-y Date: Fri, 12 Jul 2024 06:49:38 +0900 Subject: [PATCH 73/78] =?UTF-8?q?[feat]=20deleteLike=20Service=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20-=20#69?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/dateroad/course/service/CourseService.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) 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 f72c9a61..5ccd77af 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 @@ -53,6 +53,14 @@ public void createCourseLike(Long userId, Long courseId) { saveCourseLike(findUser, findCourse); } + @Transactional + public void deleteCourseLike(Long userId, Long courseId) { + User findUser = getUser(userId); + Course findCourse = getCourse(courseId); + Like findLike = getLike(findUser, findCourse); + likeRepository.delete(findLike); + } + private List convertToDtoList(List entities, Function converter) { return entities.stream() .map(converter) @@ -104,6 +112,11 @@ private void saveCourseLike(User user, Course course) { likeRepository.save(like); } + private Like getLike(User findUser, Course findCourse) { + return likeRepository.findByUserAndCourse(findUser, findCourse) + .orElseThrow(() -> new EntityNotFoundException(FailureCode.LIKE_NOT_FOUND)); + } + @Transactional public Course createCourse(final Long userId, final CourseCreateReq courseRegisterReq, final List places, final List images) { From 9f0572495c5dd432f519fcfaadc06ec0d6f03f1b Mon Sep 17 00:00:00 2001 From: gardening-y Date: Fri, 12 Jul 2024 06:49:58 +0900 Subject: [PATCH 74/78] =?UTF-8?q?[feat]=20deleteLike=20=EC=98=88=EC=99=B8?= =?UTF-8?q?=20=EC=B2=98=EB=A6=AC=20=EA=B5=AC=ED=98=84=20-=20#69?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dateroad-common/src/main/java/org/dateroad/code/FailureCode.java | 1 + 1 file changed, 1 insertion(+) 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 7088c087..7d8b677c 100644 --- a/dateroad-common/src/main/java/org/dateroad/code/FailureCode.java +++ b/dateroad-common/src/main/java/org/dateroad/code/FailureCode.java @@ -58,6 +58,7 @@ public enum FailureCode { DATE_PLACE_NOT_FOUND(HttpStatus.NOT_FOUND, "e4046", "데이트 장소를 찾을 수 없습니다."), COURSE_NOT_FOUND(HttpStatus.NOT_FOUND, "e4047", "데이트 코스를 찾을 수 없습니다."), NEAREST_DATE_NOT_FOUND(HttpStatus.NOT_FOUND, "e4048", "다가오는 데이트를 찾을 수 없습니다."), + LIKE_NOT_FOUND(HttpStatus.NOT_FOUND, "e4048", "해당 데이트 코스에 좋아요를 찾을 수 없습니다."), /** * 405 Method Not Allowed From 34173e7763f26b0d927235be007ab7e356d6a000 Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Fri, 12 Jul 2024 08:09:52 +0900 Subject: [PATCH 75/78] =?UTF-8?q?[feat]=20=EA=B4=91=EA=B3=A0=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=EC=A1=B0=ED=9A=8C=20=EA=B5=AC=ED=98=84=20-=20#71?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/AdvertismentController.java | 12 +++++++ .../service/AdvertismentService.java | 33 +++++++++++++++++++ .../adImage/repository/AdImageRepository.java | 1 + 3 files changed, 46 insertions(+) diff --git a/dateroad-api/src/main/java/org/dateroad/advertisment/api/AdvertismentController.java b/dateroad-api/src/main/java/org/dateroad/advertisment/api/AdvertismentController.java index 6f0cf247..9804ac0c 100644 --- a/dateroad-api/src/main/java/org/dateroad/advertisment/api/AdvertismentController.java +++ b/dateroad-api/src/main/java/org/dateroad/advertisment/api/AdvertismentController.java @@ -2,10 +2,13 @@ import lombok.RequiredArgsConstructor; import org.dateroad.advertisment.dto.response.AdvGetAllRes; +import org.dateroad.advertisment.dto.response.AdvGetDetailRes; import org.dateroad.advertisment.service.AdvertismentService; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -21,4 +24,13 @@ public ResponseEntity getAllAdvertisments(){ .status(HttpStatus.OK) .body(advertismentService.getAllAdvertisments()); } + + @GetMapping("{advId}") + public ResponseEntity getAllAdvertisments( + final @PathVariable Long advId + ){ + return ResponseEntity + .status(HttpStatus.OK) + .body(advertismentService.getAdvertismentsDetail(advId)); + } } diff --git a/dateroad-api/src/main/java/org/dateroad/advertisment/service/AdvertismentService.java b/dateroad-api/src/main/java/org/dateroad/advertisment/service/AdvertismentService.java index 2e38968f..9090d60e 100644 --- a/dateroad-api/src/main/java/org/dateroad/advertisment/service/AdvertismentService.java +++ b/dateroad-api/src/main/java/org/dateroad/advertisment/service/AdvertismentService.java @@ -1,18 +1,31 @@ package org.dateroad.advertisment.service; +import java.util.List; +import java.util.Optional; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; +import org.dateroad.adImage.domain.AdImage; +import org.dateroad.adImage.repository.AdImageRepository; +import org.dateroad.advertisement.domain.Advertisment; import org.dateroad.advertisement.repository.AdvertismentRepository; import org.dateroad.advertisment.dto.response.AdvGetAllRes; import org.dateroad.advertisment.dto.response.AdvGetAllRes.AdvertismentDtoRes; +import org.dateroad.advertisment.dto.response.AdvGetDetailRes; +import org.dateroad.advertisment.dto.response.AdvGetDetailRes.AdvImagesRes; +import org.dateroad.code.FailureCode; +import org.dateroad.exception.EntityNotFoundException; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; @Service @RequiredArgsConstructor +@Transactional(readOnly = true) public class AdvertismentService { private final AdvertismentRepository advertismentRepository; + private final AdImageRepository adImageRepository; + public AdvGetAllRes getAllAdvertisments() { Pageable topFive = PageRequest.of(0, 5); return AdvGetAllRes.of(advertismentRepository.findTop5ByOrderByCreatedDateDesc(topFive). @@ -20,4 +33,24 @@ public AdvGetAllRes getAllAdvertisments() { .map(AdvertismentDtoRes::of) .collect(Collectors.toList())); } + + public AdvGetDetailRes getAdvertismentsDetail(final Long advId) { + Advertisment advertisment = getAdvertisment(advId); + List adImages = adImageRepository.findAllById(advId); + return AdvGetDetailRes.of( + getImages(adImages), advertisment.getTitle(), advertisment.getCreatedAt().toLocalDate(), advertisment.getTitle() + ); + } + + private static List getImages(List adImages) { + return adImages.stream().map( + adImage -> AdvImagesRes.of(adImage.getImageUrl(), adImage.getSequence()) + ).toList(); + } + + private Advertisment getAdvertisment(Long advId) { + return advertismentRepository.findById(advId).orElseThrow( + () -> new EntityNotFoundException(FailureCode.ADVERTISMENT_NOT_FOUND) + ); + } } diff --git a/dateroad-domain/src/main/java/org/dateroad/adImage/repository/AdImageRepository.java b/dateroad-domain/src/main/java/org/dateroad/adImage/repository/AdImageRepository.java index 85eb284a..1e4b3a11 100644 --- a/dateroad-domain/src/main/java/org/dateroad/adImage/repository/AdImageRepository.java +++ b/dateroad-domain/src/main/java/org/dateroad/adImage/repository/AdImageRepository.java @@ -8,4 +8,5 @@ @Repository public interface AdImageRepository extends JpaRepository { + List findAllById(Long advertismentId); } From de93737086f6c809bd2e37bedc3d191228339d3a Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Fri, 12 Jul 2024 08:10:09 +0900 Subject: [PATCH 76/78] =?UTF-8?q?[feat]=20=EA=B4=91=EA=B3=A0=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EA=B4=80=EB=A0=A8=20DTO=20=EA=B5=AC=ED=98=84=20-?= =?UTF-8?q?=20#71?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dto/response/AdvGetDetailRes.java | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 dateroad-api/src/main/java/org/dateroad/advertisment/dto/response/AdvGetDetailRes.java diff --git a/dateroad-api/src/main/java/org/dateroad/advertisment/dto/response/AdvGetDetailRes.java b/dateroad-api/src/main/java/org/dateroad/advertisment/dto/response/AdvGetDetailRes.java new file mode 100644 index 00000000..600f9e7a --- /dev/null +++ b/dateroad-api/src/main/java/org/dateroad/advertisment/dto/response/AdvGetDetailRes.java @@ -0,0 +1,40 @@ +package org.dateroad.advertisment.dto.response; + +import com.fasterxml.jackson.annotation.JsonFormat; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.List; +import lombok.AccessLevel; +import lombok.Builder; + +@Builder(access = AccessLevel.PROTECTED) +public record AdvGetDetailRes( + List images, + String title, + @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy.MM.dd", timezone = "Asia/Seoul") + + LocalDate createAt, + String description +) { + public static AdvGetDetailRes of(List images, String title, LocalDate createAt, String description) { + return AdvGetDetailRes.builder() + .images(images) + .title(title) + .createAt(createAt) + .description(description) + .build(); + } + + @Builder + public record AdvImagesRes( + String imagesUrl, + int sequence + ) { + public static AdvImagesRes of(String imagesUrl, int sequence) { + return AdvImagesRes.builder() + .imagesUrl(imagesUrl) + .sequence(sequence) + .build(); + } + } +} From d7ceea5a2e6f84cac2bf2576e4645d184dcfcae6 Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Fri, 12 Jul 2024 08:10:34 +0900 Subject: [PATCH 77/78] =?UTF-8?q?[feat]=20=EA=B4=91=EA=B3=A0=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC=EC=B2=98=EB=A6=AC=20=EA=B5=AC=ED=98=84=20-=20#71?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/org/dateroad/code/FailureCode.java | 2 ++ 1 file changed, 2 insertions(+) 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 d3fe54ea..58c30f53 100644 --- a/dateroad-common/src/main/java/org/dateroad/code/FailureCode.java +++ b/dateroad-common/src/main/java/org/dateroad/code/FailureCode.java @@ -62,6 +62,7 @@ public enum FailureCode { COURSE_TAG_NOT_FOUND(HttpStatus.NOT_FOUND, "e40410", "데이트 태그를 찾을 수 없습니다."), NEAREST_DATE_NOT_FOUND(HttpStatus.NOT_FOUND, "e40411", "다가오는 데이트를 찾을 수 없습니다."), LIKE_NOT_FOUND(HttpStatus.NOT_FOUND, "e40412", "해당 데이트 코스에 좋아요를 찾을 수 없습니다."), + ADVERTISMENT_NOT_FOUND(HttpStatus.NOT_FOUND, "e40413", "해당 광고를 찾을 수 없습니다."), INSUFFICIENT_USER_POINTS(HttpStatus.NOT_FOUND, "e4048", "유저의 포인트가 부족합니다."), /** @@ -78,6 +79,7 @@ public enum FailureCode { DUPLICATE_COURSE_LIKE(HttpStatus.CONFLICT, "e4093", "해당 데이트 코스에 좋아요가 이미 존재합니다."), INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "e5000", "서버 내부 오류입니다."); + /** * 500 Internal Server Error */ From 10a539bb011eb48f83617ca1a6f6827856a99204 Mon Sep 17 00:00:00 2001 From: rlarlgnszx Date: Fri, 12 Jul 2024 08:21:03 +0900 Subject: [PATCH 78/78] =?UTF-8?q?[refactor]=20=EC=BB=A8=EB=B2=A4=EC=85=98?= =?UTF-8?q?=20=EB=A7=9E=EC=B6=B0=20=EC=88=98=EC=A0=95=20-=20#71?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../api/AdvertismentController.java | 8 ++------ .../dto/response/AdvGetDetailRes.java | 3 +-- .../service/AdvertismentService.java | 17 +++++++++-------- 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/dateroad-api/src/main/java/org/dateroad/advertisment/api/AdvertismentController.java b/dateroad-api/src/main/java/org/dateroad/advertisment/api/AdvertismentController.java index 9804ac0c..1cd47c94 100644 --- a/dateroad-api/src/main/java/org/dateroad/advertisment/api/AdvertismentController.java +++ b/dateroad-api/src/main/java/org/dateroad/advertisment/api/AdvertismentController.java @@ -20,17 +20,13 @@ public class AdvertismentController { @GetMapping public ResponseEntity getAllAdvertisments(){ - return ResponseEntity - .status(HttpStatus.OK) - .body(advertismentService.getAllAdvertisments()); + return ResponseEntity.ok(advertismentService.getAllAdvertisments()); } @GetMapping("{advId}") public ResponseEntity getAllAdvertisments( final @PathVariable Long advId ){ - return ResponseEntity - .status(HttpStatus.OK) - .body(advertismentService.getAdvertismentsDetail(advId)); + return ResponseEntity.ok(advertismentService.getAdvertismentsDetail(advId)); } } diff --git a/dateroad-api/src/main/java/org/dateroad/advertisment/dto/response/AdvGetDetailRes.java b/dateroad-api/src/main/java/org/dateroad/advertisment/dto/response/AdvGetDetailRes.java index 600f9e7a..c86bf000 100644 --- a/dateroad-api/src/main/java/org/dateroad/advertisment/dto/response/AdvGetDetailRes.java +++ b/dateroad-api/src/main/java/org/dateroad/advertisment/dto/response/AdvGetDetailRes.java @@ -12,7 +12,6 @@ public record AdvGetDetailRes( List images, String title, @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy.MM.dd", timezone = "Asia/Seoul") - LocalDate createAt, String description ) { @@ -25,7 +24,7 @@ public static AdvGetDetailRes of(List images, String title, LocalD .build(); } - @Builder + @Builder(access = AccessLevel.PROTECTED) public record AdvImagesRes( String imagesUrl, int sequence diff --git a/dateroad-api/src/main/java/org/dateroad/advertisment/service/AdvertismentService.java b/dateroad-api/src/main/java/org/dateroad/advertisment/service/AdvertismentService.java index 9090d60e..b32f6476 100644 --- a/dateroad-api/src/main/java/org/dateroad/advertisment/service/AdvertismentService.java +++ b/dateroad-api/src/main/java/org/dateroad/advertisment/service/AdvertismentService.java @@ -26,6 +26,12 @@ public class AdvertismentService { private final AdvertismentRepository advertismentRepository; private final AdImageRepository adImageRepository; + private static List getImages(final List adImages) { + return adImages.stream().map( + adImage -> AdvImagesRes.of(adImage.getImageUrl(), adImage.getSequence()) + ).toList(); + } + public AdvGetAllRes getAllAdvertisments() { Pageable topFive = PageRequest.of(0, 5); return AdvGetAllRes.of(advertismentRepository.findTop5ByOrderByCreatedDateDesc(topFive). @@ -38,17 +44,12 @@ public AdvGetDetailRes getAdvertismentsDetail(final Long advId) { Advertisment advertisment = getAdvertisment(advId); List adImages = adImageRepository.findAllById(advId); return AdvGetDetailRes.of( - getImages(adImages), advertisment.getTitle(), advertisment.getCreatedAt().toLocalDate(), advertisment.getTitle() + getImages(adImages), advertisment.getTitle(), advertisment.getCreatedAt().toLocalDate(), + advertisment.getTitle() ); } - private static List getImages(List adImages) { - return adImages.stream().map( - adImage -> AdvImagesRes.of(adImage.getImageUrl(), adImage.getSequence()) - ).toList(); - } - - private Advertisment getAdvertisment(Long advId) { + private Advertisment getAdvertisment(final Long advId) { return advertismentRepository.findById(advId).orElseThrow( () -> new EntityNotFoundException(FailureCode.ADVERTISMENT_NOT_FOUND) );