From bd54b5b03df5a5401e117a7daf346e509df48118 Mon Sep 17 00:00:00 2001 From: ekgns33 Date: Wed, 26 Mar 2025 10:52:48 +0900 Subject: [PATCH 01/14] =?UTF-8?q?:recycle:=20refactor=20:=20jwt=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1=20=ED=8C=8C=EB=9D=BC=EB=A7=A4=ED=84=B0?= =?UTF-8?q?=EB=A1=9C=20=EC=97=94=ED=8B=B0=ED=8B=B0=EC=9D=98=20=EC=8B=9D?= =?UTF-8?q?=EB=B3=84=EC=9E=90=EB=A7=8C=20=EC=A0=9C=EA=B3=B5=ED=95=98?= =?UTF-8?q?=EB=8F=84=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/runimo/runimo/auth/jwt/JwtTokenFactory.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/runimo/runimo/auth/jwt/JwtTokenFactory.java b/src/main/java/org/runimo/runimo/auth/jwt/JwtTokenFactory.java index d2851c53..911bf008 100644 --- a/src/main/java/org/runimo/runimo/auth/jwt/JwtTokenFactory.java +++ b/src/main/java/org/runimo/runimo/auth/jwt/JwtTokenFactory.java @@ -23,24 +23,24 @@ public class JwtTokenFactory { @Value("${jwt.refresh.expiration}") private long jwtRefreshExpiration; - public String generateAccessToken(User user) { + public String generateAccessToken(String userPublicId) { Date now = new Date(); Date expiryDate = new Date(now.getTime() + jwtExpiration); return JWT.create() - .withSubject(user.getPublicId()) + .withSubject(userPublicId) .withIssuedAt(now) .withExpiresAt(expiryDate) .withIssuer(ISSUER) .sign(Algorithm.HMAC256(jwtSecret)); } - public String generateRefreshToken(User user) { + public String generateRefreshToken(String userPublicId) { Date now = new Date(); Date expiryDate = new Date(now.getTime() + jwtRefreshExpiration); return JWT.create() - .withSubject(user.getPublicId()) + .withSubject(userPublicId) .withIssuedAt(now) .withExpiresAt(expiryDate) .withIssuer(ISSUER) @@ -49,8 +49,8 @@ public String generateRefreshToken(User user) { } public TokenPair generateTokenPair(User user) { - String accessToken = generateAccessToken(user); - String refreshToken = generateRefreshToken(user); + String accessToken = generateAccessToken(user.getPublicId()); + String refreshToken = generateRefreshToken(user.getPublicId()); return new TokenPair(accessToken, refreshToken); } } From fac18250f97bd58c65f3c60e1df161a5a5dcb4f5 Mon Sep 17 00:00:00 2001 From: ekgns33 Date: Wed, 26 Mar 2025 20:41:46 +0900 Subject: [PATCH 02/14] =?UTF-8?q?:bug:=20fix=20:=20JWT=20=ED=86=A0?= =?UTF-8?q?=ED=81=B0=20Issuer=20=EB=B6=88=EC=9D=BC=EC=B9=98=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/org/runimo/runimo/auth/jwt/JwtResolver.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/runimo/runimo/auth/jwt/JwtResolver.java b/src/main/java/org/runimo/runimo/auth/jwt/JwtResolver.java index 5bdd0679..b827dc72 100644 --- a/src/main/java/org/runimo/runimo/auth/jwt/JwtResolver.java +++ b/src/main/java/org/runimo/runimo/auth/jwt/JwtResolver.java @@ -10,7 +10,7 @@ @Component public class JwtResolver { - private static final String ISSUER = "RunUSAuthService"; + private static final String ISSUER = "RUNIMO_SERVICE"; @Value("${jwt.secret}") private String jwtSecret; @Value("${jwt.expiration}") From d6ae9ff64e98dcdc887d786d19ddbb7c6ff7492e Mon Sep 17 00:00:00 2001 From: ekgns33 Date: Wed, 26 Mar 2025 20:42:45 +0900 Subject: [PATCH 03/14] =?UTF-8?q?:bug:=20fix=20:=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8/=ED=9A=8C=EC=9B=90=EA=B0=80=EC=9E=85=20endpoint=20fil?= =?UTF-8?q?ter=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EB=93=B1=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/org/runimo/runimo/common/GlobalConsts.java | 4 ++-- src/main/java/org/runimo/runimo/config/SecurityConfig.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/runimo/runimo/common/GlobalConsts.java b/src/main/java/org/runimo/runimo/common/GlobalConsts.java index fe72b427..30a63f6c 100644 --- a/src/main/java/org/runimo/runimo/common/GlobalConsts.java +++ b/src/main/java/org/runimo/runimo/common/GlobalConsts.java @@ -14,8 +14,8 @@ public final class GlobalConsts { public static final String DEFAULT_IMG_URL = "default_img_url"; public static final String SESSION_ATTRIBUTE_USER = "user-info"; public static final Set WHITE_LIST_ENDPOINTS = Set.of( - "/test/auth", - "/auth", + "/api/v1/test/auth", + "/api/v1/users/auth", "/swagger-ui", "/v3/api-docs" ); diff --git a/src/main/java/org/runimo/runimo/config/SecurityConfig.java b/src/main/java/org/runimo/runimo/config/SecurityConfig.java index de740b9c..3ba6ca54 100644 --- a/src/main/java/org/runimo/runimo/config/SecurityConfig.java +++ b/src/main/java/org/runimo/runimo/config/SecurityConfig.java @@ -28,7 +28,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti .sessionCreationPolicy(SessionCreationPolicy.STATELESS) ) .authorizeHttpRequests(authorize -> authorize - .requestMatchers("/auth/**").permitAll() + .requestMatchers("/api/v1/users/auth/**").permitAll() .anyRequest().authenticated() ) .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); @@ -45,7 +45,7 @@ public SecurityFilterChain devSecurityFilterChain(HttpSecurity http) throws Exce .sessionCreationPolicy(SessionCreationPolicy.STATELESS) ) .authorizeHttpRequests(authorize -> authorize - .requestMatchers("/auth/**").permitAll() + .requestMatchers("/api/v1/users/auth/**").permitAll() .requestMatchers("/swagger-ui/**", "/swagger-ui.html", "/v3/api-docs/**").permitAll() .anyRequest().authenticated() ); From e71cba2a0063d72055b64a87549b836715e605c2 Mon Sep 17 00:00:00 2001 From: ekgns33 Date: Wed, 26 Mar 2025 20:44:01 +0900 Subject: [PATCH 04/14] =?UTF-8?q?:recycle:=20refactor=20:=20=EB=B6=88?= =?UTF-8?q?=ED=95=84=EC=9A=94=ED=95=9C=20=EB=B3=80=EC=88=98=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C,=20endpoint=20=EC=88=98=EC=A0=95=EC=82=AC=ED=95=AD=20?= =?UTF-8?q?=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/org/runimo/runimo/auth/jwt/JwtResolver.java | 4 ---- src/main/java/org/runimo/runimo/common/GlobalConsts.java | 4 ---- 2 files changed, 8 deletions(-) diff --git a/src/main/java/org/runimo/runimo/auth/jwt/JwtResolver.java b/src/main/java/org/runimo/runimo/auth/jwt/JwtResolver.java index b827dc72..957a0502 100644 --- a/src/main/java/org/runimo/runimo/auth/jwt/JwtResolver.java +++ b/src/main/java/org/runimo/runimo/auth/jwt/JwtResolver.java @@ -13,10 +13,6 @@ public class JwtResolver { private static final String ISSUER = "RUNIMO_SERVICE"; @Value("${jwt.secret}") private String jwtSecret; - @Value("${jwt.expiration}") - private long jwtExpiration; - @Value("${jwt.refresh.expiration}") - private long jwtRefreshExpiration; public DecodedJWT verifyAccessToken(String token) throws JWTVerificationException { return JWT.require(Algorithm.HMAC256(jwtSecret)).withIssuer(ISSUER).build().verify(token); diff --git a/src/main/java/org/runimo/runimo/common/GlobalConsts.java b/src/main/java/org/runimo/runimo/common/GlobalConsts.java index 30a63f6c..9ba476a4 100644 --- a/src/main/java/org/runimo/runimo/common/GlobalConsts.java +++ b/src/main/java/org/runimo/runimo/common/GlobalConsts.java @@ -3,16 +3,12 @@ import lombok.AccessLevel; import lombok.NoArgsConstructor; -import java.time.ZoneId; import java.util.Set; @NoArgsConstructor(access = AccessLevel.PRIVATE) public final class GlobalConsts { public static final String TIME_ZONE_ID = "Asia/Seoul"; - public static final ZoneId ZONE_ID = ZoneId.of(TIME_ZONE_ID); - public static final String DEFAULT_IMG_URL = "default_img_url"; - public static final String SESSION_ATTRIBUTE_USER = "user-info"; public static final Set WHITE_LIST_ENDPOINTS = Set.of( "/api/v1/test/auth", "/api/v1/users/auth", From a27162b8ffb6514ce1b3bcf46c918bf5e1e155ab Mon Sep 17 00:00:00 2001 From: ekgns33 Date: Wed, 26 Mar 2025 20:45:34 +0900 Subject: [PATCH 05/14] =?UTF-8?q?:sparkles:=20feat=20:=20userIdResolver?= =?UTF-8?q?=EB=A5=BC=20=EC=8A=A4=ED=94=84=EB=A7=81=20mvc=20handlerResolver?= =?UTF-8?q?=EC=97=90=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../runimo/runimo/config/WebMvcConfig.java | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/main/java/org/runimo/runimo/config/WebMvcConfig.java diff --git a/src/main/java/org/runimo/runimo/config/WebMvcConfig.java b/src/main/java/org/runimo/runimo/config/WebMvcConfig.java new file mode 100644 index 00000000..fb70ab99 --- /dev/null +++ b/src/main/java/org/runimo/runimo/config/WebMvcConfig.java @@ -0,0 +1,21 @@ +package org.runimo.runimo.config; + +import lombok.RequiredArgsConstructor; +import org.runimo.runimo.user.controller.UserIdResolver; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import java.util.List; + +@Configuration +@RequiredArgsConstructor +public class WebMvcConfig implements WebMvcConfigurer { + + private final UserIdResolver userIdResolver; + + @Override + public void addArgumentResolvers(List resolvers) { + resolvers.add(userIdResolver); + } +} From 6eece62ac3dba5fa9ddf5ab2b0a98542f27e0470 Mon Sep 17 00:00:00 2001 From: ekgns33 Date: Wed, 26 Mar 2025 20:46:26 +0900 Subject: [PATCH 06/14] =?UTF-8?q?:sparkles:=20feat=20:=20BaseEntity,=20Ite?= =?UTF-8?q?mActivity=20JPA=20=EC=97=94=ED=8B=B0=ED=8B=B0=EC=97=90=20?= =?UTF-8?q?=EC=BB=AC=EB=9F=BC=EB=AA=85=20=EB=AA=85=EC=8B=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/org/runimo/runimo/common/BaseEntity.java | 5 +---- .../java/org/runimo/runimo/item/domain/ItemActivity.java | 9 ++++----- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/main/java/org/runimo/runimo/common/BaseEntity.java b/src/main/java/org/runimo/runimo/common/BaseEntity.java index 84fc971e..23de1604 100644 --- a/src/main/java/org/runimo/runimo/common/BaseEntity.java +++ b/src/main/java/org/runimo/runimo/common/BaseEntity.java @@ -1,9 +1,6 @@ package org.runimo.runimo.common; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.GenerationType; -import jakarta.persistence.Id; -import jakarta.persistence.MappedSuperclass; +import jakarta.persistence.*; import lombok.Getter; import lombok.NoArgsConstructor; import org.hibernate.annotations.CreationTimestamp; diff --git a/src/main/java/org/runimo/runimo/item/domain/ItemActivity.java b/src/main/java/org/runimo/runimo/item/domain/ItemActivity.java index 9fff3689..9094913c 100644 --- a/src/main/java/org/runimo/runimo/item/domain/ItemActivity.java +++ b/src/main/java/org/runimo/runimo/item/domain/ItemActivity.java @@ -1,8 +1,6 @@ package org.runimo.runimo.item.domain; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Table; +import jakarta.persistence.*; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; @@ -17,11 +15,12 @@ public class ItemActivity extends BaseEntity { @Column(name = "activity_user_id", nullable = false) private Long userId; - @Column(name = "activity_event_id", nullable = false) + @Column(name = "activity_item_id", nullable = false) private Long itemId; - + @Column(name = "quantity", nullable = false) private Long quantity; @Column(name = "activity_event_type", nullable = false) + @Enumerated(EnumType.STRING) private ActivityType type; @Builder From c556bf6f2b74a99055d7272926354d0e29a411b1 Mon Sep 17 00:00:00 2001 From: ekgns33 Date: Wed, 26 Mar 2025 20:47:12 +0900 Subject: [PATCH 07/14] =?UTF-8?q?:sparkles:=20feat=20:=20=EB=B3=B4?= =?UTF-8?q?=EC=9C=A0=ED=95=9C=20=EC=95=84=EC=9D=B4=ED=85=9C=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../user/controller/UserItemController.java | 27 +++++++++++++++++++ .../user/repository/MyItemRepository.java | 19 +++++++++++++ .../user/service/dtos/InventoryItem.java | 9 +++++++ .../user/service/dtos/ItemQueryResponse.java | 8 ++++++ .../service/usecases/MyItemQueryUsecase.java | 7 +++++ .../usecases/MyItemQueryUsecaseImpl.java | 23 ++++++++++++++++ 6 files changed, 93 insertions(+) create mode 100644 src/main/java/org/runimo/runimo/user/controller/UserItemController.java create mode 100644 src/main/java/org/runimo/runimo/user/repository/MyItemRepository.java create mode 100644 src/main/java/org/runimo/runimo/user/service/dtos/InventoryItem.java create mode 100644 src/main/java/org/runimo/runimo/user/service/dtos/ItemQueryResponse.java create mode 100644 src/main/java/org/runimo/runimo/user/service/usecases/MyItemQueryUsecase.java create mode 100644 src/main/java/org/runimo/runimo/user/service/usecases/MyItemQueryUsecaseImpl.java diff --git a/src/main/java/org/runimo/runimo/user/controller/UserItemController.java b/src/main/java/org/runimo/runimo/user/controller/UserItemController.java new file mode 100644 index 00000000..c62658b8 --- /dev/null +++ b/src/main/java/org/runimo/runimo/user/controller/UserItemController.java @@ -0,0 +1,27 @@ +package org.runimo.runimo.user.controller; + +import lombok.RequiredArgsConstructor; +import org.runimo.runimo.common.response.SuccessResponse; +import org.runimo.runimo.user.enums.UserHttpResponseCode; +import org.runimo.runimo.user.service.dtos.ItemQueryResponse; +import org.runimo.runimo.user.service.usecases.MyItemQueryUsecase; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api/v1/users/me/items") +@RequiredArgsConstructor +public class UserItemController { + + private final MyItemQueryUsecase myItemQueryUsecase; + + @GetMapping + public ResponseEntity> queryItems( + @UserId Long userId + ) { + ItemQueryResponse response = myItemQueryUsecase.execute(userId); + return ResponseEntity.ok(SuccessResponse.of(UserHttpResponseCode.MY_PAGE_DATA_FETCHED, response)); + } +} diff --git a/src/main/java/org/runimo/runimo/user/repository/MyItemRepository.java b/src/main/java/org/runimo/runimo/user/repository/MyItemRepository.java new file mode 100644 index 00000000..3092317c --- /dev/null +++ b/src/main/java/org/runimo/runimo/user/repository/MyItemRepository.java @@ -0,0 +1,19 @@ +package org.runimo.runimo.user.repository; + +import org.runimo.runimo.user.domain.UserItem; +import org.runimo.runimo.user.service.dtos.InventoryItem; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface MyItemRepository extends JpaRepository { + + @Query("SELECT new org.runimo.runimo.user.service.dtos.InventoryItem(i.itemId, it.name, i.quantity, it.imgUrl) " + + "FROM UserItem i" + + " join Item it on i.itemId = it.id" + + " WHERE i.userId = :userId") + List findInventoryItemsByUserId(Long userId); +} diff --git a/src/main/java/org/runimo/runimo/user/service/dtos/InventoryItem.java b/src/main/java/org/runimo/runimo/user/service/dtos/InventoryItem.java new file mode 100644 index 00000000..a4db6d1f --- /dev/null +++ b/src/main/java/org/runimo/runimo/user/service/dtos/InventoryItem.java @@ -0,0 +1,9 @@ +package org.runimo.runimo.user.service.dtos; + +public record InventoryItem( + Long itemId, + String name, + Long amount, + String imgUrl +) { +} diff --git a/src/main/java/org/runimo/runimo/user/service/dtos/ItemQueryResponse.java b/src/main/java/org/runimo/runimo/user/service/dtos/ItemQueryResponse.java new file mode 100644 index 00000000..7302548d --- /dev/null +++ b/src/main/java/org/runimo/runimo/user/service/dtos/ItemQueryResponse.java @@ -0,0 +1,8 @@ +package org.runimo.runimo.user.service.dtos; + +import java.util.List; + +public record ItemQueryResponse( + List items +) { +} diff --git a/src/main/java/org/runimo/runimo/user/service/usecases/MyItemQueryUsecase.java b/src/main/java/org/runimo/runimo/user/service/usecases/MyItemQueryUsecase.java new file mode 100644 index 00000000..114b6644 --- /dev/null +++ b/src/main/java/org/runimo/runimo/user/service/usecases/MyItemQueryUsecase.java @@ -0,0 +1,7 @@ +package org.runimo.runimo.user.service.usecases; + +import org.runimo.runimo.user.service.dtos.ItemQueryResponse; + +public interface MyItemQueryUsecase { + ItemQueryResponse execute(Long userId); +} diff --git a/src/main/java/org/runimo/runimo/user/service/usecases/MyItemQueryUsecaseImpl.java b/src/main/java/org/runimo/runimo/user/service/usecases/MyItemQueryUsecaseImpl.java new file mode 100644 index 00000000..0f04f400 --- /dev/null +++ b/src/main/java/org/runimo/runimo/user/service/usecases/MyItemQueryUsecaseImpl.java @@ -0,0 +1,23 @@ +package org.runimo.runimo.user.service.usecases; + + +import lombok.RequiredArgsConstructor; +import org.runimo.runimo.user.repository.MyItemRepository; +import org.runimo.runimo.user.service.dtos.InventoryItem; +import org.runimo.runimo.user.service.dtos.ItemQueryResponse; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +@RequiredArgsConstructor +public class MyItemQueryUsecaseImpl implements MyItemQueryUsecase { + + private final MyItemRepository myItemRepository; + + @Override + public ItemQueryResponse execute(Long userId) { + List myItems = myItemRepository.findInventoryItemsByUserId(userId); + return new ItemQueryResponse(myItems); + } +} From 787c0a37ed5aef763a1549adee9a08c4eccbc3da Mon Sep 17 00:00:00 2001 From: ekgns33 Date: Wed, 26 Mar 2025 20:47:48 +0900 Subject: [PATCH 08/14] =?UTF-8?q?:recycle:=20refactor:=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8,=20=ED=9A=8C=EC=9B=90=EA=B0=80=EC=9E=85=20en?= =?UTF-8?q?dpoint=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/runimo/runimo/user/controller/UserController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/runimo/runimo/user/controller/UserController.java b/src/main/java/org/runimo/runimo/user/controller/UserController.java index a3bb2850..47b205fc 100644 --- a/src/main/java/org/runimo/runimo/user/controller/UserController.java +++ b/src/main/java/org/runimo/runimo/user/controller/UserController.java @@ -41,7 +41,7 @@ public class UserController { @ApiResponse(responseCode = "400", description = "잘못된 요청 데이터"), @ApiResponse(responseCode = "401", description = "인증 실패") }) - @PostMapping("/login") + @PostMapping("/auth/login") public ResponseEntity> login( @Valid @RequestBody AuthLoginRequest request ) { @@ -63,7 +63,7 @@ public ResponseEntity> login( @ApiResponse(responseCode = "400", description = "잘못된 요청 데이터"), @ApiResponse(responseCode = "409", description = "이미 존재하는 사용자") }) - @PostMapping("/signup") + @PostMapping("/auth/signup") public ResponseEntity> signupAndLogin( @Valid @RequestBody AuthSignupRequest request) { SignupUserInfo authResult = userOAuthUsecase.validateAndSignup( From 861b11096a87323019e87e3e4d5d16f9fdfdfd3b Mon Sep 17 00:00:00 2001 From: ekgns33 Date: Wed, 26 Mar 2025 20:48:22 +0900 Subject: [PATCH 09/14] =?UTF-8?q?:bug:=20fix:=20UserIdResolver=EA=B0=80=20?= =?UTF-8?q?userPublicId=EB=A1=9C=20=EC=A1=B0=ED=9A=8C=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/org/runimo/runimo/user/controller/UserIdResolver.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/runimo/runimo/user/controller/UserIdResolver.java b/src/main/java/org/runimo/runimo/user/controller/UserIdResolver.java index 580955a8..9a559230 100644 --- a/src/main/java/org/runimo/runimo/user/controller/UserIdResolver.java +++ b/src/main/java/org/runimo/runimo/user/controller/UserIdResolver.java @@ -31,7 +31,7 @@ public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer m if (authentication == null || !authentication.isAuthenticated()) { throw new SecurityException("No authentication found"); } - User user = userFinder.findUserById(Long.valueOf(authentication.getName())) + User user = userFinder.findUserByPublicId(authentication.getName()) .orElseThrow(NoPermissionException::new); return user.getId(); } From f0ca1f346d60a119d7366efb77a2aae885791560 Mon Sep 17 00:00:00 2001 From: ekgns33 Date: Wed, 26 Mar 2025 20:48:59 +0900 Subject: [PATCH 10/14] =?UTF-8?q?:recycle:=20refactor=20:=20=EB=B6=88?= =?UTF-8?q?=ED=95=84=EC=9A=94=ED=95=9C=20=EB=B3=80=EC=88=98=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../runimo/user/service/usecases/UserOAuthUsecaseImpl.java | 2 +- .../runimo/user/service/usecases/UserRegisterService.java | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/runimo/runimo/user/service/usecases/UserOAuthUsecaseImpl.java b/src/main/java/org/runimo/runimo/user/service/usecases/UserOAuthUsecaseImpl.java index 6b2b150c..abee58ae 100644 --- a/src/main/java/org/runimo/runimo/user/service/usecases/UserOAuthUsecaseImpl.java +++ b/src/main/java/org/runimo/runimo/user/service/usecases/UserOAuthUsecaseImpl.java @@ -47,7 +47,7 @@ public SignupUserInfo validateAndSignup(final UserSignupCommand command, final S .ifPresent(oAuthInfo -> { throw new IllegalArgumentException(); }); - User savedUser = userRegisterService.register(command, provider, pid); + User savedUser = userRegisterService.register(command, pid); return new SignupUserInfo(savedUser.getId(), jwtfactory.generateTokenPair(savedUser)); } } diff --git a/src/main/java/org/runimo/runimo/user/service/usecases/UserRegisterService.java b/src/main/java/org/runimo/runimo/user/service/usecases/UserRegisterService.java index 20c146dc..d2138060 100644 --- a/src/main/java/org/runimo/runimo/user/service/usecases/UserRegisterService.java +++ b/src/main/java/org/runimo/runimo/user/service/usecases/UserRegisterService.java @@ -2,7 +2,6 @@ import lombok.RequiredArgsConstructor; import org.runimo.runimo.rewards.service.eggs.EggGrantService; -import org.runimo.runimo.user.domain.SocialProvider; import org.runimo.runimo.user.domain.User; import org.runimo.runimo.user.service.UserCreator; import org.runimo.runimo.user.service.UserItemCreator; @@ -19,9 +18,9 @@ public class UserRegisterService { private final EggGrantService eggGrantService; @Transactional - public User register(UserSignupCommand command, SocialProvider provider, String providerId) { + public User register(UserSignupCommand command, String providerId) { User savedUser = userCreator.createUser(command); - userCreator.createUserOAuthInfo(savedUser, provider, providerId); + userCreator.createUserOAuthInfo(savedUser, command.provider(), providerId); userItemCreator.createAll(savedUser.getId()); eggGrantService.grantGreetingEggToUser(savedUser); return savedUser; From 3398cbefed222d00666045d0829e984e1638f2af Mon Sep 17 00:00:00 2001 From: ekgns33 Date: Wed, 26 Mar 2025 20:51:43 +0900 Subject: [PATCH 11/14] =?UTF-8?q?:white=5Fcheck=5Fmark:=20test=20:=20?= =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C=20=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../org/runimo/runimo/rewards/RewardTest.java | 2 +- .../org/runimo/runimo/user/UserFixtures.java | 15 ++ .../user/api/QueryItemControllerTest.java | 52 ++++++ .../user/api/UserItemAcceptanceTest.java | 159 ++++++++++++++++++ .../usecases/QueryUserItemUsecaseTest.java | 46 +++++ .../usecases/UserRegisterServiceTest.java | 11 +- 6 files changed, 283 insertions(+), 2 deletions(-) create mode 100644 src/test/java/org/runimo/runimo/user/UserFixtures.java create mode 100644 src/test/java/org/runimo/runimo/user/api/QueryItemControllerTest.java create mode 100644 src/test/java/org/runimo/runimo/user/api/UserItemAcceptanceTest.java create mode 100644 src/test/java/org/runimo/runimo/user/service/usecases/QueryUserItemUsecaseTest.java diff --git a/src/test/java/org/runimo/runimo/rewards/RewardTest.java b/src/test/java/org/runimo/runimo/rewards/RewardTest.java index 15a8b662..06a98286 100644 --- a/src/test/java/org/runimo/runimo/rewards/RewardTest.java +++ b/src/test/java/org/runimo/runimo/rewards/RewardTest.java @@ -49,7 +49,7 @@ class RewardTest { void setUp() { //given UserSignupCommand command = new UserSignupCommand("test", SocialProvider.KAKAO, "1234"); - savedUser = userRegisterService.register(command, SocialProvider.KAKAO, "1234"); + savedUser = userRegisterService.register(command, "1234"); } @AfterEach diff --git a/src/test/java/org/runimo/runimo/user/UserFixtures.java b/src/test/java/org/runimo/runimo/user/UserFixtures.java new file mode 100644 index 00000000..4800024a --- /dev/null +++ b/src/test/java/org/runimo/runimo/user/UserFixtures.java @@ -0,0 +1,15 @@ +package org.runimo.runimo.user; + +import org.runimo.runimo.user.domain.User; + +public final class UserFixtures { + + public static User getDefaultUser() { + return User.builder() + .nickname("test") + .imgUrl("test") + .totalDistanceInMeters(0L) + .totalTimeInSeconds(0L) + .build(); + } +} diff --git a/src/test/java/org/runimo/runimo/user/api/QueryItemControllerTest.java b/src/test/java/org/runimo/runimo/user/api/QueryItemControllerTest.java new file mode 100644 index 00000000..e3fe2835 --- /dev/null +++ b/src/test/java/org/runimo/runimo/user/api/QueryItemControllerTest.java @@ -0,0 +1,52 @@ +package org.runimo.runimo.user.api; + +import org.junit.jupiter.api.Test; +import org.runimo.runimo.auth.jwt.JwtTokenFactory; +import org.runimo.runimo.user.UserFixtures; +import org.runimo.runimo.user.service.UserFinder; +import org.runimo.runimo.user.service.dtos.ItemQueryResponse; +import org.runimo.runimo.user.service.usecases.MyItemQueryUsecase; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.bean.override.mockito.MockitoBean; +import org.springframework.test.web.servlet.MockMvc; + +import java.util.ArrayList; +import java.util.Optional; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@SpringBootTest +@AutoConfigureMockMvc +@ActiveProfiles("test") +class QueryItemControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Autowired + private JwtTokenFactory jwtTokenFactory; + @MockitoBean + private UserFinder userFinder; + @MockitoBean + private MyItemQueryUsecase myItemQueryUsecase; + + @Test + void 보유한_아이템_조회_성공() throws Exception { + String accessToken = jwtTokenFactory.generateAccessToken("test-user-uuid-1"); + given(myItemQueryUsecase.execute(any())) + .willReturn(new ItemQueryResponse(new ArrayList<>())); + given(userFinder.findUserByPublicId(any())) + .willReturn(Optional.of(UserFixtures.getDefaultUser())); + mockMvc.perform(get("/api/v1/users/me/items") + .header("Authorization", "Bearer " + accessToken)) + .andDo(print()) + .andExpect(status().isOk()); + } +} diff --git a/src/test/java/org/runimo/runimo/user/api/UserItemAcceptanceTest.java b/src/test/java/org/runimo/runimo/user/api/UserItemAcceptanceTest.java new file mode 100644 index 00000000..49908a77 --- /dev/null +++ b/src/test/java/org/runimo/runimo/user/api/UserItemAcceptanceTest.java @@ -0,0 +1,159 @@ +package org.runimo.runimo.user.api; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.restassured.RestAssured; +import io.restassured.http.ContentType; +import io.restassured.response.ValidatableResponse; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.runimo.runimo.CleanUpUtil; +import org.runimo.runimo.auth.jwt.JwtTokenFactory; +import org.runimo.runimo.auth.service.OidcService; +import org.runimo.runimo.user.controller.request.AuthSignupRequest; +import org.runimo.runimo.user.controller.request.UseItemRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.http.HttpStatus; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.bean.override.mockito.MockitoBean; +import org.springframework.test.context.jdbc.Sql; + +import static io.restassured.RestAssured.given; +import static org.hamcrest.Matchers.*; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.when; + +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) + +@ActiveProfiles("test") +class UserItemAcceptanceTest { + + @LocalServerPort + private int port; + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private JwtTokenFactory jwtTokenFactory; + + @MockitoBean + private OidcService oidcService; + + @Autowired + private CleanUpUtil cleanUpUtil; + + @BeforeEach + void setUp() { + RestAssured.port = port; + } + + @AfterEach() + void tearDown() { + cleanUpUtil.cleanUpUserInfos(); + } + + @Test + @Sql(scripts = "/sql/user_item_test_data.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) + void 아이템_조회_성공() { + // given + String jwt = "Bearer " + jwtTokenFactory.generateAccessToken("test-user-uuid-1"); + + // when + then + given() + .header("Authorization", jwt) + .when() + .get("/api/v1/users/me/items") + .then() + .log().all() + .statusCode(200) + .contentType(ContentType.JSON) + .body("success", equalTo(true)) + .body("payload", notNullValue()) + .body("payload.size()", greaterThan(0)) + .body("payload.items[0].item_id", not(emptyOrNullString())) + .body("payload.items[0].amount", greaterThanOrEqualTo(0)); + } + + @Test + @Sql(scripts = "/sql/user_item_test_data.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) + void 아이템_사용시_보유량감소() throws JsonProcessingException { + String jwt = "Bearer " + jwtTokenFactory.generateAccessToken("test-user-uuid-1"); + + UseItemRequest request = new UseItemRequest(1L, 2L); + + given() + .header("Authorization", jwt) + .body(objectMapper.writeValueAsString(request)) + .contentType(ContentType.JSON) + .when() + .post("/api/v1/users/me/items/use") + .then() + .log().ifError() + .statusCode(HttpStatus.OK.value()); + + given() + .header("Authorization", jwt) + .when() + .get("/api/v1/users/me/items") + .then() + .statusCode(HttpStatus.OK.value()) + .body("payload", notNullValue()) + .body("payload.size()", greaterThan(0)) + .body("payload.items[0].item_id", not(emptyOrNullString())) + .body("payload.items[0].amount", equalTo(0)); + } + + @Test + @Sql(scripts = "/sql/user_item_test_data.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) + void 보유한_수량보다_더_많은_요청_시_에러() throws JsonProcessingException { + String jwt = "Bearer " + jwtTokenFactory.generateAccessToken("test-user-uuid-1"); + UseItemRequest request = new UseItemRequest(1L, 10L); + + given() + .header("Authorization", jwt) + .body(objectMapper.writeValueAsString(request)) + .contentType(ContentType.JSON) + .when() + .post("/api/v1/users/me/items/use") + .then() + .log().ifError() + .statusCode(HttpStatus.BAD_REQUEST.value()); + } + + @Test + void 회원가입후_알_지급_성공() throws JsonProcessingException { + String token = jwtTokenFactory.generateAccessToken("test-user-uuid-1"); + when(oidcService.validateOidcTokenAndGetProviderId(any(), any())) + .thenReturn("123"); + + AuthSignupRequest request = new AuthSignupRequest(token, "KAKAO", "1234", "https://example.com/image.jpg"); + + ValidatableResponse res = given() + .body(objectMapper.writeValueAsString(request)) + .contentType(ContentType.JSON) + .when() + .post("/api/v1/users/auth/signup") + .then() + .log().ifError() + .statusCode(HttpStatus.CREATED.value()); + + String accessToken = res.extract().body().jsonPath().getString("payload.access_token"); + + given() + .header("Authorization", "Bearer " + accessToken) + .when() + .get("/api/v1/users/me/items") + .then() + .log().all() + .statusCode(200) + .contentType(ContentType.JSON) + .body("success", equalTo(true)) + .body("payload", notNullValue()) + .body("payload.size()", greaterThan(0)) + .body("payload.items[0].item_id", not(emptyOrNullString())) + .body("payload.items[0].amount", greaterThanOrEqualTo(0)); + } +} diff --git a/src/test/java/org/runimo/runimo/user/service/usecases/QueryUserItemUsecaseTest.java b/src/test/java/org/runimo/runimo/user/service/usecases/QueryUserItemUsecaseTest.java new file mode 100644 index 00000000..fa7f1021 --- /dev/null +++ b/src/test/java/org/runimo/runimo/user/service/usecases/QueryUserItemUsecaseTest.java @@ -0,0 +1,46 @@ +package org.runimo.runimo.user.service.usecases; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.runimo.runimo.user.repository.MyItemRepository; +import org.runimo.runimo.user.service.dtos.InventoryItem; +import org.runimo.runimo.user.service.dtos.ItemQueryResponse; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.BDDMockito.given; +import static org.mockito.MockitoAnnotations.openMocks; + +/* + * 1. 유저의 아이템을 조회한다. + * */ +class QueryUserItemUsecaseTest { + + private MyItemQueryUsecase myItemQueryUsecase; + @Mock + private MyItemRepository myItemRepository; + + @BeforeEach + void setUp() { + openMocks(this); + myItemQueryUsecase = new MyItemQueryUsecaseImpl(myItemRepository); + } + + @Test + void 사용자의_보유_아이템_전체_조회() { + // given + Long userId = 1L; + given(myItemRepository.findInventoryItemsByUserId(userId)).willReturn(List.of( + new InventoryItem(1L, "마당알", 1L, "imgUrl"), + new InventoryItem(2L, "숲알", 30L, "imgUr2l")) + ); + // when + ItemQueryResponse res = myItemQueryUsecase.execute(userId); + // then + assertNotNull(res); + assertEquals(2, res.items().size()); + } +} diff --git a/src/test/java/org/runimo/runimo/user/service/usecases/UserRegisterServiceTest.java b/src/test/java/org/runimo/runimo/user/service/usecases/UserRegisterServiceTest.java index 953476de..a23b80f1 100644 --- a/src/test/java/org/runimo/runimo/user/service/usecases/UserRegisterServiceTest.java +++ b/src/test/java/org/runimo/runimo/user/service/usecases/UserRegisterServiceTest.java @@ -1,6 +1,8 @@ package org.runimo.runimo.user.service.usecases; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; +import org.runimo.runimo.CleanUpUtil; import org.runimo.runimo.item.repository.ItemRepository; import org.runimo.runimo.user.domain.SocialProvider; import org.runimo.runimo.user.domain.User; @@ -25,12 +27,19 @@ class UserRegisterServiceTest { private UserItemRepository userItemRepository; @Autowired private ItemRepository itemRepository; + @Autowired + private CleanUpUtil cleanUpUtil; + + @AfterEach + void tearDown() { + cleanUpUtil.cleanUpUserInfos(); + } @Test void 회원가입_알_지급_테스트() { // given UserSignupCommand command = new UserSignupCommand("test", SocialProvider.KAKAO, "1234"); - User createdUser = userRegisterService.register(command, SocialProvider.KAKAO, "1234"); + User createdUser = userRegisterService.register(command, "1234"); UserItem ui = userItemRepository.findByUserIdAndItemId(createdUser.getId(), 1L).get(); assertNotNull(ui); assertEquals(1L, ui.getQuantity()); From e7bec3cb7b81c2404f82f01732d72b96092e098a Mon Sep 17 00:00:00 2001 From: ekgns33 Date: Wed, 26 Mar 2025 20:52:42 +0900 Subject: [PATCH 12/14] =?UTF-8?q?:hammer:=20chore=20:=20ddl=20=EC=88=98?= =?UTF-8?q?=EC=A0=95,=20test=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20dml=EC=9E=91?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/sql/schema.sql | 174 ++++++++---------- src/test/resources/sql/schema.sql | 1 + .../resources/sql/user_item_test_data.sql | 25 +++ 3 files changed, 105 insertions(+), 95 deletions(-) create mode 100644 src/test/resources/sql/user_item_test_data.sql diff --git a/src/main/resources/sql/schema.sql b/src/main/resources/sql/schema.sql index d13df5d6..1fa8b843 100644 --- a/src/main/resources/sql/schema.sql +++ b/src/main/resources/sql/schema.sql @@ -13,115 +13,99 @@ DROP TABLE IF EXISTS users; SET FOREIGN_KEY_CHECKS = 1; -CREATE TABLE `users` ( - `id` BIGINT PRIMARY KEY AUTO_INCREMENT, - `public_id` VARCHAR(255), - `nickname` VARCHAR(255), - `img_url` VARCHAR(255), - `total_distance_in_meters` BIGINT NOT NULL DEFAULT 0, - `total_time_in_seconds` BIGINT NOT NULL DEFAULT 0, - `updated_at` TIMESTAMP, - `created_at` TIMESTAMP, - `deleted_at` TIMESTAMP +CREATE TABLE `users` +( + `id` BIGINT PRIMARY KEY AUTO_INCREMENT, + `public_id` VARCHAR(255), + `nickname` VARCHAR(255), + `img_url` VARCHAR(255), + `total_distance_in_meters` BIGINT NOT NULL DEFAULT 0, + `total_time_in_seconds` BIGINT NOT NULL DEFAULT 0, + `updated_at` TIMESTAMP, + `created_at` TIMESTAMP, + `deleted_at` TIMESTAMP ); -CREATE TABLE `user_token` ( - `user_id` BIGINT NOT NULL, - `device_token` VARCHAR(255) NOT NULL, - `created_at` TIMESTAMP, - `updated_at` TIMESTAMP, - `deleted_at` TIMESTAMP, - FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE -); +CREATE TABLE `user_token` +( + `user_id` BIGINT NOT NULL, + `device_token` VARCHAR(255) NOT NULL, + `created_at` TIMESTAMP, + `updated_at` TIMESTAMP, + `deleted_at` TIMESTAMP, -CREATE TABLE `oauth_accounts` ( - `id` BIGINT PRIMARY KEY AUTO_INCREMENT, - `user_id` BIGINT NOT NULL, - `provider` VARCHAR(255), - `provider_id` VARCHAR(255), - `created_at` TIMESTAMP, - `updated_at` TIMESTAMP, - `deleted_at` TIMESTAMP, - FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE + FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ); -CREATE TABLE `running_records` ( - `id` BIGINT PRIMARY KEY AUTO_INCREMENT, - `user_id` BIGINT NOT NULL, - `record_public_id` VARCHAR(255) NOT NULL, - `start_at` TIMESTAMP, - `end_at` TIMESTAMP, - `total_distance` BIGINT, - `pace_in_milli_seconds` BIGINT, - `created_at` TIMESTAMP, - `updated_at` TIMESTAMP, - `deleted_at` TIMESTAMP +CREATE TABLE `oauth_accounts` +( + `id` BIGINT PRIMARY KEY AUTO_INCREMENT, + `user_id` BIGINT NOT NULL, + `provider` VARCHAR(255), + `provider_id` VARCHAR(255), + `created_at` TIMESTAMP, + `updated_at` TIMESTAMP, + `deleted_at` TIMESTAMP, + FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ); -CREATE TABLE `items` ( - `id` BIGINT PRIMARY KEY AUTO_INCREMENT, - `name` VARCHAR(255) NOT NULL, - `item_code` VARCHAR(255) NOT NULL, - `description` VARCHAR(255), - `item_type` VARCHAR(255) NOT NULL, - `img_url` VARCHAR(255), - `dtype` VARCHAR(255), - `egg_type` VARCHAR(255), - `hatch_require_amount` BIGINT, - `created_at` TIMESTAMP, - `updated_at` TIMESTAMP, - `deleted_at` TIMESTAMP -); -CREATE TABLE `item_activity` ( - `id` BIGINT PRIMARY KEY AUTO_INCREMENT, - `activity_user_id` BIGINT NOT NULL, - `activity_item_id` BIGINT NOT NULL, - `activity_event_type` VARCHAR(255) NOT NULL, - `created_at` TIMESTAMP, - `updated_at` TIMESTAMP, - `deleted_at` TIMESTAMP +CREATE TABLE `running_records` +( + `id` integer PRIMARY KEY AUTO_INCREMENT, + `user_id` integer NOT NULL, + `record_public_id` VARCHAR(255) NOT NULL, + `title` varchar(255), + `started_at` timestamp, + `end_at` timestamp, + `total_distance` integer, + `pace_in_milli_seconds` integer, + `created_at` timestamp, + `updated_at` timestamp, + `deleted_at` TIMESTAMP ); -CREATE TABLE `user_item` ( - `id` BIGINT PRIMARY KEY AUTO_INCREMENT, - `user_id` BIGINT NOT NULL, - `item_id` BIGINT NOT NULL, - `quantity` BIGINT NOT NULL, - `created_at` TIMESTAMP, - `updated_at` TIMESTAMP, - `deleted_at` TIMESTAMP +CREATE TABLE `items` +( + `id` integer PRIMARY KEY AUTO_INCREMENT, + `name` varchar(255) NOT NULL, + `item_code` varchar(255) NOT NULL, + `description` varchar(255), + `item_type` varchar(255) NOT NULL, + `img_url` varchar(255), + `dtype` varchar(255), + `egg_type` varchar(255), + `hatch_require_amount` long, + `created_at` timestamp, + `updated_at` timestamp, + `deleted_at` TIMESTAMP ); -CREATE TABLE `incubator` ( - `id` BIGINT PRIMARY KEY AUTO_INCREMENT, - `user_id` BIGINT NOT NULL, - `slot` BIGINT NOT NULL, - `egg_id` BIGINT NOT NULL, - `progress` BIGINT DEFAULT 0, - `created_at` TIMESTAMP, - `updated_at` TIMESTAMP, - `deleted_at` TIMESTAMP +CREATE TABLE `item_activity` +( + `id` integer PRIMARY KEY AUTO_INCREMENT, + `activity_user_id` integer NOT NULL, + `activity_item_id` integer NOT NULL, + `activity_event_type` varchar(255) NOT NULL, + `quantity` integer, + `created_at` timestamp, + `updated_at` timestamp, + `deleted_at` TIMESTAMP ); -CREATE TABLE `runimo` ( - `id` BIGINT PRIMARY KEY AUTO_INCREMENT, - `name` VARCHAR(255), - `description` VARCHAR(255), - `type` VARCHAR(255) NOT NULL, - `created_at` TIMESTAMP, - `updated_at` TIMESTAMP, - `deleted_at` TIMESTAMP +CREATE TABLE `user_item` +( + `id` BIGINT PRIMARY KEY AUTO_INCREMENT, + `user_id` integer NOT NULL, + `item_id` integer NOT NULL, + `quantity` integer NOT NULL, + `created_at` timestamp, + `updated_at` timestamp, + `deleted_at` TIMESTAMP ); -CREATE TABLE `user_runimo` ( - `id` BIGINT PRIMARY KEY AUTO_INCREMENT, - `user_id` BIGINT NOT NULL, - `runimo_id` BIGINT NOT NULL, - `created_at` TIMESTAMP, - `updated_at` TIMESTAMP, - `deleted_at` TIMESTAMP -); +ALTER TABLE `user_token` + ADD FOREIGN KEY (`user_id`) REFERENCES `users` (`id`); -ALTER TABLE `user_token` ADD FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE; -ALTER TABLE `oauth_accounts` ADD FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON DELETE CASCADE; \ No newline at end of file +ALTER TABLE `oauth_accounts` + ADD FOREIGN KEY (`user_id`) REFERENCES `users` (`id`); diff --git a/src/test/resources/sql/schema.sql b/src/test/resources/sql/schema.sql index fa4e7a14..1fa8b843 100644 --- a/src/test/resources/sql/schema.sql +++ b/src/test/resources/sql/schema.sql @@ -87,6 +87,7 @@ CREATE TABLE `item_activity` `activity_user_id` integer NOT NULL, `activity_item_id` integer NOT NULL, `activity_event_type` varchar(255) NOT NULL, + `quantity` integer, `created_at` timestamp, `updated_at` timestamp, `deleted_at` TIMESTAMP diff --git a/src/test/resources/sql/user_item_test_data.sql b/src/test/resources/sql/user_item_test_data.sql new file mode 100644 index 00000000..78aea917 --- /dev/null +++ b/src/test/resources/sql/user_item_test_data.sql @@ -0,0 +1,25 @@ +-- 사용자 +SET FOREIGN_KEY_CHECKS = 0; +TRUNCATE TABLE users; +INSERT INTO users (id, public_id, nickname, img_url, total_distance_in_meters, total_time_in_seconds, created_at, + updated_at) +VALUES (1, 'test-user-uuid-1', 'Daniel', 'https://example.com/images/user1.png', 10000, 3600, NOW(), NOW()), + (2, 'test-user-uuid-2', 'Moon', 'https://example.com/images/user2.png', 5000, 1800, NOW(), NOW()); +SET FOREIGN_KEY_CHECKS = 1; + + +TRUNCATE TABLE items; +INSERT INTO items (name, item_code, description, item_type, img_url, dtype, egg_type, hatch_require_amount, created_at, + updated_at) +VALUES ('마당알', 'A100', '마당알: 기본 알', 'USABLE', 'example.url', 'Egg', 'MADANG', 10, NOW(), NOW()); + +INSERT INTO items (name, item_code, description, item_type, img_url, dtype, egg_type, hatch_require_amount, created_at, + updated_at) +VALUES ('숲알', 'A101', '숲알: 기본 알', 'USABLE', 'example1.url', 'Egg', 'FOREST', 20, NOW(), NOW()); + + +-- 보유 아이템 +TRUNCATE TABLE user_item; +INSERT INTO user_item (id, user_id, item_id, quantity, created_at, updated_at) +VALUES (1001, 1, 1, 2, NOW(), NOW()), + (1002, 1, 2, 1, NOW(), NOW()) From e839274e4acb7355ce08b36dfdfb27c444765976 Mon Sep 17 00:00:00 2001 From: ekgns33 Date: Wed, 26 Mar 2025 20:55:43 +0900 Subject: [PATCH 13/14] =?UTF-8?q?:wrench:=20chore:=20application.yml=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/resources/application.yml | 2 +- src/test/resources/{application-test.yml => application.yml} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/test/resources/{application-test.yml => application.yml} (97%) diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index f2cfdabe..5513c22e 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -18,7 +18,7 @@ spring: password: ${DB_PASSWORD} jpa: hibernate: - ddl-auto: ${JPA_DDL_AUTO:update} + ddl-auto: ${JPA_DDL_AUTO:none} properties: hibernate: dialect: ${JPA_DIALECT} diff --git a/src/test/resources/application-test.yml b/src/test/resources/application.yml similarity index 97% rename from src/test/resources/application-test.yml rename to src/test/resources/application.yml index 4f302129..f1985a73 100644 --- a/src/test/resources/application-test.yml +++ b/src/test/resources/application.yml @@ -17,7 +17,7 @@ spring: password: ${DB_PASSWORD} jpa: hibernate: - ddl-auto: ${JPA_DDL_AUTO:update} + ddl-auto: none properties: hibernate: dialect: org.hibernate.dialect.H2Dialect From 95282daaddd1ad55ef47fcdb6ce467ad9dfa65ae Mon Sep 17 00:00:00 2001 From: ekgns33 Date: Wed, 26 Mar 2025 20:56:29 +0900 Subject: [PATCH 14/14] =?UTF-8?q?:heavy=5Fplus=5Fsign:=20chore=20:=20RestA?= =?UTF-8?q?ssured=20=EC=9D=98=EC=A1=B4=EC=84=B1=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build.gradle | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build.gradle b/build.gradle index c0e8e778..413e4804 100644 --- a/build.gradle +++ b/build.gradle @@ -37,6 +37,10 @@ dependencies { runtimeOnly 'com.h2database:h2' runtimeOnly 'com.mysql:mysql-connector-j' + + testImplementation 'io.rest-assured:rest-assured:5.4.0' + testImplementation 'io.rest-assured:json-path:5.4.0' + testImplementation 'io.rest-assured:json-schema-validator:5.4.0' testImplementation 'org.springframework.security:spring-security-test' testImplementation 'org.springframework.boot:spring-boot-starter-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher'