From 347f018ff5bb296d01be8ae0399db3751d309309 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9E=AC=ED=98=81?= Date: Tue, 19 Nov 2024 12:42:42 +0900 Subject: [PATCH 1/4] =?UTF-8?q?feat:=20=EC=9E=A5=EB=B0=94=EA=B5=AC?= =?UTF-8?q?=EB=8B=88=20=EC=A1=B0=ED=9A=8C=20=EA=B8=B0=EB=8A=A5=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84=20(#44)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 장바구니 추가 기능 구현 (#41) * feat: 장바구니 조회 기능 구현 (#43) * feat: 장바구니 추가 기능 구현 * feat: 장바구니 조회 기능 구현 --- .../order/application/OrderService.java | 29 +++++++++++++++- .../domain/repository/CartRepository.java | 4 +++ .../order/dto/response/CartResponse.java | 33 +++++++++++++++++++ .../order/presentation/OrderController.java | 12 ++++++- 4 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/jangburich/domain/order/dto/response/CartResponse.java diff --git a/src/main/java/com/jangburich/domain/order/application/OrderService.java b/src/main/java/com/jangburich/domain/order/application/OrderService.java index f547aeb..87c6a6f 100644 --- a/src/main/java/com/jangburich/domain/order/application/OrderService.java +++ b/src/main/java/com/jangburich/domain/order/application/OrderService.java @@ -4,13 +4,15 @@ import com.jangburich.domain.menu.domain.repository.MenuRepository; import com.jangburich.domain.order.domain.Cart; import com.jangburich.domain.order.domain.repository.CartRepository; -import com.jangburich.domain.order.domain.repository.OrdersRepository; import com.jangburich.domain.order.dto.request.AddCartRequest; +import com.jangburich.domain.order.dto.response.CartResponse; +import com.jangburich.domain.order.dto.response.CartResponse.GetCartItemsResponse; import com.jangburich.domain.store.domain.Store; import com.jangburich.domain.store.domain.repository.StoreRepository; import com.jangburich.domain.user.domain.User; import com.jangburich.domain.user.domain.repository.UserRepository; import com.jangburich.global.payload.Message; +import java.util.List; import java.util.Optional; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -65,4 +67,29 @@ public Message addCart(String userProviderId, AddCartRequest addCartRequest) { .message("장바구니에 상품을 추가했습니다.") .build(); } + + public CartResponse getCartItems(String userProviderId) { + User user = userRepository.findByProviderId(userProviderId) + .orElseThrow(() -> new NullPointerException()); + + List carts = cartRepository.findAllByUser(user); + + if (carts.isEmpty()) { + return CartResponse.of(List.of(), 0); + } + + List cartItems = carts.stream() + .map(cart -> GetCartItemsResponse.of( + cart.getMenu().getName(), + cart.getMenu().getDescription(), + cart.getQuantity(), + cart.getMenu().getPrice() + )) + .toList(); + + int discountAmount = 0; + CartResponse cartResponse = CartResponse.of(cartItems, discountAmount); + + return cartResponse; + } } diff --git a/src/main/java/com/jangburich/domain/order/domain/repository/CartRepository.java b/src/main/java/com/jangburich/domain/order/domain/repository/CartRepository.java index 51cd8a7..3e82e3b 100644 --- a/src/main/java/com/jangburich/domain/order/domain/repository/CartRepository.java +++ b/src/main/java/com/jangburich/domain/order/domain/repository/CartRepository.java @@ -1,6 +1,8 @@ package com.jangburich.domain.order.domain.repository; import com.jangburich.domain.order.domain.Cart; +import com.jangburich.domain.user.domain.User; +import java.util.List; import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; @@ -11,4 +13,6 @@ public interface CartRepository extends JpaRepository { @Query("SELECT c FROM Cart c WHERE c.user.userId = :userId AND c.menu.id = :menuId") Optional findByUserIdAndMenuId(@Param("userId") Long userId, @Param("menuId") Long menuId); + + List findAllByUser(User user); } diff --git a/src/main/java/com/jangburich/domain/order/dto/response/CartResponse.java b/src/main/java/com/jangburich/domain/order/dto/response/CartResponse.java new file mode 100644 index 0000000..2cb6307 --- /dev/null +++ b/src/main/java/com/jangburich/domain/order/dto/response/CartResponse.java @@ -0,0 +1,33 @@ +package com.jangburich.domain.order.dto.response; + +import java.util.List; + +public record CartResponse( + List cartItems, + Integer totalAmount, + Integer discountAmount, + Integer finalAmount +) { + public static CartResponse of(List cartItems, Integer discountAmount) { + int totalAmount = cartItems.stream() + .mapToInt(item -> item.menuPrice * item.quantity) + .sum(); + + discountAmount = 0; + + int finalAmount = totalAmount - discountAmount; + + return new CartResponse(cartItems, totalAmount, discountAmount, finalAmount); + } + + public record GetCartItemsResponse( + String menuName, + String menuDescription, + Integer quantity, + Integer menuPrice + ) { + public static GetCartItemsResponse of(String menuName, String menuDescription, Integer quantity, Integer menuPrice) { + return new GetCartItemsResponse(menuName, menuDescription, quantity, menuPrice); + } + } +} diff --git a/src/main/java/com/jangburich/domain/order/presentation/OrderController.java b/src/main/java/com/jangburich/domain/order/presentation/OrderController.java index e403e6a..914e958 100644 --- a/src/main/java/com/jangburich/domain/order/presentation/OrderController.java +++ b/src/main/java/com/jangburich/domain/order/presentation/OrderController.java @@ -2,6 +2,7 @@ import com.jangburich.domain.order.application.OrderService; import com.jangburich.domain.order.dto.request.AddCartRequest; +import com.jangburich.domain.order.dto.response.CartResponse; import com.jangburich.global.payload.Message; import com.jangburich.global.payload.ResponseCustom; import com.jangburich.utils.parser.AuthenticationParser; @@ -9,6 +10,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.security.core.Authentication; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -23,11 +25,19 @@ public class OrderController { private final OrderService orderService; @Operation(summary = "장바구니 담기", description = "장바구니에 물건과 수량을 담습니다.") - @PostMapping("/cart") + @PostMapping("/carts") public ResponseCustom addCart( Authentication authentication, @RequestBody AddCartRequest addCartRequest ) { return ResponseCustom.OK(orderService.addCart(AuthenticationParser.parseUserId(authentication), addCartRequest)); } + + @Operation(summary = "장바구니 조회", description = "장바구니에 담은 상품을 조회합니다.") + @GetMapping("/carts") + public ResponseCustom getCartItems( + Authentication authentication + ) { + return ResponseCustom.OK(orderService.getCartItems(AuthenticationParser.parseUserId(authentication))); + } } From 2b91377b3c91574b160d42b4f3ec4364263a67a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9E=AC=ED=98=81?= Date: Tue, 19 Nov 2024 15:36:54 +0900 Subject: [PATCH 2/4] =?UTF-8?q?feat:=20=EC=83=81=ED=92=88=20=EC=A3=BC?= =?UTF-8?q?=EB=AC=B8=EA=B3=BC=20=EC=8B=9D=EA=B6=8C=20=EC=82=AC=EC=9A=A9=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84(=EC=83=81=ED=92=88=20?= =?UTF-8?q?=EC=A3=BC=EB=AC=B8=20=EC=8B=9C=20=ED=8F=AC=EC=9D=B8=ED=8A=B8=20?= =?UTF-8?q?=EC=86=8C=EB=AA=A8=EB=8A=94=20todo)=20(#45)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 장바구니 추가 기능 구현 * feat: 장바구니 조회 기능 구현 * feat: 상품 주문과 식권 사용 기능 구현 --- .../jangburich/domain/common/BaseEntity.java | 4 + .../order/application/OrderService.java | 103 +++++++++++++++++- .../jangburich/domain/order/domain/Cart.java | 6 +- .../domain/order/domain/Orders.java | 15 +++ .../domain/repository/CartRepository.java | 6 +- .../order/dto/request/OrderRequest.java | 15 +++ .../order/dto/response/CartResponse.java | 12 +- .../dto/response/GetCartItemsResponse.java | 13 +++ .../order/presentation/OrderController.java | 21 +++- 9 files changed, 178 insertions(+), 17 deletions(-) create mode 100644 src/main/java/com/jangburich/domain/order/dto/request/OrderRequest.java create mode 100644 src/main/java/com/jangburich/domain/order/dto/response/GetCartItemsResponse.java diff --git a/src/main/java/com/jangburich/domain/common/BaseEntity.java b/src/main/java/com/jangburich/domain/common/BaseEntity.java index f724af1..ee3568c 100644 --- a/src/main/java/com/jangburich/domain/common/BaseEntity.java +++ b/src/main/java/com/jangburich/domain/common/BaseEntity.java @@ -26,4 +26,8 @@ public abstract class BaseEntity { @Enumerated(value = EnumType.STRING) @Column(name = "status") private Status status = Status.ACTIVE; + + public void updateStatus(Status status) { + this.status = status; + } } diff --git a/src/main/java/com/jangburich/domain/order/application/OrderService.java b/src/main/java/com/jangburich/domain/order/application/OrderService.java index 87c6a6f..43ac3bb 100644 --- a/src/main/java/com/jangburich/domain/order/application/OrderService.java +++ b/src/main/java/com/jangburich/domain/order/application/OrderService.java @@ -1,14 +1,21 @@ package com.jangburich.domain.order.application; +import com.amazonaws.services.kms.model.NotFoundException; +import com.jangburich.domain.common.Status; import com.jangburich.domain.menu.domain.Menu; import com.jangburich.domain.menu.domain.repository.MenuRepository; import com.jangburich.domain.order.domain.Cart; +import com.jangburich.domain.order.domain.Orders; import com.jangburich.domain.order.domain.repository.CartRepository; +import com.jangburich.domain.order.domain.repository.OrdersRepository; import com.jangburich.domain.order.dto.request.AddCartRequest; +import com.jangburich.domain.order.dto.request.OrderRequest; import com.jangburich.domain.order.dto.response.CartResponse; -import com.jangburich.domain.order.dto.response.CartResponse.GetCartItemsResponse; +import com.jangburich.domain.order.dto.response.GetCartItemsResponse; import com.jangburich.domain.store.domain.Store; import com.jangburich.domain.store.domain.repository.StoreRepository; +import com.jangburich.domain.team.domain.Team; +import com.jangburich.domain.team.domain.repository.TeamRepository; import com.jangburich.domain.user.domain.User; import com.jangburich.domain.user.domain.repository.UserRepository; import com.jangburich.global.payload.Message; @@ -27,6 +34,8 @@ public class OrderService { private final UserRepository userRepository; private final MenuRepository menuRepository; private final StoreRepository storeRepository; + private final OrdersRepository ordersRepository; + private final TeamRepository teamRepository; @Transactional public Message addCart(String userProviderId, AddCartRequest addCartRequest) { @@ -46,7 +55,7 @@ public Message addCart(String userProviderId, AddCartRequest addCartRequest) { if (optionalCart.isPresent()) { Cart existingCart = optionalCart.get(); - existingCart.updateQuantity(addCartRequest.quantity()); + existingCart.updateQuantity(existingCart.getQuantity() + addCartRequest.quantity()); return Message.builder() .message("장바구니에 상품을 추가했습니다.") @@ -72,7 +81,7 @@ public CartResponse getCartItems(String userProviderId) { User user = userRepository.findByProviderId(userProviderId) .orElseThrow(() -> new NullPointerException()); - List carts = cartRepository.findAllByUser(user); + List carts = cartRepository.findAllByUserAndStatus(user, Status.ACTIVE); if (carts.isEmpty()) { return CartResponse.of(List.of(), 0); @@ -92,4 +101,92 @@ public CartResponse getCartItems(String userProviderId) { return cartResponse; } + + @Transactional + public Message order(String userProviderId, OrderRequest orderRequest) { + User user = userRepository.findByProviderId(userProviderId) + .orElseThrow(() -> new NullPointerException()); + + Store store = storeRepository.findById(orderRequest.storeId()) + .orElseThrow(() -> new IllegalArgumentException("유효하지 않은 가게 id 입니다.")); + + Team team = teamRepository.findById(orderRequest.teamId()) + .orElseThrow(() -> new IllegalArgumentException("유효하지 않은 그룹 id 입니다.")); + + List existingCarts = cartRepository.findAllByUserAndStore(user, store); + + List mergedCarts = mergeCarts(existingCarts, orderRequest.items(), user, store); + + + Orders orders = saveOrder(user, store, team, orderRequest); + + associateCartsWithOrder(mergedCarts, orders); + + cartRepository.saveAll(mergedCarts); + + return Message.builder() + .message("주문이 완료되었습니다.") + .build(); + } + + private List mergeCarts(List existingCarts, List items, User user, Store store) { + for (OrderRequest.OrderItemRequest item : items) { + Optional existingCart = findCartByMenuId(existingCarts, item.menuId()); + if (existingCart.isPresent()) { + existingCart.get().updateQuantity(existingCart.get().getQuantity() + item.quantity()); + existingCart.get().updateStatus(Status.INACTIVE); + continue; + } + Cart newCart = createNewCart(item, user, store); + existingCarts.add(newCart); + } + return existingCarts; + } + + private Optional findCartByMenuId(List carts, Long menuId) { + return carts.stream() + .filter(cart -> cart.getMenu().getId().equals(menuId)) + .findFirst(); + } + + private Cart createNewCart(OrderRequest.OrderItemRequest item, User user, Store store) { + Menu menu = menuRepository.findById(item.menuId()) + .orElseThrow(() -> new IllegalArgumentException("유효하지 않은 메뉴 ID입니다.")); + return Cart.builder() + .quantity(item.quantity()) + .menu(menu) + .user(user) + .store(store) + .orders(null) + .build(); + } + + private Orders saveOrder(User user, Store store, Team team, OrderRequest orderRequest) { + Orders orders = Orders.builder() + .store(store) + .user(user) + .team(team) + .build(); + return ordersRepository.save(orders); + } + + private void associateCartsWithOrder(List carts, Orders orders) { + carts.forEach(cart -> cart.updateOrders(orders)); + } + + public Message useMealTicket(String userProviderId, Long orderId) { + User user = userRepository.findByProviderId(userProviderId) + .orElseThrow(() -> new NullPointerException()); + + Orders orders = ordersRepository.findById(orderId) + .orElseThrow(() -> new NotFoundException("식권을 찾을 수 없습니다")); + + orders.validateUser(user); + + orders.updateStatus(Status.INACTIVE); + + return Message.builder() + .message("식권을 사용했습니다.") + .build(); + } } diff --git a/src/main/java/com/jangburich/domain/order/domain/Cart.java b/src/main/java/com/jangburich/domain/order/domain/Cart.java index 0be2f63..abbd1c3 100644 --- a/src/main/java/com/jangburich/domain/order/domain/Cart.java +++ b/src/main/java/com/jangburich/domain/order/domain/Cart.java @@ -58,6 +58,10 @@ public Cart(Integer quantity, Orders orders, Menu menu, User user, Store store) } public void updateQuantity(int quantity) { - this.quantity += quantity; + this.quantity = quantity; + } + + public void updateOrders(Orders orders) { + this.orders = orders; } } diff --git a/src/main/java/com/jangburich/domain/order/domain/Orders.java b/src/main/java/com/jangburich/domain/order/domain/Orders.java index 260ab2a..621f0a9 100644 --- a/src/main/java/com/jangburich/domain/order/domain/Orders.java +++ b/src/main/java/com/jangburich/domain/order/domain/Orders.java @@ -13,6 +13,7 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import lombok.AccessLevel; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @@ -37,4 +38,18 @@ public class Orders extends BaseEntity { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "team_id") private Team team; + + + @Builder + public Orders(Store store, User user, Team team) { + this.store = store; + this.user = user; + this.team = team; + } + + public void validateUser(User user) { + if (!this.user.equals(user)) { + throw new IllegalArgumentException("유저 정보가 일치하지 않습니다."); + } + } } diff --git a/src/main/java/com/jangburich/domain/order/domain/repository/CartRepository.java b/src/main/java/com/jangburich/domain/order/domain/repository/CartRepository.java index 3e82e3b..a21d4e7 100644 --- a/src/main/java/com/jangburich/domain/order/domain/repository/CartRepository.java +++ b/src/main/java/com/jangburich/domain/order/domain/repository/CartRepository.java @@ -1,6 +1,8 @@ package com.jangburich.domain.order.domain.repository; +import com.jangburich.domain.common.Status; import com.jangburich.domain.order.domain.Cart; +import com.jangburich.domain.store.domain.Store; import com.jangburich.domain.user.domain.User; import java.util.List; import java.util.Optional; @@ -14,5 +16,7 @@ public interface CartRepository extends JpaRepository { @Query("SELECT c FROM Cart c WHERE c.user.userId = :userId AND c.menu.id = :menuId") Optional findByUserIdAndMenuId(@Param("userId") Long userId, @Param("menuId") Long menuId); - List findAllByUser(User user); + List findAllByUserAndStore(User user, Store store); + + List findAllByUserAndStatus(User user, Status status); } diff --git a/src/main/java/com/jangburich/domain/order/dto/request/OrderRequest.java b/src/main/java/com/jangburich/domain/order/dto/request/OrderRequest.java new file mode 100644 index 0000000..06eb1cd --- /dev/null +++ b/src/main/java/com/jangburich/domain/order/dto/request/OrderRequest.java @@ -0,0 +1,15 @@ +package com.jangburich.domain.order.dto.request; + +import java.util.List; + +public record OrderRequest( + Long storeId, + Long teamId, + List items +) { + public static record OrderItemRequest( + Long menuId, + Integer quantity + ) { + } +} diff --git a/src/main/java/com/jangburich/domain/order/dto/response/CartResponse.java b/src/main/java/com/jangburich/domain/order/dto/response/CartResponse.java index 2cb6307..08df2e6 100644 --- a/src/main/java/com/jangburich/domain/order/dto/response/CartResponse.java +++ b/src/main/java/com/jangburich/domain/order/dto/response/CartResponse.java @@ -10,7 +10,7 @@ public record CartResponse( ) { public static CartResponse of(List cartItems, Integer discountAmount) { int totalAmount = cartItems.stream() - .mapToInt(item -> item.menuPrice * item.quantity) + .mapToInt(item -> item.menuPrice() * item.quantity()) .sum(); discountAmount = 0; @@ -20,14 +20,4 @@ public static CartResponse of(List cartItems, Integer disc return new CartResponse(cartItems, totalAmount, discountAmount, finalAmount); } - public record GetCartItemsResponse( - String menuName, - String menuDescription, - Integer quantity, - Integer menuPrice - ) { - public static GetCartItemsResponse of(String menuName, String menuDescription, Integer quantity, Integer menuPrice) { - return new GetCartItemsResponse(menuName, menuDescription, quantity, menuPrice); - } - } } diff --git a/src/main/java/com/jangburich/domain/order/dto/response/GetCartItemsResponse.java b/src/main/java/com/jangburich/domain/order/dto/response/GetCartItemsResponse.java new file mode 100644 index 0000000..1c0b120 --- /dev/null +++ b/src/main/java/com/jangburich/domain/order/dto/response/GetCartItemsResponse.java @@ -0,0 +1,13 @@ +package com.jangburich.domain.order.dto.response; + +public record GetCartItemsResponse( + String menuName, + String menuDescription, + Integer quantity, + Integer menuPrice +) { + public static GetCartItemsResponse of(String menuName, String menuDescription, Integer quantity, + Integer menuPrice) { + return new GetCartItemsResponse(menuName, menuDescription, quantity, menuPrice); + } +} diff --git a/src/main/java/com/jangburich/domain/order/presentation/OrderController.java b/src/main/java/com/jangburich/domain/order/presentation/OrderController.java index 914e958..b6f53a1 100644 --- a/src/main/java/com/jangburich/domain/order/presentation/OrderController.java +++ b/src/main/java/com/jangburich/domain/order/presentation/OrderController.java @@ -2,6 +2,7 @@ import com.jangburich.domain.order.application.OrderService; import com.jangburich.domain.order.dto.request.AddCartRequest; +import com.jangburich.domain.order.dto.request.OrderRequest; import com.jangburich.domain.order.dto.response.CartResponse; import com.jangburich.global.payload.Message; import com.jangburich.global.payload.ResponseCustom; @@ -11,6 +12,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.security.core.Authentication; import org.springframework.web.bind.annotation.GetMapping; +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.RequestMapping; @@ -40,4 +42,21 @@ public ResponseCustom getCartItems( ) { return ResponseCustom.OK(orderService.getCartItems(AuthenticationParser.parseUserId(authentication))); } -} + + @Operation(summary = "상품 주문", description = "상품을 주문합니다.") + @PostMapping + public ResponseCustom order( + Authentication authentication, + @RequestBody OrderRequest orderRequest + ) { + return ResponseCustom.OK(orderService.order(AuthenticationParser.parseUserId(authentication), orderRequest)); + } + + @Operation(summary = "식권 사용", description = "식권을 사용합니다.") + public ResponseCustom useMealTicket( + Authentication authentication, + @PathVariable Long orderId + ) { + return ResponseCustom.OK(orderService.useMealTicket(AuthenticationParser.parseUserId(authentication), orderId)); + } +} \ No newline at end of file From 46919745bc820994dbb1f94ad283c3334977d335 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EC=9E=AC=ED=98=81?= Date: Tue, 19 Nov 2024 15:38:23 +0900 Subject: [PATCH 3/4] =?UTF-8?q?feat:=20=EC=83=81=ED=92=88=20=EC=A3=BC?= =?UTF-8?q?=EB=AC=B8=EA=B3=BC=20=EC=8B=9D=EA=B6=8C=20=EC=82=AC=EC=9A=A9=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84=20(#46)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 장바구니 추가 기능 구현 (#41) * feat: 장바구니 조회 기능 구현 (#43) * feat: 장바구니 추가 기능 구현 * feat: 장바구니 조회 기능 구현 * feat: 상품 주문과 식권 사용 기능 구현(상품 주문 시 포인트 소모는 todo) (#45) * feat: 장바구니 추가 기능 구현 * feat: 장바구니 조회 기능 구현 * feat: 상품 주문과 식권 사용 기능 구현 --- .../jangburich/domain/common/BaseEntity.java | 4 + .../order/application/OrderService.java | 103 +++++++++++++++++- .../jangburich/domain/order/domain/Cart.java | 6 +- .../domain/order/domain/Orders.java | 15 +++ .../domain/repository/CartRepository.java | 6 +- .../order/dto/request/OrderRequest.java | 15 +++ .../order/dto/response/CartResponse.java | 12 +- .../dto/response/GetCartItemsResponse.java | 13 +++ .../order/presentation/OrderController.java | 21 +++- 9 files changed, 178 insertions(+), 17 deletions(-) create mode 100644 src/main/java/com/jangburich/domain/order/dto/request/OrderRequest.java create mode 100644 src/main/java/com/jangburich/domain/order/dto/response/GetCartItemsResponse.java diff --git a/src/main/java/com/jangburich/domain/common/BaseEntity.java b/src/main/java/com/jangburich/domain/common/BaseEntity.java index f724af1..ee3568c 100644 --- a/src/main/java/com/jangburich/domain/common/BaseEntity.java +++ b/src/main/java/com/jangburich/domain/common/BaseEntity.java @@ -26,4 +26,8 @@ public abstract class BaseEntity { @Enumerated(value = EnumType.STRING) @Column(name = "status") private Status status = Status.ACTIVE; + + public void updateStatus(Status status) { + this.status = status; + } } diff --git a/src/main/java/com/jangburich/domain/order/application/OrderService.java b/src/main/java/com/jangburich/domain/order/application/OrderService.java index 87c6a6f..43ac3bb 100644 --- a/src/main/java/com/jangburich/domain/order/application/OrderService.java +++ b/src/main/java/com/jangburich/domain/order/application/OrderService.java @@ -1,14 +1,21 @@ package com.jangburich.domain.order.application; +import com.amazonaws.services.kms.model.NotFoundException; +import com.jangburich.domain.common.Status; import com.jangburich.domain.menu.domain.Menu; import com.jangburich.domain.menu.domain.repository.MenuRepository; import com.jangburich.domain.order.domain.Cart; +import com.jangburich.domain.order.domain.Orders; import com.jangburich.domain.order.domain.repository.CartRepository; +import com.jangburich.domain.order.domain.repository.OrdersRepository; import com.jangburich.domain.order.dto.request.AddCartRequest; +import com.jangburich.domain.order.dto.request.OrderRequest; import com.jangburich.domain.order.dto.response.CartResponse; -import com.jangburich.domain.order.dto.response.CartResponse.GetCartItemsResponse; +import com.jangburich.domain.order.dto.response.GetCartItemsResponse; import com.jangburich.domain.store.domain.Store; import com.jangburich.domain.store.domain.repository.StoreRepository; +import com.jangburich.domain.team.domain.Team; +import com.jangburich.domain.team.domain.repository.TeamRepository; import com.jangburich.domain.user.domain.User; import com.jangburich.domain.user.domain.repository.UserRepository; import com.jangburich.global.payload.Message; @@ -27,6 +34,8 @@ public class OrderService { private final UserRepository userRepository; private final MenuRepository menuRepository; private final StoreRepository storeRepository; + private final OrdersRepository ordersRepository; + private final TeamRepository teamRepository; @Transactional public Message addCart(String userProviderId, AddCartRequest addCartRequest) { @@ -46,7 +55,7 @@ public Message addCart(String userProviderId, AddCartRequest addCartRequest) { if (optionalCart.isPresent()) { Cart existingCart = optionalCart.get(); - existingCart.updateQuantity(addCartRequest.quantity()); + existingCart.updateQuantity(existingCart.getQuantity() + addCartRequest.quantity()); return Message.builder() .message("장바구니에 상품을 추가했습니다.") @@ -72,7 +81,7 @@ public CartResponse getCartItems(String userProviderId) { User user = userRepository.findByProviderId(userProviderId) .orElseThrow(() -> new NullPointerException()); - List carts = cartRepository.findAllByUser(user); + List carts = cartRepository.findAllByUserAndStatus(user, Status.ACTIVE); if (carts.isEmpty()) { return CartResponse.of(List.of(), 0); @@ -92,4 +101,92 @@ public CartResponse getCartItems(String userProviderId) { return cartResponse; } + + @Transactional + public Message order(String userProviderId, OrderRequest orderRequest) { + User user = userRepository.findByProviderId(userProviderId) + .orElseThrow(() -> new NullPointerException()); + + Store store = storeRepository.findById(orderRequest.storeId()) + .orElseThrow(() -> new IllegalArgumentException("유효하지 않은 가게 id 입니다.")); + + Team team = teamRepository.findById(orderRequest.teamId()) + .orElseThrow(() -> new IllegalArgumentException("유효하지 않은 그룹 id 입니다.")); + + List existingCarts = cartRepository.findAllByUserAndStore(user, store); + + List mergedCarts = mergeCarts(existingCarts, orderRequest.items(), user, store); + + + Orders orders = saveOrder(user, store, team, orderRequest); + + associateCartsWithOrder(mergedCarts, orders); + + cartRepository.saveAll(mergedCarts); + + return Message.builder() + .message("주문이 완료되었습니다.") + .build(); + } + + private List mergeCarts(List existingCarts, List items, User user, Store store) { + for (OrderRequest.OrderItemRequest item : items) { + Optional existingCart = findCartByMenuId(existingCarts, item.menuId()); + if (existingCart.isPresent()) { + existingCart.get().updateQuantity(existingCart.get().getQuantity() + item.quantity()); + existingCart.get().updateStatus(Status.INACTIVE); + continue; + } + Cart newCart = createNewCart(item, user, store); + existingCarts.add(newCart); + } + return existingCarts; + } + + private Optional findCartByMenuId(List carts, Long menuId) { + return carts.stream() + .filter(cart -> cart.getMenu().getId().equals(menuId)) + .findFirst(); + } + + private Cart createNewCart(OrderRequest.OrderItemRequest item, User user, Store store) { + Menu menu = menuRepository.findById(item.menuId()) + .orElseThrow(() -> new IllegalArgumentException("유효하지 않은 메뉴 ID입니다.")); + return Cart.builder() + .quantity(item.quantity()) + .menu(menu) + .user(user) + .store(store) + .orders(null) + .build(); + } + + private Orders saveOrder(User user, Store store, Team team, OrderRequest orderRequest) { + Orders orders = Orders.builder() + .store(store) + .user(user) + .team(team) + .build(); + return ordersRepository.save(orders); + } + + private void associateCartsWithOrder(List carts, Orders orders) { + carts.forEach(cart -> cart.updateOrders(orders)); + } + + public Message useMealTicket(String userProviderId, Long orderId) { + User user = userRepository.findByProviderId(userProviderId) + .orElseThrow(() -> new NullPointerException()); + + Orders orders = ordersRepository.findById(orderId) + .orElseThrow(() -> new NotFoundException("식권을 찾을 수 없습니다")); + + orders.validateUser(user); + + orders.updateStatus(Status.INACTIVE); + + return Message.builder() + .message("식권을 사용했습니다.") + .build(); + } } diff --git a/src/main/java/com/jangburich/domain/order/domain/Cart.java b/src/main/java/com/jangburich/domain/order/domain/Cart.java index 0be2f63..abbd1c3 100644 --- a/src/main/java/com/jangburich/domain/order/domain/Cart.java +++ b/src/main/java/com/jangburich/domain/order/domain/Cart.java @@ -58,6 +58,10 @@ public Cart(Integer quantity, Orders orders, Menu menu, User user, Store store) } public void updateQuantity(int quantity) { - this.quantity += quantity; + this.quantity = quantity; + } + + public void updateOrders(Orders orders) { + this.orders = orders; } } diff --git a/src/main/java/com/jangburich/domain/order/domain/Orders.java b/src/main/java/com/jangburich/domain/order/domain/Orders.java index 260ab2a..621f0a9 100644 --- a/src/main/java/com/jangburich/domain/order/domain/Orders.java +++ b/src/main/java/com/jangburich/domain/order/domain/Orders.java @@ -13,6 +13,7 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import lombok.AccessLevel; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @@ -37,4 +38,18 @@ public class Orders extends BaseEntity { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "team_id") private Team team; + + + @Builder + public Orders(Store store, User user, Team team) { + this.store = store; + this.user = user; + this.team = team; + } + + public void validateUser(User user) { + if (!this.user.equals(user)) { + throw new IllegalArgumentException("유저 정보가 일치하지 않습니다."); + } + } } diff --git a/src/main/java/com/jangburich/domain/order/domain/repository/CartRepository.java b/src/main/java/com/jangburich/domain/order/domain/repository/CartRepository.java index 3e82e3b..a21d4e7 100644 --- a/src/main/java/com/jangburich/domain/order/domain/repository/CartRepository.java +++ b/src/main/java/com/jangburich/domain/order/domain/repository/CartRepository.java @@ -1,6 +1,8 @@ package com.jangburich.domain.order.domain.repository; +import com.jangburich.domain.common.Status; import com.jangburich.domain.order.domain.Cart; +import com.jangburich.domain.store.domain.Store; import com.jangburich.domain.user.domain.User; import java.util.List; import java.util.Optional; @@ -14,5 +16,7 @@ public interface CartRepository extends JpaRepository { @Query("SELECT c FROM Cart c WHERE c.user.userId = :userId AND c.menu.id = :menuId") Optional findByUserIdAndMenuId(@Param("userId") Long userId, @Param("menuId") Long menuId); - List findAllByUser(User user); + List findAllByUserAndStore(User user, Store store); + + List findAllByUserAndStatus(User user, Status status); } diff --git a/src/main/java/com/jangburich/domain/order/dto/request/OrderRequest.java b/src/main/java/com/jangburich/domain/order/dto/request/OrderRequest.java new file mode 100644 index 0000000..06eb1cd --- /dev/null +++ b/src/main/java/com/jangburich/domain/order/dto/request/OrderRequest.java @@ -0,0 +1,15 @@ +package com.jangburich.domain.order.dto.request; + +import java.util.List; + +public record OrderRequest( + Long storeId, + Long teamId, + List items +) { + public static record OrderItemRequest( + Long menuId, + Integer quantity + ) { + } +} diff --git a/src/main/java/com/jangburich/domain/order/dto/response/CartResponse.java b/src/main/java/com/jangburich/domain/order/dto/response/CartResponse.java index 2cb6307..08df2e6 100644 --- a/src/main/java/com/jangburich/domain/order/dto/response/CartResponse.java +++ b/src/main/java/com/jangburich/domain/order/dto/response/CartResponse.java @@ -10,7 +10,7 @@ public record CartResponse( ) { public static CartResponse of(List cartItems, Integer discountAmount) { int totalAmount = cartItems.stream() - .mapToInt(item -> item.menuPrice * item.quantity) + .mapToInt(item -> item.menuPrice() * item.quantity()) .sum(); discountAmount = 0; @@ -20,14 +20,4 @@ public static CartResponse of(List cartItems, Integer disc return new CartResponse(cartItems, totalAmount, discountAmount, finalAmount); } - public record GetCartItemsResponse( - String menuName, - String menuDescription, - Integer quantity, - Integer menuPrice - ) { - public static GetCartItemsResponse of(String menuName, String menuDescription, Integer quantity, Integer menuPrice) { - return new GetCartItemsResponse(menuName, menuDescription, quantity, menuPrice); - } - } } diff --git a/src/main/java/com/jangburich/domain/order/dto/response/GetCartItemsResponse.java b/src/main/java/com/jangburich/domain/order/dto/response/GetCartItemsResponse.java new file mode 100644 index 0000000..1c0b120 --- /dev/null +++ b/src/main/java/com/jangburich/domain/order/dto/response/GetCartItemsResponse.java @@ -0,0 +1,13 @@ +package com.jangburich.domain.order.dto.response; + +public record GetCartItemsResponse( + String menuName, + String menuDescription, + Integer quantity, + Integer menuPrice +) { + public static GetCartItemsResponse of(String menuName, String menuDescription, Integer quantity, + Integer menuPrice) { + return new GetCartItemsResponse(menuName, menuDescription, quantity, menuPrice); + } +} diff --git a/src/main/java/com/jangburich/domain/order/presentation/OrderController.java b/src/main/java/com/jangburich/domain/order/presentation/OrderController.java index 914e958..b6f53a1 100644 --- a/src/main/java/com/jangburich/domain/order/presentation/OrderController.java +++ b/src/main/java/com/jangburich/domain/order/presentation/OrderController.java @@ -2,6 +2,7 @@ import com.jangburich.domain.order.application.OrderService; import com.jangburich.domain.order.dto.request.AddCartRequest; +import com.jangburich.domain.order.dto.request.OrderRequest; import com.jangburich.domain.order.dto.response.CartResponse; import com.jangburich.global.payload.Message; import com.jangburich.global.payload.ResponseCustom; @@ -11,6 +12,7 @@ import lombok.RequiredArgsConstructor; import org.springframework.security.core.Authentication; import org.springframework.web.bind.annotation.GetMapping; +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.RequestMapping; @@ -40,4 +42,21 @@ public ResponseCustom getCartItems( ) { return ResponseCustom.OK(orderService.getCartItems(AuthenticationParser.parseUserId(authentication))); } -} + + @Operation(summary = "상품 주문", description = "상품을 주문합니다.") + @PostMapping + public ResponseCustom order( + Authentication authentication, + @RequestBody OrderRequest orderRequest + ) { + return ResponseCustom.OK(orderService.order(AuthenticationParser.parseUserId(authentication), orderRequest)); + } + + @Operation(summary = "식권 사용", description = "식권을 사용합니다.") + public ResponseCustom useMealTicket( + Authentication authentication, + @PathVariable Long orderId + ) { + return ResponseCustom.OK(orderService.useMealTicket(AuthenticationParser.parseUserId(authentication), orderId)); + } +} \ No newline at end of file From dfc32b8c5a836eaff836c52a3c27d3cab4c1b5d5 Mon Sep 17 00:00:00 2001 From: HyunWoo9930 Date: Tue, 19 Nov 2024 19:54:09 +0900 Subject: [PATCH 4/4] =?UTF-8?q?fix=20:=20=EC=B9=B4=EC=B9=B4=EC=98=A4=20?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EB=A1=9C=EC=A7=81=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../domain/controller/MenuController.java | 28 +-- .../menu/domain/service/MenuService.java | 19 +- .../domain/service/OAuthUserService.java | 226 +++++++++--------- .../order/application/OrderService.java | 2 +- .../order/presentation/OrderController.java | 88 +++---- .../domain/controller/OwnerController.java | 20 +- .../owner/domain/service/OwnerService.java | 11 +- .../presentation/PaymentController.java | 12 +- .../jangburich/domain/store/domain/Store.java | 6 + .../domain/controller/StoreController.java | 62 ++--- .../store/domain/service/StoreService.java | 30 +-- .../domain/team/application/TeamService.java | 96 ++++---- .../team/presentation/TeamController.java | 50 ++-- .../{domain => }/controller/HealthCheck.java | 2 +- .../user/controller/UserController.java | 89 +++++++ .../user/domain/KakaoApiResponseDTO.java | 77 ++++++ .../jangburich/domain/user/domain/User.java | 3 +- .../user/domain/service/UserService.java | 12 - .../repository/UserRepository.java | 2 +- .../domain/user/service/UserService.java | 70 ++++++ .../jangburich/global/GetAuthorization.java | 25 ++ .../config/security/SecurityConfig.java | 39 +-- .../global/config/security/SwaggerConfig.java | 11 +- .../utils/AuthorizationHeaderFilter.java | 25 ++ .../CustomAuthorizationRequestResolver.java | 44 ---- .../utils/CustomSuccessHandler.java | 51 ---- .../java/com/jangburich/utils/JwtFilter.java | 77 ------ .../java/com/jangburich/utils/JwtUtil.java | 59 ----- 28 files changed, 637 insertions(+), 599 deletions(-) rename src/main/java/com/jangburich/domain/user/{domain => }/controller/HealthCheck.java (82%) create mode 100644 src/main/java/com/jangburich/domain/user/controller/UserController.java create mode 100644 src/main/java/com/jangburich/domain/user/domain/KakaoApiResponseDTO.java delete mode 100644 src/main/java/com/jangburich/domain/user/domain/service/UserService.java rename src/main/java/com/jangburich/domain/user/{domain => }/repository/UserRepository.java (85%) create mode 100644 src/main/java/com/jangburich/domain/user/service/UserService.java create mode 100644 src/main/java/com/jangburich/global/GetAuthorization.java create mode 100644 src/main/java/com/jangburich/utils/AuthorizationHeaderFilter.java delete mode 100644 src/main/java/com/jangburich/utils/CustomAuthorizationRequestResolver.java delete mode 100644 src/main/java/com/jangburich/utils/CustomSuccessHandler.java delete mode 100644 src/main/java/com/jangburich/utils/JwtFilter.java delete mode 100644 src/main/java/com/jangburich/utils/JwtUtil.java diff --git a/src/main/java/com/jangburich/domain/menu/domain/controller/MenuController.java b/src/main/java/com/jangburich/domain/menu/domain/controller/MenuController.java index 8250686..95f55c7 100644 --- a/src/main/java/com/jangburich/domain/menu/domain/controller/MenuController.java +++ b/src/main/java/com/jangburich/domain/menu/domain/controller/MenuController.java @@ -2,12 +2,12 @@ import java.util.List; -import org.springframework.security.core.Authentication; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestAttribute; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -16,7 +16,7 @@ import com.jangburich.domain.menu.domain.MenuGetResponseDTO; import com.jangburich.domain.menu.domain.MenuUpdateRequestDTO; import com.jangburich.domain.menu.domain.service.MenuService; -import com.jangburich.domain.oauth.domain.CustomOAuthUser; +import com.jangburich.global.GetAuthorization; import com.jangburich.global.payload.Message; import com.jangburich.global.payload.ResponseCustom; @@ -32,32 +32,32 @@ public class MenuController { private final MenuService menuService; @PostMapping("/register") - public ResponseCustom registerMenu(Authentication authentication, + public ResponseCustom registerMenu( + @RequestAttribute(value = "authorizationHeader") String authorizationHeader, @RequestBody MenuCreateRequestDTO menuCreateRequestDTO) { - CustomOAuthUser customOAuthUser = (CustomOAuthUser)authentication.getPrincipal(); - menuService.registerMenu(customOAuthUser, menuCreateRequestDTO); + menuService.registerMenu(GetAuthorization.getUserId(authorizationHeader), menuCreateRequestDTO); return ResponseCustom.OK(Message.builder().message("success").build()); } @PatchMapping("/update/{id}") - public ResponseCustom updateMenu(Authentication authentication, @PathVariable Long id, + public ResponseCustom updateMenu( + @RequestAttribute(value = "authorizationHeader") String authorizationHeader, @PathVariable Long id, @RequestBody MenuUpdateRequestDTO menuUpdateRequestDTO) { - CustomOAuthUser customOAuthUser = (CustomOAuthUser)authentication.getPrincipal(); - menuService.updateMenu(customOAuthUser, id, menuUpdateRequestDTO); + menuService.updateMenu(GetAuthorization.getUserId(authorizationHeader), id, menuUpdateRequestDTO); return ResponseCustom.OK(Message.builder().message("success").build()); } @DeleteMapping("/{id}") - public ResponseCustom deleteMenu(Authentication authentication, @PathVariable Long id) { - CustomOAuthUser customOAuthUser = (CustomOAuthUser)authentication.getPrincipal(); - menuService.deleteMenu(customOAuthUser, id); + public ResponseCustom deleteMenu( + @RequestAttribute(value = "authorizationHeader") String authorizationHeader, @PathVariable Long id) { + menuService.deleteMenu(GetAuthorization.getUserId(authorizationHeader), id); return ResponseCustom.OK(Message.builder().message("success").build()); } @GetMapping("") - public ResponseCustom> getMenu(Authentication authentication) { - CustomOAuthUser customOAuthUser = (CustomOAuthUser)authentication.getPrincipal(); - List menu = menuService.getMenu(customOAuthUser); + public ResponseCustom> getMenu( + @RequestAttribute(value = "authorizationHeader") String authorizationHeader) { + List menu = menuService.getMenu(GetAuthorization.getUserId(authorizationHeader)); return ResponseCustom.OK(menu); } } diff --git a/src/main/java/com/jangburich/domain/menu/domain/service/MenuService.java b/src/main/java/com/jangburich/domain/menu/domain/service/MenuService.java index 22dfc49..da07a52 100644 --- a/src/main/java/com/jangburich/domain/menu/domain/service/MenuService.java +++ b/src/main/java/com/jangburich/domain/menu/domain/service/MenuService.java @@ -10,13 +10,12 @@ import com.jangburich.domain.menu.domain.MenuGetResponseDTO; import com.jangburich.domain.menu.domain.MenuUpdateRequestDTO; import com.jangburich.domain.menu.domain.repository.MenuRepository; -import com.jangburich.domain.oauth.domain.CustomOAuthUser; import com.jangburich.domain.owner.domain.Owner; import com.jangburich.domain.owner.domain.repository.OwnerRepository; import com.jangburich.domain.store.domain.Store; import com.jangburich.domain.store.domain.repository.StoreRepository; import com.jangburich.domain.user.domain.User; -import com.jangburich.domain.user.domain.repository.UserRepository; +import com.jangburich.domain.user.repository.UserRepository; import com.jangburich.global.error.DefaultNullPointerException; import com.jangburich.global.payload.ErrorCode; @@ -31,8 +30,8 @@ public class MenuService { private final StoreRepository storeRepository; private final UserRepository userRepository; - public void registerMenu(CustomOAuthUser customOAuthUser, MenuCreateRequestDTO menuCreateRequestDTO) { - User user = userRepository.findByProviderId(customOAuthUser.getUserId()) + public void registerMenu(String customOAuthUser, MenuCreateRequestDTO menuCreateRequestDTO) { + User user = userRepository.findByProviderId(customOAuthUser) .orElseThrow(() -> new DefaultNullPointerException(ErrorCode.INVALID_AUTHENTICATION)); Owner owner = ownerRepository.findByUser(user) @@ -45,10 +44,10 @@ public void registerMenu(CustomOAuthUser customOAuthUser, MenuCreateRequestDTO m menuCreateRequestDTO.getImage_url(), menuCreateRequestDTO.getPrice(), store)); } - public void updateMenu(CustomOAuthUser customOAuthUser, Long menuId, MenuUpdateRequestDTO menuUpdateRequestDTO) { + public void updateMenu(String customOAuthUser, Long menuId, MenuUpdateRequestDTO menuUpdateRequestDTO) { Menu menu = menuRepository.findById(menuId) .orElseThrow(() -> new DefaultNullPointerException(ErrorCode.INVALID_PARAMETER)); - if (!menu.getStore().getOwner().getUser().getProviderId().equals(customOAuthUser.getUserId())) { + if (!menu.getStore().getOwner().getUser().getProviderId().equals(customOAuthUser)) { throw new DefaultNullPointerException(ErrorCode.INVALID_AUTHENTICATION); } if (menuUpdateRequestDTO.getName() != null) @@ -64,17 +63,17 @@ public void updateMenu(CustomOAuthUser customOAuthUser, Long menuId, MenuUpdateR } @Transactional - public void deleteMenu(CustomOAuthUser customOAuthUser, Long id) { + public void deleteMenu(String customOAuthUser, Long id) { Menu menu = menuRepository.findById(id) .orElseThrow(() -> new DefaultNullPointerException(ErrorCode.INVALID_PARAMETER)); - if (!menu.getStore().getOwner().getUser().getProviderId().equals(customOAuthUser.getUserId())) { + if (!menu.getStore().getOwner().getUser().getProviderId().equals(customOAuthUser)) { throw new DefaultNullPointerException(ErrorCode.INVALID_AUTHENTICATION); } menuRepository.delete(menu); } - public List getMenu(CustomOAuthUser customOAuthUser) { - User user = userRepository.findByProviderId(customOAuthUser.getUserId()) + public List getMenu(String customOAuthUser) { + User user = userRepository.findByProviderId(customOAuthUser) .orElseThrow(() -> new DefaultNullPointerException(ErrorCode.INVALID_AUTHENTICATION)); Owner owner = ownerRepository.findByUser(user) diff --git a/src/main/java/com/jangburich/domain/oauth/domain/service/OAuthUserService.java b/src/main/java/com/jangburich/domain/oauth/domain/service/OAuthUserService.java index 7049e72..0b1f6e3 100644 --- a/src/main/java/com/jangburich/domain/oauth/domain/service/OAuthUserService.java +++ b/src/main/java/com/jangburich/domain/oauth/domain/service/OAuthUserService.java @@ -1,113 +1,113 @@ -package com.jangburich.domain.oauth.domain.service; - -import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService; -import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; -import org.springframework.security.oauth2.core.OAuth2AuthenticationException; -import org.springframework.security.oauth2.core.user.OAuth2User; -import org.springframework.stereotype.Service; -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.request.ServletRequestAttributes; - -import com.jangburich.domain.oauth.domain.CustomOAuthUser; -import com.jangburich.domain.oauth.domain.KakaoResponse; -import com.jangburich.domain.oauth.domain.OAuth2Response; -import com.jangburich.domain.oauth.domain.OAuthUserDTO; -import com.jangburich.domain.owner.domain.Owner; -import com.jangburich.domain.owner.domain.repository.OwnerRepository; -import com.jangburich.domain.user.domain.User; -import com.jangburich.domain.user.domain.repository.UserRepository; - -import jakarta.servlet.http.HttpServletRequest; -import lombok.extern.slf4j.Slf4j; - -@Service -@Slf4j -public class OAuthUserService extends DefaultOAuth2UserService { - private final UserRepository userRepository; - private final OwnerRepository ownerRepository; - - public OAuthUserService(UserRepository userRepository, OwnerRepository ownerRepository) { - this.userRepository = userRepository; - this.ownerRepository = ownerRepository; - } - - @Override - public OAuth2User loadUser(OAuth2UserRequest oAuth2UserRequest) throws OAuth2AuthenticationException { - OAuth2User oAuth2User = super.loadUser(oAuth2UserRequest); - log.info("OAuth2User loaded: {}", oAuth2User.getName()); - - HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest(); - String state = (String)request.getSession().getAttribute("oauth2_state"); - request.getSession().removeAttribute("oauth2_state"); - - OAuth2Response oAuth2Response = new KakaoResponse(oAuth2User.getAttributes()); - - // String userId = oAuth2Response.getProvider() + "_" + oAuth2Response.getProviderId(); - String userId = oAuth2Response.getProviderId(); - - if ("user".equals(state)) { - User existUser = userRepository.findByProviderId(userId).orElse(null); - if (existUser == null) { - User newUser = User.create(userId, oAuth2Response.getNickname(), oAuth2Response.getImage(), - "ROLE_USER"); - userRepository.save(newUser); - - OAuthUserDTO userDTO = new OAuthUserDTO(); - userDTO.setUserId(userId); - userDTO.setNickname(oAuth2Response.getNickname()); - userDTO.setImage(oAuth2Response.getImage()); - userDTO.setRole("ROLE_USER"); - - return new CustomOAuthUser(userDTO); - } else { - existUser.setNickname(oAuth2Response.getNickname()); - existUser.setProfileImageUrl(oAuth2Response.getImage()); - - userRepository.save(existUser); - - OAuthUserDTO userDTO = new OAuthUserDTO(); - userDTO.setUserId(existUser.getProviderId()); - userDTO.setNickname(existUser.getNickname()); - userDTO.setImage(existUser.getProfileImageUrl()); - userDTO.setCreatedAt(existUser.getCreatedAt()); - userDTO.setRole("ROLE_USER"); - - return new CustomOAuthUser(userDTO); - } - } else if ("owner".equals(state)) { - User existUser = userRepository.findByProviderId(userId).orElse(null); - if (existUser == null || !existUser.getRole().equals("ROLE_OWNER")) { - User newUser = User.create(userId, oAuth2Response.getNickname(), oAuth2Response.getImage(), - "ROLE_OWNER"); - userRepository.save(newUser); - - OAuthUserDTO userDTO = new OAuthUserDTO(); - userDTO.setUserId(userId); - userDTO.setNickname(oAuth2Response.getNickname()); - userDTO.setImage(oAuth2Response.getImage()); - userDTO.setRole("ROLE_OWNER"); - - Owner newOwner = Owner.create(newUser); - newOwner.setUser(newUser); - ownerRepository.save(newOwner); - - return new CustomOAuthUser(userDTO); - } else { - existUser.setNickname(oAuth2Response.getNickname()); - existUser.setProfileImageUrl(oAuth2Response.getImage()); - - userRepository.save(existUser); - - OAuthUserDTO userDTO = new OAuthUserDTO(); - userDTO.setUserId(existUser.getProviderId()); - userDTO.setNickname(existUser.getNickname()); - userDTO.setImage(existUser.getProfileImageUrl()); - userDTO.setRole("ROLE_OWNER"); - - return new CustomOAuthUser(userDTO); - } - } else { - return null; - } - } -} +// package com.jangburich.domain.oauth.domain.service; +// +// import org.springframework.security.oauth2.client.userinfo.DefaultOAuth2UserService; +// import org.springframework.security.oauth2.client.userinfo.OAuth2UserRequest; +// import org.springframework.security.oauth2.core.OAuth2AuthenticationException; +// import org.springframework.security.oauth2.core.user.OAuth2User; +// import org.springframework.stereotype.Service; +// import org.springframework.web.context.request.RequestContextHolder; +// import org.springframework.web.context.request.ServletRequestAttributes; +// +// import com.jangburich.domain.oauth.domain.CustomOAuthUser; +// import com.jangburich.domain.oauth.domain.KakaoResponse; +// import com.jangburich.domain.oauth.domain.OAuth2Response; +// import com.jangburich.domain.oauth.domain.OAuthUserDTO; +// import com.jangburich.domain.owner.domain.Owner; +// import com.jangburich.domain.owner.domain.repository.OwnerRepository; +// import com.jangburich.domain.user.domain.User; +// import com.jangburich.domain.user.repository.UserRepository; +// +// import jakarta.servlet.http.HttpServletRequest; +// import lombok.extern.slf4j.Slf4j; +// +// @Service +// @Slf4j +// public class OAuthUserService extends DefaultOAuth2UserService { +// private final UserRepository userRepository; +// private final OwnerRepository ownerRepository; +// +// public OAuthUserService(UserRepository userRepository, OwnerRepository ownerRepository) { +// this.userRepository = userRepository; +// this.ownerRepository = ownerRepository; +// } +// +// @Override +// public OAuth2User loadUser(OAuth2UserRequest oAuth2UserRequest) throws OAuth2AuthenticationException { +// OAuth2User oAuth2User = super.loadUser(oAuth2UserRequest); +// log.info("OAuth2User loaded: {}", oAuth2User.getName()); +// +// HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest(); +// String state = (String)request.getSession().getAttribute("oauth2_state"); +// request.getSession().removeAttribute("oauth2_state"); +// +// OAuth2Response oAuth2Response = new KakaoResponse(oAuth2User.getAttributes()); +// +// // String userId = oAuth2Response.getProvider() + "_" + oAuth2Response.getProviderId(); +// String userId = oAuth2Response.getProviderId(); +// +// if ("user".equals(state)) { +// User existUser = userRepository.findByProviderId(userId).orElse(null); +// if (existUser == null) { +// User newUser = User.create(userId, oAuth2Response.getNickname(), oAuth2Response.getImage(), +// "ROLE_USER"); +// userRepository.save(newUser); +// +// OAuthUserDTO userDTO = new OAuthUserDTO(); +// userDTO.setUserId(userId); +// userDTO.setNickname(oAuth2Response.getNickname()); +// userDTO.setImage(oAuth2Response.getImage()); +// userDTO.setRole("ROLE_USER"); +// +// return new CustomOAuthUser(userDTO); +// } else { +// existUser.setNickname(oAuth2Response.getNickname()); +// existUser.setProfileImageUrl(oAuth2Response.getImage()); +// +// userRepository.save(existUser); +// +// OAuthUserDTO userDTO = new OAuthUserDTO(); +// userDTO.setUserId(existUser.getProviderId()); +// userDTO.setNickname(existUser.getNickname()); +// userDTO.setImage(existUser.getProfileImageUrl()); +// userDTO.setCreatedAt(existUser.getCreatedAt()); +// userDTO.setRole("ROLE_USER"); +// +// return new CustomOAuthUser(userDTO); +// } +// } else if ("owner".equals(state)) { +// User existUser = userRepository.findByProviderId(userId).orElse(null); +// if (existUser == null || !existUser.getRole().equals("ROLE_OWNER")) { +// User newUser = User.create(userId, oAuth2Response.getNickname(), oAuth2Response.getImage(), +// "ROLE_OWNER"); +// userRepository.save(newUser); +// +// OAuthUserDTO userDTO = new OAuthUserDTO(); +// userDTO.setUserId(userId); +// userDTO.setNickname(oAuth2Response.getNickname()); +// userDTO.setImage(oAuth2Response.getImage()); +// userDTO.setRole("ROLE_OWNER"); +// +// Owner newOwner = Owner.create(newUser); +// newOwner.setUser(newUser); +// ownerRepository.save(newOwner); +// +// return new CustomOAuthUser(userDTO); +// } else { +// existUser.setNickname(oAuth2Response.getNickname()); +// existUser.setProfileImageUrl(oAuth2Response.getImage()); +// +// userRepository.save(existUser); +// +// OAuthUserDTO userDTO = new OAuthUserDTO(); +// userDTO.setUserId(existUser.getProviderId()); +// userDTO.setNickname(existUser.getNickname()); +// userDTO.setImage(existUser.getProfileImageUrl()); +// userDTO.setRole("ROLE_OWNER"); +// +// return new CustomOAuthUser(userDTO); +// } +// } else { +// return null; +// } +// } +// } diff --git a/src/main/java/com/jangburich/domain/order/application/OrderService.java b/src/main/java/com/jangburich/domain/order/application/OrderService.java index 43ac3bb..4564f3e 100644 --- a/src/main/java/com/jangburich/domain/order/application/OrderService.java +++ b/src/main/java/com/jangburich/domain/order/application/OrderService.java @@ -17,7 +17,7 @@ import com.jangburich.domain.team.domain.Team; import com.jangburich.domain.team.domain.repository.TeamRepository; import com.jangburich.domain.user.domain.User; -import com.jangburich.domain.user.domain.repository.UserRepository; +import com.jangburich.domain.user.repository.UserRepository; import com.jangburich.global.payload.Message; import java.util.List; import java.util.Optional; diff --git a/src/main/java/com/jangburich/domain/order/presentation/OrderController.java b/src/main/java/com/jangburich/domain/order/presentation/OrderController.java index b6f53a1..b30cab3 100644 --- a/src/main/java/com/jangburich/domain/order/presentation/OrderController.java +++ b/src/main/java/com/jangburich/domain/order/presentation/OrderController.java @@ -1,22 +1,24 @@ package com.jangburich.domain.order.presentation; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestAttribute; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + import com.jangburich.domain.order.application.OrderService; import com.jangburich.domain.order.dto.request.AddCartRequest; import com.jangburich.domain.order.dto.request.OrderRequest; import com.jangburich.domain.order.dto.response.CartResponse; +import com.jangburich.global.GetAuthorization; import com.jangburich.global.payload.Message; import com.jangburich.global.payload.ResponseCustom; -import com.jangburich.utils.parser.AuthenticationParser; + import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; -import org.springframework.security.core.Authentication; -import org.springframework.web.bind.annotation.GetMapping; -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.RequestMapping; -import org.springframework.web.bind.annotation.RestController; @Tag(name = "Order", description = "Order API") @RestController @@ -24,39 +26,39 @@ @RequestMapping("/orders") public class OrderController { - private final OrderService orderService; - - @Operation(summary = "장바구니 담기", description = "장바구니에 물건과 수량을 담습니다.") - @PostMapping("/carts") - public ResponseCustom addCart( - Authentication authentication, - @RequestBody AddCartRequest addCartRequest - ) { - return ResponseCustom.OK(orderService.addCart(AuthenticationParser.parseUserId(authentication), addCartRequest)); - } - - @Operation(summary = "장바구니 조회", description = "장바구니에 담은 상품을 조회합니다.") - @GetMapping("/carts") - public ResponseCustom getCartItems( - Authentication authentication - ) { - return ResponseCustom.OK(orderService.getCartItems(AuthenticationParser.parseUserId(authentication))); - } - - @Operation(summary = "상품 주문", description = "상품을 주문합니다.") - @PostMapping - public ResponseCustom order( - Authentication authentication, - @RequestBody OrderRequest orderRequest - ) { - return ResponseCustom.OK(orderService.order(AuthenticationParser.parseUserId(authentication), orderRequest)); - } - - @Operation(summary = "식권 사용", description = "식권을 사용합니다.") - public ResponseCustom useMealTicket( - Authentication authentication, - @PathVariable Long orderId - ) { - return ResponseCustom.OK(orderService.useMealTicket(AuthenticationParser.parseUserId(authentication), orderId)); - } + private final OrderService orderService; + + @Operation(summary = "장바구니 담기", description = "장바구니에 물건과 수량을 담습니다.") + @PostMapping("/carts") + public ResponseCustom addCart( + @RequestAttribute(value = "authorizationHeader") String authorizationHeader, + @RequestBody AddCartRequest addCartRequest + ) { + return ResponseCustom.OK(orderService.addCart(GetAuthorization.getUserId(authorizationHeader), addCartRequest)); + } + + @Operation(summary = "장바구니 조회", description = "장바구니에 담은 상품을 조회합니다.") + @GetMapping("/carts") + public ResponseCustom getCartItems( + @RequestAttribute(value = "authorizationHeader") String authorizationHeader + ) { + return ResponseCustom.OK(orderService.getCartItems(GetAuthorization.getUserId(authorizationHeader))); + } + + @Operation(summary = "상품 주문", description = "상품을 주문합니다.") + @PostMapping + public ResponseCustom order( + @RequestAttribute(value = "authorizationHeader") String authorizationHeader, + @RequestBody OrderRequest orderRequest + ) { + return ResponseCustom.OK(orderService.order(GetAuthorization.getUserId(authorizationHeader), orderRequest)); + } + + @Operation(summary = "식권 사용", description = "식권을 사용합니다.") + public ResponseCustom useMealTicket( + @RequestAttribute(value = "authorizationHeader") String authorizationHeader, + @PathVariable Long orderId + ) { + return ResponseCustom.OK(orderService.useMealTicket(GetAuthorization.getUserId(authorizationHeader), orderId)); + } } \ No newline at end of file diff --git a/src/main/java/com/jangburich/domain/owner/domain/controller/OwnerController.java b/src/main/java/com/jangburich/domain/owner/domain/controller/OwnerController.java index 0ba8b9d..bf7f07a 100644 --- a/src/main/java/com/jangburich/domain/owner/domain/controller/OwnerController.java +++ b/src/main/java/com/jangburich/domain/owner/domain/controller/OwnerController.java @@ -1,8 +1,8 @@ package com.jangburich.domain.owner.domain.controller; -import org.springframework.security.core.Authentication; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestAttribute; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @@ -10,6 +10,7 @@ import com.jangburich.domain.owner.domain.OwnerCreateReqDTO; import com.jangburich.domain.owner.domain.OwnerGetResDTO; import com.jangburich.domain.owner.domain.service.OwnerService; +import com.jangburich.global.GetAuthorization; import com.jangburich.global.payload.Message; import com.jangburich.global.payload.ResponseCustom; @@ -27,18 +28,19 @@ public class OwnerController { @Operation(summary = "사장님 정보 등록", description = "사장님 상세 정보를 등록합니다.") @PostMapping("/register") - public ResponseCustom registerOwner(Authentication authentication, OwnerCreateReqDTO ownerCreateReqDTO) { - CustomOAuthUser customOAuthUser = (CustomOAuthUser)authentication.getPrincipal(); - ownerService.registerOwner(customOAuthUser, ownerCreateReqDTO); + public ResponseCustom registerOwner( + @RequestAttribute(value = "authorizationHeader") String authorizationHeader, + OwnerCreateReqDTO ownerCreateReqDTO) { + ownerService.registerOwner(GetAuthorization.getUserId(authorizationHeader), ownerCreateReqDTO); return ResponseCustom.OK(Message.builder() - .message("success") - .build()); + .message("success") + .build()); } @Operation(summary = "사장님 정보 조회", description = "사장님 정보를 조회합니다.") @GetMapping("") - public ResponseCustom getOwnerInfo(Authentication authentication) { - CustomOAuthUser customOAuthUser = (CustomOAuthUser)authentication.getPrincipal(); - return ResponseCustom.OK(ownerService.getOwnerInfo(customOAuthUser)); + public ResponseCustom getOwnerInfo( + @RequestAttribute(value = "authorizationHeader") String authorizationHeader) { + return ResponseCustom.OK(ownerService.getOwnerInfo(GetAuthorization.getUserId(authorizationHeader))); } } diff --git a/src/main/java/com/jangburich/domain/owner/domain/service/OwnerService.java b/src/main/java/com/jangburich/domain/owner/domain/service/OwnerService.java index 8d35a0f..de0daba 100644 --- a/src/main/java/com/jangburich/domain/owner/domain/service/OwnerService.java +++ b/src/main/java/com/jangburich/domain/owner/domain/service/OwnerService.java @@ -2,13 +2,12 @@ import org.springframework.stereotype.Service; -import com.jangburich.domain.oauth.domain.CustomOAuthUser; import com.jangburich.domain.owner.domain.Owner; import com.jangburich.domain.owner.domain.OwnerCreateReqDTO; import com.jangburich.domain.owner.domain.OwnerGetResDTO; import com.jangburich.domain.owner.domain.repository.OwnerRepository; import com.jangburich.domain.user.domain.User; -import com.jangburich.domain.user.domain.repository.UserRepository; +import com.jangburich.domain.user.repository.UserRepository; import com.jangburich.global.error.DefaultNullPointerException; import com.jangburich.global.payload.ErrorCode; @@ -21,8 +20,8 @@ public class OwnerService { private final OwnerRepository ownerRepository; private final UserRepository userRepository; - public void registerOwner(CustomOAuthUser customOAuthUser, OwnerCreateReqDTO ownerCreateReqDTO) { - User user = userRepository.findByProviderId(customOAuthUser.getUserId()) + public void registerOwner(String customOAuthUser, OwnerCreateReqDTO ownerCreateReqDTO) { + User user = userRepository.findByProviderId(customOAuthUser) .orElseThrow(() -> new DefaultNullPointerException(ErrorCode.INVALID_AUTHENTICATION)); Owner owner = ownerRepository.findByUser(user) @@ -37,8 +36,8 @@ public void registerOwner(CustomOAuthUser customOAuthUser, OwnerCreateReqDTO own ownerRepository.save(owner); } - public OwnerGetResDTO getOwnerInfo(CustomOAuthUser customOAuthUser) { - User user = userRepository.findByProviderId(customOAuthUser.getUserId()) + public OwnerGetResDTO getOwnerInfo(String customOAuthUser) { + User user = userRepository.findByProviderId(customOAuthUser) .orElseThrow(() -> new DefaultNullPointerException(ErrorCode.INVALID_AUTHENTICATION)); Owner owner = ownerRepository.findByUser(user) diff --git a/src/main/java/com/jangburich/domain/payment/presentation/PaymentController.java b/src/main/java/com/jangburich/domain/payment/presentation/PaymentController.java index da0791c..3989c07 100644 --- a/src/main/java/com/jangburich/domain/payment/presentation/PaymentController.java +++ b/src/main/java/com/jangburich/domain/payment/presentation/PaymentController.java @@ -1,8 +1,8 @@ package com.jangburich.domain.payment.presentation; -import org.springframework.security.core.Authentication; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestAttribute; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; @@ -14,8 +14,8 @@ import com.jangburich.domain.payment.dto.response.ReadyResponse; import com.jangburich.domain.payment.exception.PaymentCancellationException; import com.jangburich.domain.payment.exception.PaymentFailedException; +import com.jangburich.global.GetAuthorization; import com.jangburich.global.payload.ResponseCustom; -import com.jangburich.utils.parser.AuthenticationParser; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -31,16 +31,18 @@ public class PaymentController { @Operation(summary = "결제 준비", description = "카카오페이 등 결제 수단을 준비한다.") @PostMapping("/ready") - public ResponseCustom payReady(Authentication authentication, @RequestBody PayRequest payRequest) { + public ResponseCustom payReady( + @RequestAttribute(value = "authorizationHeader") String authorizationHeader, + @RequestBody PayRequest payRequest) { return ResponseCustom.OK( - paymentProcessingService.processPayment(AuthenticationParser.parseUserId(authentication), payRequest)); + paymentProcessingService.processPayment(GetAuthorization.getUserId(authorizationHeader), payRequest)); } @Operation(summary = "결제 성공", description = "결제 성공") @GetMapping("/success") public ResponseCustom afterPayRequest(@RequestParam("pg_token") String pgToken) { return ResponseCustom.OK( - paymentProcessingService.processSuccess(pgToken)); + paymentProcessingService.processSuccess(pgToken)); } @Operation(summary = "결제 취소", description = "결제 진행 중에 취소되는 경우") diff --git a/src/main/java/com/jangburich/domain/store/domain/Store.java b/src/main/java/com/jangburich/domain/store/domain/Store.java index 3dbc358..9f57826 100644 --- a/src/main/java/com/jangburich/domain/store/domain/Store.java +++ b/src/main/java/com/jangburich/domain/store/domain/Store.java @@ -93,6 +93,12 @@ public class Store { @Column(name = "contact_number") private String contactNumber; + public static Store create(Owner owner) { + Store newOwner = new Store(); + newOwner.setOwner(owner); + return newOwner; + } + public static Store of(Owner owner, StoreCreateRequestDTO storeCreateRequestDTO) { Store newStore = new Store(); newStore.setOwner(owner); diff --git a/src/main/java/com/jangburich/domain/store/domain/controller/StoreController.java b/src/main/java/com/jangburich/domain/store/domain/controller/StoreController.java index 67c21d3..f76f3a8 100644 --- a/src/main/java/com/jangburich/domain/store/domain/controller/StoreController.java +++ b/src/main/java/com/jangburich/domain/store/domain/controller/StoreController.java @@ -2,18 +2,17 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; -import org.springframework.security.core.Authentication; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestAttribute; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; -import com.jangburich.domain.oauth.domain.CustomOAuthUser; import com.jangburich.domain.store.domain.Category; import com.jangburich.domain.store.domain.StoreAdditionalInfoCreateRequestDTO; import com.jangburich.domain.store.domain.StoreCreateRequestDTO; @@ -25,9 +24,9 @@ import com.jangburich.domain.store.domain.dto.response.PaymentGroupDetailResponse; import com.jangburich.domain.store.domain.dto.response.SearchStoresResponse; import com.jangburich.domain.store.domain.service.StoreService; +import com.jangburich.global.GetAuthorization; import com.jangburich.global.payload.Message; import com.jangburich.global.payload.ResponseCustom; -import com.jangburich.utils.parser.AuthenticationParser; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -44,82 +43,83 @@ public class StoreController { @Operation(summary = "카테고리 별 가게 목록 조회", description = "카테고리 별로 가게 목록을 조회합니다.") @GetMapping("/category") public ResponseCustom> searchByCategory( - Authentication authentication, + @RequestAttribute(value = "authorizationHeader") String authorizationHeader, @RequestParam(required = false, defaultValue = "3") Integer searchRadius, @RequestParam(required = false, defaultValue = "ALL") Category category, - @ModelAttribute StoreSearchCondition storeSearchCondition, - Pageable pageable - ) { + @ModelAttribute StoreSearchCondition storeSearchCondition, Pageable pageable) { return ResponseCustom.OK( - storeService.searchByCategory(authentication, searchRadius, category, storeSearchCondition, pageable)); + storeService.searchByCategory(authorizationHeader, searchRadius, category, storeSearchCondition, pageable)); } @Operation(summary = "매장 찾기(검색)", description = "검색어와 매장 유형에 맞는 매장을 검색합니다.") @GetMapping("/search") public ResponseCustom> searchStores( - Authentication authentication, + @RequestAttribute(value = "authorizationHeader") String authorizationHeader, @RequestParam(required = false, defaultValue = "") String keyword, - @ModelAttribute StoreSearchConditionWithType storeSearchConditionWithType, - Pageable pageable - ) { + @ModelAttribute StoreSearchConditionWithType storeSearchConditionWithType, Pageable pageable) { return ResponseCustom.OK( - storeService.searchStores(authentication, keyword, storeSearchConditionWithType, pageable)); + storeService.searchStores(authorizationHeader, keyword, storeSearchConditionWithType, pageable)); } @Operation(summary = "가게 등록", description = "신규 파트너 가게를 등록합니다.") @PostMapping("/create") - public ResponseCustom createStore(Authentication authentication, + public ResponseCustom createStore( + @RequestAttribute(value = "authorizationHeader") String authorizationHeader, @RequestBody StoreCreateRequestDTO storeCreateRequestDTO) { - CustomOAuthUser customOAuth2User = (CustomOAuthUser)authentication.getPrincipal(); - storeService.createStore(customOAuth2User, storeCreateRequestDTO); + storeService.createStore(GetAuthorization.getUserId(authorizationHeader), storeCreateRequestDTO); return ResponseCustom.OK(Message.builder().message("success").build()); } @Operation(summary = "가게 추가정보 저장", description = "예약 가능 여부, 최소 선결제 금액, 선결제 사용 기간을 저장합니다.") @PostMapping("/create/additionalInfo") - public ResponseCustom createAdditionalInfo(Authentication authentication, + public ResponseCustom createAdditionalInfo( + @RequestAttribute(value = "authorizationHeader") String authorizationHeader, @RequestBody StoreAdditionalInfoCreateRequestDTO storeAdditionalInfoCreateRequestDTO) { - CustomOAuthUser customOAuthUser = (CustomOAuthUser)authentication.getPrincipal(); - storeService.createAdditionalInfo(customOAuthUser, storeAdditionalInfoCreateRequestDTO); + storeService.createAdditionalInfo(GetAuthorization.getUserId(authorizationHeader), + storeAdditionalInfoCreateRequestDTO); return ResponseCustom.OK(Message.builder().message("success").build()); } @Operation(summary = "가게 정보 수정", description = "가게 정보를 수정합니다.") @PatchMapping("/update") - public ResponseCustom updateStore(Authentication authentication, + public ResponseCustom updateStore( + @RequestAttribute(value = "authorizationHeader") String authorizationHeader, @RequestBody StoreUpdateRequestDTO storeUpdateRequestDTO) { - storeService.updateStore(AuthenticationParser.parseUserId(authentication), storeUpdateRequestDTO); + storeService.updateStore(GetAuthorization.getUserId(authorizationHeader), storeUpdateRequestDTO); return ResponseCustom.OK(Message.builder().message("success").build()); } @Operation(summary = "가게 정보 조회", description = "가게 상세 정보를 조회합니다.") @GetMapping("") - public ResponseCustom getStoreInfo(Authentication authentication) { - CustomOAuthUser customOAuth2User = (CustomOAuthUser)authentication.getPrincipal(); - return ResponseCustom.OK(storeService.getStoreInfo(customOAuth2User)); + public ResponseCustom getStoreInfo( + @RequestAttribute(value = "authorizationHeader") String authorizationHeader) { + return ResponseCustom.OK(storeService.getStoreInfo(GetAuthorization.getUserId(authorizationHeader))); } @Operation(summary = "결제 그룹 조회", description = "장부 결제 그룹을 조회합니다.") @GetMapping("/payment_group") - public ResponseCustom> getPaymentGroup(Authentication authentication, + public ResponseCustom> getPaymentGroup( + @RequestAttribute(value = "authorizationHeader") String authorizationHeader, Pageable pageable) { return ResponseCustom.OK( - storeService.getPaymentGroup(AuthenticationParser.parseUserId(authentication), pageable)); + storeService.getPaymentGroup(GetAuthorization.getUserId(authorizationHeader), pageable)); } @Operation(summary = "결제 그룹 상세 조회", description = "장부 결제 그룹을 상세 조회합니다.") @GetMapping("/payment_group/{teamId}") - public ResponseCustom getPaymentGroupDetail(Authentication authentication, - @PathVariable Long teamId, + public ResponseCustom getPaymentGroupDetail( + @RequestAttribute(value = "authorizationHeader") String authorizationHeader, @PathVariable Long teamId, Pageable pageable) { return ResponseCustom.OK( - storeService.getPaymentGroupDetail(AuthenticationParser.parseUserId(authentication), teamId, pageable)); + storeService.getPaymentGroupDetail(GetAuthorization.getUserId(authorizationHeader), teamId, pageable)); } @Operation(summary = "결제 내역 조회", description = "가게에서 일어난 결제 내역을 조회합니다.") @GetMapping("/payment_history") - public ResponseCustom getPaymentHistory(Authentication authentication, Pageable pageable) { + public ResponseCustom getPaymentHistory( + @RequestAttribute(value = "authorizationHeader") String authorizationHeader, + Pageable pageable) { return ResponseCustom.OK( - storeService.getPaymentHistory(AuthenticationParser.parseUserId(authentication), pageable)); + storeService.getPaymentHistory(GetAuthorization.getUserId(authorizationHeader), pageable)); } } \ No newline at end of file diff --git a/src/main/java/com/jangburich/domain/store/domain/service/StoreService.java b/src/main/java/com/jangburich/domain/store/domain/service/StoreService.java index 58b9b41..665c969 100644 --- a/src/main/java/com/jangburich/domain/store/domain/service/StoreService.java +++ b/src/main/java/com/jangburich/domain/store/domain/service/StoreService.java @@ -2,11 +2,9 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; -import org.springframework.security.core.Authentication; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import com.jangburich.domain.oauth.domain.CustomOAuthUser; import com.jangburich.domain.owner.domain.Owner; import com.jangburich.domain.owner.domain.repository.OwnerRepository; import com.jangburich.domain.payment.domain.TeamChargeHistoryResponse; @@ -29,10 +27,10 @@ import com.jangburich.domain.team.domain.Team; import com.jangburich.domain.team.domain.repository.TeamRepository; import com.jangburich.domain.user.domain.User; -import com.jangburich.domain.user.domain.repository.UserRepository; +import com.jangburich.domain.user.repository.UserRepository; +import com.jangburich.global.GetAuthorization; import com.jangburich.global.error.DefaultNullPointerException; import com.jangburich.global.payload.ErrorCode; -import com.jangburich.utils.parser.AuthenticationParser; import lombok.RequiredArgsConstructor; @@ -48,8 +46,8 @@ public class StoreService { private final TeamChargeHistoryRepository teamChargeHistoryRepository; @Transactional - public void createStore(CustomOAuthUser customOAuth2User, StoreCreateRequestDTO storeCreateRequestDTO) { - User user = userRepository.findByProviderId(customOAuth2User.getUserId()) + public void createStore(String authentication, StoreCreateRequestDTO storeCreateRequestDTO) { + User user = userRepository.findByProviderId(authentication) .orElseThrow(() -> new DefaultNullPointerException(ErrorCode.INVALID_AUTHENTICATION)); Owner owner = ownerRepository.findByUser(user) @@ -59,9 +57,9 @@ public void createStore(CustomOAuthUser customOAuth2User, StoreCreateRequestDTO } @Transactional - public void createAdditionalInfo(CustomOAuthUser customOAuthUser, + public void createAdditionalInfo(String authentication, StoreAdditionalInfoCreateRequestDTO storeAdditionalInfoCreateRequestDTO) { - User user = userRepository.findByProviderId(customOAuthUser.getUserId()) + User user = userRepository.findByProviderId(authentication) .orElseThrow(() -> new DefaultNullPointerException(ErrorCode.INVALID_AUTHENTICATION)); Owner owner = ownerRepository.findByUser(user) @@ -143,8 +141,8 @@ public Store updateStore(Store store, StoreUpdateRequestDTO storeUpdateRequestDT return store; } - public StoreGetResponseDTO getStoreInfo(CustomOAuthUser customOAuth2User) { - User user = userRepository.findByProviderId(customOAuth2User.getUserId()) + public StoreGetResponseDTO getStoreInfo(String authentication) { + User user = userRepository.findByProviderId(authentication) .orElseThrow(() -> new DefaultNullPointerException(ErrorCode.INVALID_AUTHENTICATION)); Owner owner = ownerRepository.findByUser(user) @@ -153,7 +151,7 @@ public StoreGetResponseDTO getStoreInfo(CustomOAuthUser customOAuth2User) { Store store = storeRepository.findByOwner(owner) .orElseThrow(() -> new DefaultNullPointerException(ErrorCode.INVALID_PARAMETER)); - if (!store.getOwner().getUser().getProviderId().equals(customOAuth2User.getUserId())) { + if (!store.getOwner().getUser().getProviderId().equals(authentication)) { throw new DefaultNullPointerException(ErrorCode.INVALID_AUTHENTICATION); } @@ -173,19 +171,17 @@ public Page getPaymentGroup(String userId, Pageable pageab return storeTeamRepository.findAllByStore(store, pageable); } - public Page searchByCategory(final Authentication authentication, final Integer searchRadius, + public Page searchByCategory(final String authentication, final Integer searchRadius, final Category category, final StoreSearchCondition storeSearchCondition, final Pageable pageable) { - String parsed = AuthenticationParser.parseUserId(authentication); - User user = userRepository.findByProviderId(parsed) + User user = userRepository.findByProviderId(GetAuthorization.getUserId(authentication)) .orElseThrow(() -> new DefaultNullPointerException(ErrorCode.INVALID_AUTHENTICATION)); return storeRepository.findStoresByCategory(user.getUserId(), searchRadius, category, storeSearchCondition, pageable); } - public Page searchStores(final Authentication authentication, final String keyword, + public Page searchStores(final String authentication, final String keyword, final StoreSearchConditionWithType storeSearchConditionWithType, final Pageable pageable) { - String parsed = AuthenticationParser.parseUserId(authentication); - User user = userRepository.findByProviderId(parsed) + User user = userRepository.findByProviderId(GetAuthorization.getUserId(authentication)) .orElseThrow(() -> new DefaultNullPointerException(ErrorCode.INVALID_AUTHENTICATION)); return storeRepository.findStores(user.getUserId(), keyword, storeSearchConditionWithType, pageable); } diff --git a/src/main/java/com/jangburich/domain/team/application/TeamService.java b/src/main/java/com/jangburich/domain/team/application/TeamService.java index d8ce558..0a05daa 100644 --- a/src/main/java/com/jangburich/domain/team/application/TeamService.java +++ b/src/main/java/com/jangburich/domain/team/application/TeamService.java @@ -1,5 +1,8 @@ package com.jangburich.domain.team.application; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + import com.jangburich.domain.team.domain.Team; import com.jangburich.domain.team.domain.TeamLeader; import com.jangburich.domain.team.domain.TeamType; @@ -8,73 +11,72 @@ import com.jangburich.domain.team.domain.repository.UserTeamRepository; import com.jangburich.domain.team.dto.request.RegisterTeamRequest; import com.jangburich.domain.user.domain.User; -import com.jangburich.domain.user.domain.repository.UserRepository; +import com.jangburich.domain.user.repository.UserRepository; +import com.jangburich.global.GetAuthorization; import com.jangburich.global.payload.Message; + import lombok.RequiredArgsConstructor; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; @Service @Transactional(readOnly = true) @RequiredArgsConstructor public class TeamService { - private static final int ZERO = 0; + private static final int ZERO = 0; - private final TeamRepository teamRepository; - private final UserRepository userRepository; - private final UserTeamRepository userTeamRepository; + private final TeamRepository teamRepository; + private final UserRepository userRepository; + private final UserTeamRepository userTeamRepository; - @Transactional - public Message registerTeam(String userId, RegisterTeamRequest registerTeamRequest) { - User user = userRepository.findByProviderId(userId) - .orElseThrow(() -> new NullPointerException()); + @Transactional + public Message registerTeam(String userId, RegisterTeamRequest registerTeamRequest) { - Team team = Team.builder() - .name(registerTeamRequest.teamName()) - .description(registerTeamRequest.description()) - .teamLeader(new TeamLeader(user.getUserId(), registerTeamRequest.teamLeaderAccountNumber(), - registerTeamRequest.bankName())) - .secretCode(registerTeamRequest.secretCode()) - .point(ZERO) - .memberLimit(registerTeamRequest.memberLimit()) - .teamType(TeamType.valueOf(registerTeamRequest.teamType())) - .build(); + User user = userRepository.findByProviderId(GetAuthorization.getUserId(userId)) + .orElseThrow(() -> new NullPointerException()); - System.out.println("222"); - teamRepository.save(team); + Team team = Team.builder() + .name(registerTeamRequest.teamName()) + .description(registerTeamRequest.description()) + .teamLeader(new TeamLeader(user.getUserId(), registerTeamRequest.teamLeaderAccountNumber(), + registerTeamRequest.bankName())) + .secretCode(registerTeamRequest.secretCode()) + .point(ZERO) + .memberLimit(registerTeamRequest.memberLimit()) + .teamType(TeamType.valueOf(registerTeamRequest.teamType())) + .build(); - UserTeam userTeam = UserTeam.of(user, team); - userTeamRepository.save(userTeam); + teamRepository.save(team); - return Message.builder() - .message("팀 생성이 완료되었습니다.") - .build(); - } + UserTeam userTeam = UserTeam.of(user, team); + userTeamRepository.save(userTeam); - @Transactional - public Message joinTeam(String userId, String joinCode) { - User user = userRepository.findByProviderId(userId) - .orElseThrow(() -> new NullPointerException()); + return Message.builder() + .message("팀 생성이 완료되었습니다.") + .build(); + } - Team team = teamRepository.findBySecretCode(joinCode) - .orElseThrow(() -> new IllegalArgumentException("Team not found")); + @Transactional + public Message joinTeam(String userId, String joinCode) { + User user = userRepository.findByProviderId(GetAuthorization.getUserId(userId)) + .orElseThrow(() -> new NullPointerException()); - team.validateJoinCode(joinCode); + Team team = teamRepository.findBySecretCode(joinCode) + .orElseThrow(() -> new IllegalArgumentException("Team not found")); - int currentMemberCount = userTeamRepository.countByTeam(team); - team.validateMemberLimit(currentMemberCount); + team.validateJoinCode(joinCode); - if (userTeamRepository.existsByUserAndTeam(user, team)) { - throw new IllegalStateException("유저는 이미 해당 팀에 속해 있습니다."); - } + int currentMemberCount = userTeamRepository.countByTeam(team); + team.validateMemberLimit(currentMemberCount); - UserTeam userTeam = UserTeam.of(user, team); - userTeamRepository.save(userTeam); + if (userTeamRepository.existsByUserAndTeam(user, team)) { + throw new IllegalStateException("유저는 이미 해당 팀에 속해 있습니다."); + } + UserTeam userTeam = UserTeam.of(user, team); + userTeamRepository.save(userTeam); - return Message.builder() - .message("팀에 성공적으로 참여하였습니다.") - .build(); - } + return Message.builder() + .message("팀에 성공적으로 참여하였습니다.") + .build(); + } } diff --git a/src/main/java/com/jangburich/domain/team/presentation/TeamController.java b/src/main/java/com/jangburich/domain/team/presentation/TeamController.java index 4e8b00d..e9dc726 100644 --- a/src/main/java/com/jangburich/domain/team/presentation/TeamController.java +++ b/src/main/java/com/jangburich/domain/team/presentation/TeamController.java @@ -1,19 +1,22 @@ package com.jangburich.domain.team.presentation; +import org.springframework.security.core.Authentication; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestAttribute; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + import com.jangburich.domain.team.application.TeamService; import com.jangburich.domain.team.dto.request.RegisterTeamRequest; import com.jangburich.global.payload.Message; import com.jangburich.global.payload.ResponseCustom; import com.jangburich.utils.parser.AuthenticationParser; + import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; -import org.springframework.security.core.Authentication; -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.RequestMapping; -import org.springframework.web.bind.annotation.RestController; @Tag(name = "Team", description = "Team API") @RestController @@ -21,23 +24,24 @@ @RequestMapping("/teams") public class TeamController { - private final TeamService teamService; + private final TeamService teamService; - @Operation(summary = "팀 생성", description = "팀을 생성한다. 팀 리더는 생성자") - @PostMapping - public ResponseCustom registerTeam( - Authentication authentication, - @RequestBody RegisterTeamRequest registerTeamRequest - ) { - return ResponseCustom.OK(teamService.registerTeam(AuthenticationParser.parseUserId(authentication), registerTeamRequest)); - } + @Operation(summary = "팀 생성", description = "팀을 생성한다. 팀 리더는 생성자") + @PostMapping + public ResponseCustom registerTeam( + @RequestAttribute(value = "authorizationHeader") String authorizationHeader, + @RequestBody RegisterTeamRequest registerTeamRequest + ) { + return ResponseCustom.OK( + teamService.registerTeam(authorizationHeader, registerTeamRequest)); + } - @Operation(summary = "팀 가입", description = "비밀 코드를 입력하여, 팀에 가입한다.") - @PostMapping("/join/{joinCode}") - public ResponseCustom joinTeam( - Authentication authentication, - @PathVariable("joinCode") String joinCode - ) { - return ResponseCustom.OK(teamService.joinTeam(AuthenticationParser.parseUserId(authentication), joinCode)); - } + @Operation(summary = "팀 가입", description = "비밀 코드를 입력하여, 팀에 가입한다.") + @PostMapping("/join/{joinCode}") + public ResponseCustom joinTeam( + @RequestAttribute(value = "authorizationHeader") String authorizationHeader, + @PathVariable("joinCode") String joinCode + ) { + return ResponseCustom.OK(teamService.joinTeam(authorizationHeader, joinCode)); + } } diff --git a/src/main/java/com/jangburich/domain/user/domain/controller/HealthCheck.java b/src/main/java/com/jangburich/domain/user/controller/HealthCheck.java similarity index 82% rename from src/main/java/com/jangburich/domain/user/domain/controller/HealthCheck.java rename to src/main/java/com/jangburich/domain/user/controller/HealthCheck.java index 4e25991..2970f85 100644 --- a/src/main/java/com/jangburich/domain/user/domain/controller/HealthCheck.java +++ b/src/main/java/com/jangburich/domain/user/controller/HealthCheck.java @@ -1,4 +1,4 @@ -package com.jangburich.domain.user.domain.controller; +package com.jangburich.domain.user.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; diff --git a/src/main/java/com/jangburich/domain/user/controller/UserController.java b/src/main/java/com/jangburich/domain/user/controller/UserController.java new file mode 100644 index 0000000..6f9de28 --- /dev/null +++ b/src/main/java/com/jangburich/domain/user/controller/UserController.java @@ -0,0 +1,89 @@ +package com.jangburich.domain.user.controller; + +import java.util.Map; + +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestAttribute; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.client.RestTemplate; + +import com.jangburich.domain.user.domain.KakaoApiResponseDTO; +import com.jangburich.domain.user.service.UserService; +import com.jangburich.global.payload.Message; +import com.jangburich.global.payload.ResponseCustom; + +import lombok.RequiredArgsConstructor; + +@RestController +@RequestMapping("/user") +@RequiredArgsConstructor +public class UserController { + + private final UserService userService; + + @PostMapping("/login") + public ResponseCustom> login( + @RequestAttribute(value = "authorizationHeader") String authorizationHeader) { + + return ResponseCustom.OK(null); + } + + @GetMapping("/user-info") + public ResponseEntity getUserInfo( + @RequestAttribute(value = "authorizationHeader") String authorizationHeader) { + KakaoApiResponseDTO userInfo = userService.getUserInfo(authorizationHeader); + + return ResponseEntity.ok(userInfo); + } + + @PostMapping("/join/user") + public ResponseCustom joinUser( + @RequestAttribute(value = "authorizationHeader") String authorizationHeader) { + userService.joinUser(authorizationHeader); + return ResponseCustom.OK(Message.builder().message("success").build()); + } + + @PostMapping("/join/owner") + public ResponseCustom joinOwner( + @RequestAttribute(value = "authorizationHeader") String authorizationHeader) { + userService.joinOwner(authorizationHeader); + return ResponseCustom.OK(Message.builder().message("success").build()); + } + + @PostMapping("/token") + public ResponseEntity> getAccessToken(@RequestParam("code") String code) { + String tokenUrl = "https://kauth.kakao.com/oauth/token"; + + // 요청 헤더 설정 + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED); + + // 요청 바디 설정 + MultiValueMap params = new LinkedMultiValueMap<>(); + params.add("grant_type", "authorization_code"); + params.add("client_id", "e155fb32e2e3f793d0ddd66212d8d461"); + params.add("redirect_uri", "http://localhost:5123"); + params.add("code", code); + + // 요청 생성 + HttpEntity> request = new HttpEntity<>(params, headers); + RestTemplate restTemplate = new RestTemplate(); + + // 요청 보내기 및 응답 받기 + ResponseEntity response = restTemplate.exchange(tokenUrl, HttpMethod.POST, request, Map.class); + + // 응답 반환 + return ResponseEntity.ok(response.getBody()); + } + +} diff --git a/src/main/java/com/jangburich/domain/user/domain/KakaoApiResponseDTO.java b/src/main/java/com/jangburich/domain/user/domain/KakaoApiResponseDTO.java new file mode 100644 index 0000000..f7a8f13 --- /dev/null +++ b/src/main/java/com/jangburich/domain/user/domain/KakaoApiResponseDTO.java @@ -0,0 +1,77 @@ +package com.jangburich.domain.user.domain; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class KakaoApiResponseDTO { + private Long id; + + @JsonProperty("connected_at") + private String connectedAt; + + private Properties properties; + + @JsonProperty("kakao_account") // JSON 키를 DTO 필드와 매핑 + private KakaoAccount kakaoAccount; + + @Getter + @Setter + public static class Properties { + private String nickname; + + @JsonProperty("profile_image") + private String profileImage; + + @JsonProperty("thumbnail_image") + private String thumbnailImage; + } + + @Getter + @Setter + public static class KakaoAccount { + + @JsonProperty("profile_nickname_needs_agreement") + private boolean profileNicknameNeedsAgreement; + + @JsonProperty("profile_image_needs_agreement") + private boolean profileImageNeedsAgreement; + + private Profile profile; + + @JsonProperty("has_email") + private boolean hasEmail; + + @JsonProperty("email_needs_agreement") + private boolean emailNeedsAgreement; + + @JsonProperty("is_email_valid") + private boolean isEmailValid; + + @JsonProperty("is_email_verified") + private boolean isEmailVerified; + + private String email; + + @Getter + @Setter + public static class Profile { + private String nickname; + + @JsonProperty("thumbnail_image_url") + private String thumbnailImageUrl; + + @JsonProperty("profile_image_url") + private String profileImageUrl; + + @JsonProperty("is_default_image") + private boolean isDefaultImage; + + @JsonProperty("is_default_nickname") + private boolean isDefaultNickname; + } + } +} + diff --git a/src/main/java/com/jangburich/domain/user/domain/User.java b/src/main/java/com/jangburich/domain/user/domain/User.java index 20ddfbf..b2593c3 100644 --- a/src/main/java/com/jangburich/domain/user/domain/User.java +++ b/src/main/java/com/jangburich/domain/user/domain/User.java @@ -56,10 +56,11 @@ public class User extends BaseEntity { private String role; - public static User create(String userId, String nickname, String image, String role) { + public static User create(String userId, String nickname, String email, String image, String role) { User newUser = new User(); newUser.setProviderId(userId); newUser.setNickname(nickname); + newUser.setEmail(email); newUser.setProfileImageUrl(image); newUser.setRole(role); return newUser; diff --git a/src/main/java/com/jangburich/domain/user/domain/service/UserService.java b/src/main/java/com/jangburich/domain/user/domain/service/UserService.java deleted file mode 100644 index 50fc6ae..0000000 --- a/src/main/java/com/jangburich/domain/user/domain/service/UserService.java +++ /dev/null @@ -1,12 +0,0 @@ -package com.jangburich.domain.user.domain.service; - -import org.springframework.stereotype.Service; - -import com.jangburich.domain.user.domain.repository.UserRepository; - -import lombok.RequiredArgsConstructor; - -@Service -@RequiredArgsConstructor -public class UserService { -} diff --git a/src/main/java/com/jangburich/domain/user/domain/repository/UserRepository.java b/src/main/java/com/jangburich/domain/user/repository/UserRepository.java similarity index 85% rename from src/main/java/com/jangburich/domain/user/domain/repository/UserRepository.java rename to src/main/java/com/jangburich/domain/user/repository/UserRepository.java index ee2f3c4..1db050d 100644 --- a/src/main/java/com/jangburich/domain/user/domain/repository/UserRepository.java +++ b/src/main/java/com/jangburich/domain/user/repository/UserRepository.java @@ -1,4 +1,4 @@ -package com.jangburich.domain.user.domain.repository; +package com.jangburich.domain.user.repository; import java.util.Optional; diff --git a/src/main/java/com/jangburich/domain/user/service/UserService.java b/src/main/java/com/jangburich/domain/user/service/UserService.java new file mode 100644 index 0000000..66fe4bb --- /dev/null +++ b/src/main/java/com/jangburich/domain/user/service/UserService.java @@ -0,0 +1,70 @@ +package com.jangburich.domain.user.service; + +import java.util.Map; + +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.client.RestTemplate; + +import com.jangburich.domain.owner.domain.Owner; +import com.jangburich.domain.owner.domain.repository.OwnerRepository; +import com.jangburich.domain.store.domain.Store; +import com.jangburich.domain.store.domain.repository.StoreRepository; +import com.jangburich.domain.user.domain.KakaoApiResponseDTO; +import com.jangburich.domain.user.domain.User; +import com.jangburich.domain.user.repository.UserRepository; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class UserService { + + private final UserRepository userRepository; + private final OwnerRepository ownerRepository; + private final StoreRepository storeRepository; + + public KakaoApiResponseDTO getUserInfo(String accessToken) { + String userInfoUrl = "https://kapi.kakao.com/v2/user/me"; + + HttpHeaders headers = new HttpHeaders(); + headers.set("Authorization", "Bearer " + accessToken); + HttpEntity request = new HttpEntity<>(headers); + + RestTemplate restTemplate = new RestTemplate(); + ResponseEntity response = restTemplate.exchange(userInfoUrl, HttpMethod.GET, request, + KakaoApiResponseDTO.class); + + return response.getBody(); + } + + @Transactional + public void joinUser(String accessToken) { + KakaoApiResponseDTO userInfo = getUserInfo(accessToken); + + User user = userRepository.findByProviderId("kakao_" + userInfo.getId()).orElse(null); + if (user == null) { + userRepository.save(User.create("kakao_" + userInfo.getId(), userInfo.getProperties().getNickname(), + userInfo.getKakaoAccount().getEmail(), userInfo.getProperties().getProfileImage(), "ROLE_USER")); + } + } + + @Transactional + public void joinOwner(String accessToken) { + KakaoApiResponseDTO userInfo = getUserInfo(accessToken); + + User user = userRepository.findByProviderId("kakao_" + userInfo.getId()).orElse(null); + if (user == null) { + User newUser = userRepository.save( + User.create("kakao_" + userInfo.getId(), userInfo.getProperties().getNickname(), + userInfo.getKakaoAccount().getEmail(), userInfo.getProperties().getProfileImage(), "ROLE_OWNER")); + Owner newOwner = ownerRepository.save(Owner.create(newUser)); + storeRepository.save(Store.create(newOwner)); + } + } + +} diff --git a/src/main/java/com/jangburich/global/GetAuthorization.java b/src/main/java/com/jangburich/global/GetAuthorization.java new file mode 100644 index 0000000..689ce6d --- /dev/null +++ b/src/main/java/com/jangburich/global/GetAuthorization.java @@ -0,0 +1,25 @@ +package com.jangburich.global; + +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.web.client.RestTemplate; + +import com.jangburich.domain.user.domain.KakaoApiResponseDTO; + +public class GetAuthorization { + public static String getUserId(String accessToken) { + String userInfoUrl = "https://kapi.kakao.com/v2/user/me"; + + HttpHeaders headers = new HttpHeaders(); + headers.set("Authorization", "Bearer " + accessToken); + HttpEntity request = new HttpEntity<>(headers); + + RestTemplate restTemplate = new RestTemplate(); + ResponseEntity response = restTemplate.exchange(userInfoUrl, HttpMethod.GET, request, + KakaoApiResponseDTO.class); + + return "kakao_" + response.getBody().getId(); + } +} diff --git a/src/main/java/com/jangburich/global/config/security/SecurityConfig.java b/src/main/java/com/jangburich/global/config/security/SecurityConfig.java index 84f2305..c3238db 100644 --- a/src/main/java/com/jangburich/global/config/security/SecurityConfig.java +++ b/src/main/java/com/jangburich/global/config/security/SecurityConfig.java @@ -6,15 +6,10 @@ import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.config.http.SessionCreationPolicy; -import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; -import com.jangburich.domain.oauth.domain.service.OAuthUserService; -import com.jangburich.utils.CustomAuthorizationRequestResolver; -import com.jangburich.utils.CustomSuccessHandler; -import com.jangburich.utils.JwtFilter; -import com.jangburich.utils.JwtUtil; +import com.jangburich.utils.AuthorizationHeaderFilter; import lombok.RequiredArgsConstructor; @@ -23,33 +18,19 @@ @EnableWebSecurity public class SecurityConfig { - private final OAuthUserService oauthUserService; - private final CustomSuccessHandler customSuccessHandler; - private final ClientRegistrationRepository clientRegistrationRepository; - @Bean - public SecurityFilterChain securityFilterChain(HttpSecurity http, JwtUtil jwtUtil) throws Exception { - http - .csrf(AbstractHttpConfigurer::disable) + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + http.csrf(AbstractHttpConfigurer::disable) .httpBasic(AbstractHttpConfigurer::disable) .formLogin(AbstractHttpConfigurer::disable) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) - .addFilterBefore(new JwtFilter(jwtUtil), UsernamePasswordAuthenticationFilter.class) - .oauth2Login(oauth2 -> oauth2 - .loginPage("/login") - .authorizationEndpoint(authorization -> authorization - .authorizationRequestResolver( - new CustomAuthorizationRequestResolver(clientRegistrationRepository, "/oauth2/authorization") - )) - .userInfoEndpoint(userInfoEndpointConfig -> userInfoEndpointConfig - .userService(oauthUserService)) - .successHandler(customSuccessHandler)) - - .authorizeHttpRequests(request -> request - .requestMatchers("/**", "/oauth2/**", "/login/**", "/swagger-ui/**", "/v3/api-docs/**", - "/swagger-resources/**", "/payments/**").permitAll() - .anyRequest().authenticated() - ); + .addFilterBefore(new AuthorizationHeaderFilter(), UsernamePasswordAuthenticationFilter.class) + .authorizeHttpRequests( + request -> request.requestMatchers("/**", "/oauth2/**", "/login/**", "/swagger-ui/**", + "/v3/api-docs/**", "/swagger-resources/**", "/payments/**") + .permitAll() + .anyRequest() + .authenticated()); return http.build(); } diff --git a/src/main/java/com/jangburich/global/config/security/SwaggerConfig.java b/src/main/java/com/jangburich/global/config/security/SwaggerConfig.java index f34242f..15aa3f0 100644 --- a/src/main/java/com/jangburich/global/config/security/SwaggerConfig.java +++ b/src/main/java/com/jangburich/global/config/security/SwaggerConfig.java @@ -23,11 +23,12 @@ public OpenAPI customOpenAPI() { return new OpenAPI() .info(info) .addSecurityItem( - new io.swagger.v3.oas.models.security.SecurityRequirement().addList("Bearer Authentication")) + new io.swagger.v3.oas.models.security.SecurityRequirement().addList("Custom String Authentication")) .components(new io.swagger.v3.oas.models.Components() - .addSecuritySchemes("Bearer Authentication", new io.swagger.v3.oas.models.security.SecurityScheme() - .type(io.swagger.v3.oas.models.security.SecurityScheme.Type.HTTP) - .scheme("bearer") - .bearerFormat("JWT"))); + .addSecuritySchemes("Custom String Authentication", + new io.swagger.v3.oas.models.security.SecurityScheme() + .type(io.swagger.v3.oas.models.security.SecurityScheme.Type.APIKEY) // API Key 타입 설정 + .name("Authorization") + .in(io.swagger.v3.oas.models.security.SecurityScheme.In.HEADER))); // 헤더로 전달 } } diff --git a/src/main/java/com/jangburich/utils/AuthorizationHeaderFilter.java b/src/main/java/com/jangburich/utils/AuthorizationHeaderFilter.java new file mode 100644 index 0000000..badd9dd --- /dev/null +++ b/src/main/java/com/jangburich/utils/AuthorizationHeaderFilter.java @@ -0,0 +1,25 @@ +package com.jangburich.utils; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.web.filter.OncePerRequestFilter; + +import java.io.IOException; + +public class AuthorizationHeaderFilter extends OncePerRequestFilter { + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + // Authorization 헤더를 읽어서 Request 속성으로 설정 + String authorizationHeader = request.getHeader("Authorization"); + if (authorizationHeader != null && !authorizationHeader.isBlank()) { + // 속성으로 저장 + request.setAttribute("authorizationHeader", authorizationHeader); + } + + filterChain.doFilter(request, response); + } +} diff --git a/src/main/java/com/jangburich/utils/CustomAuthorizationRequestResolver.java b/src/main/java/com/jangburich/utils/CustomAuthorizationRequestResolver.java deleted file mode 100644 index 9d94d31..0000000 --- a/src/main/java/com/jangburich/utils/CustomAuthorizationRequestResolver.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.jangburich.utils; - -import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; -import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizationRequestResolver; -import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver; -import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; - -import jakarta.servlet.http.HttpServletRequest; - -public class CustomAuthorizationRequestResolver implements OAuth2AuthorizationRequestResolver { - private final OAuth2AuthorizationRequestResolver defaultResolver; - - public CustomAuthorizationRequestResolver(ClientRegistrationRepository repo, String authorizationRequestBaseUri) { - this.defaultResolver = new DefaultOAuth2AuthorizationRequestResolver(repo, authorizationRequestBaseUri); - } - - @Override - public OAuth2AuthorizationRequest resolve(HttpServletRequest request) { - OAuth2AuthorizationRequest req = defaultResolver.resolve(request); - return customizeAuthorizationRequest(req, request); - } - - @Override - public OAuth2AuthorizationRequest resolve(HttpServletRequest request, String clientRegistrationId) { - OAuth2AuthorizationRequest req = defaultResolver.resolve(request, clientRegistrationId); - return customizeAuthorizationRequest(req, request); - } - - private OAuth2AuthorizationRequest customizeAuthorizationRequest(OAuth2AuthorizationRequest req, HttpServletRequest request) { - if (req == null) { - return null; - } - - String state = request.getParameter("state"); - if (state != null) { - request.getSession().setAttribute("oauth2_state", state); - } - - return OAuth2AuthorizationRequest.from(req) - .state(state) - .build(); - } - -} diff --git a/src/main/java/com/jangburich/utils/CustomSuccessHandler.java b/src/main/java/com/jangburich/utils/CustomSuccessHandler.java deleted file mode 100644 index 969806a..0000000 --- a/src/main/java/com/jangburich/utils/CustomSuccessHandler.java +++ /dev/null @@ -1,51 +0,0 @@ -package com.jangburich.utils; - -import java.io.IOException; -import java.util.Collection; -import java.util.Iterator; - -import org.springframework.security.core.Authentication; -import org.springframework.security.core.GrantedAuthority; -import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler; -import org.springframework.stereotype.Component; - -import com.jangburich.domain.oauth.domain.CustomOAuthUser; - -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; - -@Component -public class CustomSuccessHandler extends SimpleUrlAuthenticationSuccessHandler { - private final JwtUtil jwtUtil; - - public CustomSuccessHandler(JwtUtil jwtUtil) { - this.jwtUtil = jwtUtil; - } - - @Override - public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, - Authentication authentication) throws IOException, ServletException { - CustomOAuthUser customOAuthUser = (CustomOAuthUser)authentication.getPrincipal(); - String userId = customOAuthUser.getUserId(); - - Collection authorities = authentication.getAuthorities(); - Iterator iterator = authorities.iterator(); - GrantedAuthority auth = iterator.next(); - String role = auth.getAuthority(); - - String token = jwtUtil.createToken(userId, role); // 10 hours - - // Set the response type to JSON - response.setContentType("application/json"); - response.setCharacterEncoding("UTF-8"); - - // Create a JSON response with the token - String jsonResponse = String.format("{\"token\": \"%s\"}", token); - - // Write the JSON response to the output - response.getWriter().write(jsonResponse); - response.getWriter().flush(); - } - -} diff --git a/src/main/java/com/jangburich/utils/JwtFilter.java b/src/main/java/com/jangburich/utils/JwtFilter.java deleted file mode 100644 index a3442d6..0000000 --- a/src/main/java/com/jangburich/utils/JwtFilter.java +++ /dev/null @@ -1,77 +0,0 @@ -package com.jangburich.utils; - -import java.io.IOException; - -import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; -import org.springframework.web.filter.OncePerRequestFilter; - -import com.jangburich.domain.oauth.domain.CustomOAuthUser; -import com.jangburich.domain.oauth.domain.OAuthUserDTO; - -import jakarta.servlet.FilterChain; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import lombok.NonNull; -import lombok.extern.slf4j.Slf4j; - -@Slf4j -public class JwtFilter extends OncePerRequestFilter { - - private final JwtUtil jwtUtil; - - public JwtFilter(JwtUtil jwtUtil) { - this.jwtUtil = jwtUtil; - } - - @Override - protected void doFilterInternal(HttpServletRequest request, @NonNull HttpServletResponse response, - @NonNull FilterChain filterChain) throws ServletException, IOException { - // Authorization 헤더를 찾음 - String authorizationHeader = request.getHeader("Authorization"); - - if (authorizationHeader == null || !authorizationHeader.startsWith("Bearer ")) { - filterChain.doFilter(request, response); - return; - } - - // "Bearer " 이후의 토큰 부분만 추출 - String token = authorizationHeader.substring(7); - - try { - // 토큰 소멸 시간 검증 - if (jwtUtil.isTokenExpired(token)) { - filterChain.doFilter(request, response); - return; - } - - // 토큰에서 사용자 정보 획득 - String userId = jwtUtil.getUserId(token); - String role = jwtUtil.getRole(token); - - // OAuth2UserDTO 생성 및 설정 - OAuthUserDTO userDTO = new OAuthUserDTO(); - userDTO.setUserId(userId); - userDTO.setRole(role); - - // CustomOAuthUser 생성 - CustomOAuthUser customOAuthUser = new CustomOAuthUser(userDTO); - - // 스프링 시큐리티 인증 토큰 생성 및 설정 - Authentication authToken = new UsernamePasswordAuthenticationToken(customOAuthUser, null, - customOAuthUser.getAuthorities()); - SecurityContextHolder.getContext().setAuthentication(authToken); - - } catch (Exception e) { - // 예외 발생 시 로그 출력 및 인증 정보 제거 - SecurityContextHolder.clearContext(); - response.sendError(HttpServletResponse.SC_UNAUTHORIZED, e.getMessage()); - return; - } - - filterChain.doFilter(request, response); - } - -} \ No newline at end of file diff --git a/src/main/java/com/jangburich/utils/JwtUtil.java b/src/main/java/com/jangburich/utils/JwtUtil.java deleted file mode 100644 index 7026d85..0000000 --- a/src/main/java/com/jangburich/utils/JwtUtil.java +++ /dev/null @@ -1,59 +0,0 @@ -package com.jangburich.utils; - -import java.nio.charset.StandardCharsets; -import java.util.Date; - -import javax.crypto.SecretKey; - -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -import io.jsonwebtoken.Claims; -import io.jsonwebtoken.Jwts; -import io.jsonwebtoken.security.Keys; -import jakarta.servlet.http.Cookie; - -@Component -public class JwtUtil { - - private SecretKey secretKey; - - public JwtUtil(@Value("${spring.jwt.secret}") String secret) { - this.secretKey = Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8)); - } - - private Claims extractAllClaims(String token) { - return Jwts.parser().verifyWith(secretKey).build().parseSignedClaims(token).getPayload(); - } - - public String getUserId(String token) { - return extractAllClaims(token).get("userId", String.class); - } - - public String getRole(String token) { - return extractAllClaims(token).get("role", String.class); - } - - public Boolean isTokenExpired(String token) { - return extractAllClaims(token).getExpiration().before(new Date()); - } - - public String createToken(String userId, String role) { - long expiredMs = 1000 * 60 * 60 * 10; - return Jwts.builder() - .claim("userId", userId) - .claim("role", role) - .issuedAt(new Date(System.currentTimeMillis())) - .expiration(new Date(System.currentTimeMillis() + expiredMs)) - .signWith(secretKey) - .compact(); - } - - public Cookie createCookie(String key, String value) { - Cookie cookie = new Cookie(key, value); - cookie.setMaxAge(60 * 60 * 60 * 10); - cookie.setPath("/"); - cookie.setHttpOnly(true); - return cookie; - } -}