Skip to content

Commit

Permalink
Merge pull request #3 from sws6641/sws6641
Browse files Browse the repository at this point in the history
10주자 과제 제출
  • Loading branch information
bbhye1 authored Nov 27, 2023
2 parents 1205c46 + 9e47851 commit 8aa21e3
Show file tree
Hide file tree
Showing 44 changed files with 1,033 additions and 97 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package kr.megaptera.backendsurvivalweek10.application.auth;

import jakarta.transaction.Transactional;
import kr.megaptera.backendsurvivalweek10.dtos.auth.LoginResultDto;
import kr.megaptera.backendsurvivalweek10.infrastructure.UserDetailsDao;
import kr.megaptera.backendsurvivalweek10.util.AccessTokenGenerator;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.stream.Collectors;

@Service
@Transactional
public class LoginService {
private final AccessTokenGenerator accessTokenGenerator;

private final PasswordEncoder passwordEncoder;

private final UserDetailsDao userDetailsDao;

public LoginService(AccessTokenGenerator accessTokenGenerator,
PasswordEncoder passwordEncoder,
UserDetailsDao userDetailsDao) {
this.accessTokenGenerator = accessTokenGenerator;
this.passwordEncoder = passwordEncoder;
this.userDetailsDao = userDetailsDao;
}

public LoginResultDto login(String username, String password) {
return userDetailsDao.findByUsername(username)
.filter(userDetails -> passwordEncoder.matches(
password, userDetails.getPassword()))
.map(userDetails -> {
String id = userDetails.getUsername();
String accessToken = accessTokenGenerator.generate(id);
userDetailsDao.addAccessToken(id, accessToken);
return new LoginResultDto(
accessToken,
userDetails
.getAuthorities()
.stream().map(Object::toString)
.collect(Collectors.toList()));
})
.orElseThrow(() -> new BadCredentialsException("Login failed"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package kr.megaptera.backendsurvivalweek10.application.auth;

import jakarta.transaction.Transactional;
import kr.megaptera.backendsurvivalweek10.infrastructure.UserDetailsDao;
import org.springframework.stereotype.Service;

@Service
@Transactional
public class LogoutService {
private final UserDetailsDao userDetailsDao;


public LogoutService(UserDetailsDao userDetailsDao) {
this.userDetailsDao = userDetailsDao;
}

public void logout(String accessToken) {
userDetailsDao.removeAccessToken(accessToken);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package kr.megaptera.backendsurvivalweek10.application.auth;

import io.hypersistence.tsid.TSID;
import jakarta.transaction.Transactional;
import kr.megaptera.backendsurvivalweek10.dtos.auth.SignupResultDto;
import kr.megaptera.backendsurvivalweek10.exceptions.UserAlreadyExistsException;
import kr.megaptera.backendsurvivalweek10.infrastructure.UserDetailsDao;
import kr.megaptera.backendsurvivalweek10.util.AccessTokenGenerator;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

@Service
@Transactional
public class SignupService {
private final AccessTokenGenerator accessTokenGenerator;
private final PasswordEncoder passwordEncoder;
private final UserDetailsDao userDetailsDao;

public SignupService(AccessTokenGenerator accessTokenGenerator,
PasswordEncoder passwordEncoder,
UserDetailsDao userDetailsDao) {
this.accessTokenGenerator = accessTokenGenerator;
this.passwordEncoder = passwordEncoder;
this.userDetailsDao = userDetailsDao;
}

public SignupResultDto signup(String username, String password) {
if (userDetailsDao.existsByUsername(username)) {
throw new UserAlreadyExistsException();
}

String id = TSID.Factory.getTsid().toString();
String encodedPassword = passwordEncoder.encode(password);
String accessToken = accessTokenGenerator.generate(id);

userDetailsDao.addUser(id, username, encodedPassword);
userDetailsDao.addAccessToken(id, accessToken);

return new SignupResultDto(accessToken);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import kr.megaptera.backendsurvivalweek10.models.CartId;
import kr.megaptera.backendsurvivalweek10.models.Product;
import kr.megaptera.backendsurvivalweek10.models.ProductId;
import kr.megaptera.backendsurvivalweek10.models.UserId;
import kr.megaptera.backendsurvivalweek10.repositories.CartRepository;
import kr.megaptera.backendsurvivalweek10.repositories.ProductRepository;
import org.springframework.stereotype.Service;
Expand All @@ -21,12 +22,12 @@ public AddProductToCartService(CartRepository cartRepository,
this.productRepository = productRepository;
}

public Cart addProduct(ProductId productId, int quantity) {
public Cart addProduct(String userId, ProductId productId, int quantity) {
Product product = productRepository.findById(productId)
.orElseThrow();

Cart cart = cartRepository.findById(CartId.DEFAULT)
.orElse(new Cart(CartId.DEFAULT));
Cart cart = cartRepository.findByUserId(UserId.of(userId))
.orElse(new Cart(CartId.generate(), UserId.of(userId)));

cart.addProduct(product, quantity);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import kr.megaptera.backendsurvivalweek10.models.Cart;
import kr.megaptera.backendsurvivalweek10.models.CartId;
import kr.megaptera.backendsurvivalweek10.models.LineItemId;
import kr.megaptera.backendsurvivalweek10.models.UserId;
import kr.megaptera.backendsurvivalweek10.repositories.CartRepository;
import jakarta.transaction.Transactional;
import org.springframework.stereotype.Service;
Expand All @@ -16,8 +17,8 @@ public ChangeCartItemQuantityService(CartRepository cartRepository) {
this.cartRepository = cartRepository;
}

public void changeQuantity(LineItemId lineItemId, int quantity) {
Cart cart = cartRepository.findById(CartId.DEFAULT).get();
public void changeQuantity(String userId, LineItemId lineItemId, int quantity) {
Cart cart = cartRepository.findByUserId(UserId.of(userId)).get();

cart.changeLineItemQuantity(lineItemId, quantity);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package kr.megaptera.backendsurvivalweek10.application.cart;

import kr.megaptera.backendsurvivalweek10.dtos.CartDto;
import kr.megaptera.backendsurvivalweek10.dtos.cart.CartDto;
import kr.megaptera.backendsurvivalweek10.infrastructure.CartDtoFetcher;
import kr.megaptera.backendsurvivalweek10.models.CartId;
import kr.megaptera.backendsurvivalweek10.models.UserId;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand All @@ -15,7 +16,7 @@ public GetCartService(CartDtoFetcher cartDtoFetcher) {
this.cartDtoFetcher = cartDtoFetcher;
}

public CartDto getCartDto() {
return cartDtoFetcher.fetchCartDto(CartId.DEFAULT);
public CartDto getCartDto(String userId) {
return cartDtoFetcher.fetchCartDto(UserId.of(userId));
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package kr.megaptera.backendsurvivalweek10.application.product;

import kr.megaptera.backendsurvivalweek10.dtos.ProductListDto;
import kr.megaptera.backendsurvivalweek10.dtos.product.ProductListDto;
import kr.megaptera.backendsurvivalweek10.infrastructure.ProductDtoFetcher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@
import kr.megaptera.backendsurvivalweek10.application.cart.AddProductToCartService;
import kr.megaptera.backendsurvivalweek10.application.cart.ChangeCartItemQuantityService;
import kr.megaptera.backendsurvivalweek10.application.cart.GetCartService;
import kr.megaptera.backendsurvivalweek10.dtos.AddCartLineItemDto;
import kr.megaptera.backendsurvivalweek10.dtos.CartDto;
import kr.megaptera.backendsurvivalweek10.dtos.ChangeCartLineItemDto;
import kr.megaptera.backendsurvivalweek10.dtos.cart.AddCartLineItemDto;
import kr.megaptera.backendsurvivalweek10.dtos.cart.CartDto;
import kr.megaptera.backendsurvivalweek10.dtos.cart.ChangeCartLineItemDto;
import kr.megaptera.backendsurvivalweek10.models.LineItemId;
import kr.megaptera.backendsurvivalweek10.models.ProductId;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.annotation.Secured;
import org.springframework.web.bind.annotation.*;

import java.security.Principal;
import java.util.NoSuchElementException;

@RestController
Expand All @@ -30,28 +32,40 @@ public LineItemController(
}

@GetMapping
public CartDto list() {
return getCartService.getCartDto();
@Secured({"ROLE_USER", "ROLE_ADMIN"})
public CartDto list(Principal principal) {
String userId = principal.getName();

return getCartService.getCartDto(userId);
}

@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public void create(@RequestBody AddCartLineItemDto dto) {
@Secured({"ROLE_USER", "ROLE_ADMIN"})
public void create(
Principal principal,
@RequestBody AddCartLineItemDto dto) {
String userId = principal.getName();

ProductId productId = new ProductId(dto.productId());
int quantity = dto.quantity();

addProductToCartService.addProduct(productId, quantity);
addProductToCartService.addProduct(userId, productId, quantity);
}

@PatchMapping("{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
@Secured({"ROLE_USER", "ROLE_ADMIN"})
public void update(
Principal principal,
@PathVariable("id") String id,
@RequestBody ChangeCartLineItemDto dto) {
String userId = principal.getName();

LineItemId lineItemId = new LineItemId(id);
int quantity = dto.quantity();

changeCartItemQuantityService.changeQuantity(lineItemId, quantity);
changeCartItemQuantityService.changeQuantity(userId, lineItemId, quantity);
}

@ExceptionHandler(NoSuchElementException.class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@

import kr.megaptera.backendsurvivalweek10.application.product.CreateProductService;
import kr.megaptera.backendsurvivalweek10.application.product.GetProductListService;
import kr.megaptera.backendsurvivalweek10.dtos.CreateProductDto;
import kr.megaptera.backendsurvivalweek10.dtos.ProductListDto;
import kr.megaptera.backendsurvivalweek10.dtos.product.CreateProductDto;
import kr.megaptera.backendsurvivalweek10.dtos.product.ProductListDto;
import kr.megaptera.backendsurvivalweek10.models.Money;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.annotation.Secured;
import org.springframework.web.bind.annotation.*;

@RestController
Expand All @@ -27,6 +28,7 @@ public ProductListDto list() {

@PostMapping
@ResponseStatus(HttpStatus.CREATED)
@Secured("ROLE_ADMIN")
public void create(@RequestBody CreateProductDto dto) {
String name = dto.name().strip();
Money price = new Money(dto.price());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package kr.megaptera.backendsurvivalweek10.controllers;

import jakarta.validation.Valid;
import kr.megaptera.backendsurvivalweek10.application.auth.LoginService;
import kr.megaptera.backendsurvivalweek10.application.auth.LogoutService;
import kr.megaptera.backendsurvivalweek10.dtos.auth.LoginRequestDto;
import kr.megaptera.backendsurvivalweek10.dtos.auth.LoginResultDto;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.ExceptionHandler;
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.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/session")
public class SessionController {

private final LoginService loginService;
private final LogoutService logoutService;

public SessionController(LoginService loginService, LogoutService logoutService) {
this.loginService = loginService;
this.logoutService = logoutService;
}

@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public LoginResultDto login(
@Valid @RequestBody LoginRequestDto dto) {
return loginService.login(dto.username(), dto.password());
}

@DeleteMapping
@ResponseStatus(HttpStatus.NO_CONTENT)
public String logout(Authentication authentication) {
String accessToken = authentication.getCredentials().toString();

logoutService.logout(accessToken);

return "Logout";
}

@ExceptionHandler(BadCredentialsException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public String loginFailed() {
return "Bad Request";
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package kr.megaptera.backendsurvivalweek10.controllers;

import jakarta.validation.Valid;
import kr.megaptera.backendsurvivalweek10.application.auth.SignupService;
import kr.megaptera.backendsurvivalweek10.dtos.auth.SignupRequestDto;
import kr.megaptera.backendsurvivalweek10.dtos.auth.SignupResultDto;
import kr.megaptera.backendsurvivalweek10.exceptions.UserAlreadyExistsException;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
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.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/users")
public class UserController {
private final SignupService signupService;

public UserController(SignupService signupService) {
this.signupService = signupService;
}

@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public SignupResultDto signup(
@Valid @RequestBody SignupRequestDto signupRequestDto) {
return signupService.signup(
signupRequestDto.username().trim(),
signupRequestDto.password().trim());
}

@ExceptionHandler(UserAlreadyExistsException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public String alreadyExists() {
return "User already exists.";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package kr.megaptera.backendsurvivalweek10.controllers;

import org.springframework.security.access.annotation.Secured;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class WelcomeController {
@GetMapping("/")
public String home() {
return "Hello, world!";
}

@GetMapping("/admin")
@Secured("ROLE_ADMIN")
public String admin() {
return "Hello, world!";
}

@GetMapping("/user")
@Secured({"ROLE_USER", "ROLE_ADMIN"})
public String user() {
return "Hello, world!";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package kr.megaptera.backendsurvivalweek10.dtos.auth;

public record LoginRequestDto(
String username,
String password
) {
}
Loading

0 comments on commit 8aa21e3

Please sign in to comment.