Skip to content

Commit

Permalink
Merge pull request #30 from leung018/update-to-uuid
Browse files Browse the repository at this point in the history
Update-to-uuid
  • Loading branch information
leung018 authored Dec 30, 2024
2 parents bbee66f + ed3042b commit 71d07d4
Show file tree
Hide file tree
Showing 21 changed files with 156 additions and 118 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import java.time.Duration;
import java.time.Instant;
import java.util.Date;
import java.util.UUID;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import org.springframework.beans.factory.annotation.Value;
Expand Down Expand Up @@ -40,7 +41,7 @@ private Date getExpirationDate() {

public String generateAccessToken(User user) {
return Jwts.builder()
.subject(user.getId())
.subject(user.getId().toString())
.expiration(getExpirationDate())
.signWith(this.secretKey, Jwts.SIG.HS256)
.compact();
Expand All @@ -59,7 +60,7 @@ public UserAuthenticatedInfo parseAccessToken(String token) {
.parseSignedClaims(token)
.getPayload()
.getSubject();
return new UserAuthenticatedInfo(userId);
return new UserAuthenticatedInfo(UUID.fromString(userId));
} catch (Exception e) {
if (e instanceof ExpiredJwtException) {
throw new InvalidTokenException("Expired token");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
package com.leungcheng.spring_simple_backend.auth;

public record UserAuthenticatedInfo(String userId) {}
import java.util.UUID;

public record UserAuthenticatedInfo(UUID userId) {}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public Object getCredentials() {
}

@Override
public String getPrincipal() {
return userAuthenticatedInfo.userId();
public UserAuthenticatedInfo getPrincipal() {
return userAuthenticatedInfo;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ public class MeController {

@GetMapping("/me")
public UserAccountInfo me(UserAuthenticatedInfoToken authToken) {
String userId = authToken.getPrincipal();
User user = userRepository.findById(userId).orElseThrow();
User user = userRepository.findById(authToken.getPrincipal().userId()).orElseThrow();
return new UserAccountInfo(user.getUsername(), user.getBalance());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
import com.leungcheng.spring_simple_backend.domain.order.OrderService;
import com.leungcheng.spring_simple_backend.domain.order.PurchaseItems;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Size;
import java.util.Map;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PostMapping;
Expand All @@ -23,14 +23,13 @@ public class OrderController {
Order newOrder(
@Valid @RequestBody CreateOrderRequest createOrderRequest,
UserAuthenticatedInfoToken authToken) {
String userId = authToken.getPrincipal();
PurchaseItems purchaseItems = new PurchaseItems();
for (var entry : createOrderRequest.productIdToQuantity().entrySet()) {
purchaseItems.setPurchaseItem(entry.getKey(), entry.getValue());
}
return orderService.createOrder(userId, purchaseItems, createOrderRequest.requestId());
return orderService.createOrder(
authToken.getPrincipal().userId(), purchaseItems, createOrderRequest.requestId());
}

public record CreateOrderRequest(
@Size(max = 36) String requestId, Map<String, Integer> productIdToQuantity) {}
public record CreateOrderRequest(UUID requestId, Map<UUID, Integer> productIdToQuantity) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import com.leungcheng.spring_simple_backend.domain.ProductRepository;
import jakarta.validation.Valid;
import java.math.BigDecimal;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;
Expand All @@ -18,19 +19,18 @@ public class ProductController {
Product newProduct(
@Valid @RequestBody CreateProductRequest createProductRequest,
UserAuthenticatedInfoToken authToken) {
String userId = authToken.getPrincipal();
Product product =
new Product.Builder()
.name(createProductRequest.name())
.price(createProductRequest.price())
.quantity(createProductRequest.quantity())
.userId(userId)
.userId(authToken.getPrincipal().userId())
.build();
return repository.save(product);
}

@GetMapping("/products/{id}")
Product one(@PathVariable String id) {
Product one(@PathVariable UUID id) {
return repository.findById(id).orElseThrow(() -> new ProductNotFoundException(id));
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.leungcheng.spring_simple_backend.controller;

import java.util.UUID;

class ProductNotFoundException extends RuntimeException {
ProductNotFoundException(String id) {
ProductNotFoundException(UUID id) {
super("Could not find product " + id);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
import jakarta.persistence.Table;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.util.UUID;

@Entity
@Table(name = "products")
Expand All @@ -17,10 +19,10 @@ public static class Builder {
private String name;
private BigDecimal price;
private int quantity;
private String userId;
private String id = java.util.UUID.randomUUID().toString();
private UUID userId;
private UUID id = UUID.randomUUID();

private Builder id(String id) {
private Builder id(UUID id) {
this.id = id;
return this;
}
Expand All @@ -40,7 +42,7 @@ public Builder quantity(int quantity) {
return this;
}

public Builder userId(String userId) {
public Builder userId(UUID userId) {
this.userId = userId;
return this;
}
Expand All @@ -66,9 +68,9 @@ public Builder toBuilder() {

@Id
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
private String id;
private UUID id;

@NotBlank private String userId;
@NotNull private UUID userId;

@NotBlank private String name;

Expand All @@ -79,11 +81,11 @@ public Builder toBuilder() {
@Min(0)
private int quantity;

public String getId() {
public UUID getId() {
return id;
}

public String getUserId() {
public UUID getUserId() {
return userId;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.leungcheng.spring_simple_backend.domain;

import java.util.UUID;
import org.springframework.data.repository.CrudRepository;

public interface ProductRepository extends CrudRepository<Product, String> {}
public interface ProductRepository extends CrudRepository<Product, UUID> {}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.math.BigDecimal;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

Expand All @@ -22,9 +23,9 @@ public static class Builder {
private String username;
private String password;
private BigDecimal balance;
private String id = java.util.UUID.randomUUID().toString();
private UUID id = java.util.UUID.randomUUID();

private Builder id(String id) {
private Builder id(UUID id) {
this.id = id;
return this;
}
Expand Down Expand Up @@ -63,7 +64,7 @@ public User.Builder toBuilder() {
return new User.Builder().username(username).password(password).balance(balance).id(id);
}

@Id private String id;
@Id private UUID id;

@Column(unique = true)
@NotBlank
Expand All @@ -80,7 +81,7 @@ public Collection<? extends GrantedAuthority> getAuthorities() {
return List.of(); // TODO: May be not return empty list
}

public String getId() {
public UUID getId() {
return id;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package com.leungcheng.spring_simple_backend.domain;

import java.util.Optional;
import java.util.UUID;
import org.springframework.data.repository.CrudRepository;

public interface UserRepository extends CrudRepository<User, String> {
public interface UserRepository extends CrudRepository<User, UUID> {
Optional<User> findByUsername(String username);
}
Original file line number Diff line number Diff line change
@@ -1,39 +1,40 @@
package com.leungcheng.spring_simple_backend.domain.order;

import jakarta.persistence.*;
import java.util.UUID;

@Entity
@Table(
name = "orders",
uniqueConstraints = {@UniqueConstraint(columnNames = {"requestId", "buyerUserId"})})
public class Order {
@Id private final String id = java.util.UUID.randomUUID().toString();
private String buyerUserId;
@Id private final UUID id = UUID.randomUUID();
private UUID buyerUserId;
private PurchaseItems purchaseItems;

private String requestId;
private UUID requestId;

private Order() {}

Order(String buyerUserId, PurchaseItems purchaseItems, String requestId) {
Order(UUID buyerUserId, PurchaseItems purchaseItems, UUID requestId) {
this.buyerUserId = buyerUserId;
this.purchaseItems = purchaseItems;
this.requestId = requestId;
}

public String getId() {
public UUID getId() {
return id;
}

public String getBuyerUserId() {
public UUID getBuyerUserId() {
return buyerUserId;
}

public PurchaseItems getPurchaseItems() {
return purchaseItems;
}

public String getRequestId() {
public UUID getRequestId() {
return requestId;
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package com.leungcheng.spring_simple_backend.domain.order;

import java.util.Optional;
import java.util.UUID;
import org.springframework.data.repository.CrudRepository;

public interface OrderRepository extends CrudRepository<Order, String> {
Optional<Order> findByBuyerUserIdAndRequestId(String buyerUserId, String requestId);
public interface OrderRepository extends CrudRepository<Order, UUID> {
Optional<Order> findByBuyerUserIdAndRequestId(UUID buyerUserId, UUID requestId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.math.BigDecimal;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.retry.annotation.Retryable;
import org.springframework.stereotype.Service;
Expand All @@ -25,7 +26,7 @@ public static class CreateOrderException extends MyIllegalArgumentException {
// Add this static method to reduce duplication because one test in api level is interested in
// this message. But it may not be necessary to move other error messages to this class until we
// need them.
public static String insufficientStockMsg(String productId) {
public static String insufficientStockMsg(UUID productId) {
return "Insufficient stock for product: " + productId;
}

Expand All @@ -36,7 +37,11 @@ public CreateOrderException(String message) {

@Retryable(noRetryFor = CreateOrderException.class)
@Transactional(isolation = Isolation.SERIALIZABLE)
public Order createOrder(String buyerUserId, PurchaseItems purchaseItems, String requestId) {
public Order createOrder(UUID buyerUserId, PurchaseItems purchaseItems, UUID requestId) {
if (requestId == null) {
throw new CreateOrderException("Request ID cannot be null");
}

Optional<Order> order = orderRepository.findByBuyerUserIdAndRequestId(buyerUserId, requestId);
if (order.isPresent()) {
return order.get();
Expand All @@ -55,7 +60,7 @@ public Order createOrder(String buyerUserId, PurchaseItems purchaseItems, String
return addNewOrder(buyerUserId, purchaseItems, requestId);
}

private Optional<User> getUser(String userId) {
private Optional<User> getUser(UUID userId) {
return userRepository.findById(userId);
}

Expand All @@ -64,20 +69,20 @@ private void saveNewBalance(User buyer, BigDecimal newBalance) {
userRepository.save(updatedBuyer);
}

private Order addNewOrder(String buyerUserId, PurchaseItems purchaseItems, String requestId) {
private Order addNewOrder(UUID buyerUserId, PurchaseItems purchaseItems, UUID requestId) {
Order order = new Order(buyerUserId, purchaseItems, requestId);
return orderRepository.save(order);
}

private BigDecimal processPurchaseItems(PurchaseItems purchaseItems) {
ImmutableMap<String, Integer> productIdToQuantity = purchaseItems.getProductIdToQuantity();
ImmutableMap<UUID, Integer> productIdToQuantity = purchaseItems.getProductIdToQuantity();
if (productIdToQuantity.isEmpty()) {
throw new CreateOrderException("Purchase items cannot be empty");
}

BigDecimal totalCost = BigDecimal.ZERO;
for (Map.Entry<String, Integer> entry : productIdToQuantity.entrySet()) {
String productId = entry.getKey();
for (Map.Entry<UUID, Integer> entry : productIdToQuantity.entrySet()) {
UUID productId = entry.getKey();
int purchaseQuantity = entry.getValue();
Product product = getProduct(productId);

Expand Down Expand Up @@ -106,7 +111,7 @@ private void addProfitToSeller(Product product, int purchaseQuantity) {
saveNewBalance(seller, newBalance);
}

private Product getProduct(String productId) {
private Product getProduct(UUID productId) {
return productRepository
.findById(productId)
.orElseThrow(() -> new CreateOrderException("Product: " + productId + " does not exist"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import com.leungcheng.spring_simple_backend.validation.MyIllegalArgumentException;
import jakarta.persistence.*;
import java.util.Map;
import java.util.UUID;

@Embeddable
public class PurchaseItems {
Expand All @@ -15,16 +16,16 @@ public class PurchaseItems {
joinColumns = {@JoinColumn(name = "order_id", referencedColumnName = "id")})
@MapKeyColumn(name = "product_id")
@Column(name = "quantity")
private final Map<String, Integer> productIdToQuantity = new java.util.HashMap<>();
private final Map<UUID, Integer> productIdToQuantity = new java.util.HashMap<>();

public void setPurchaseItem(String productId, int quantity) {
public void setPurchaseItem(UUID productId, int quantity) {
if (quantity < 1) {
throw new MyIllegalArgumentException(INVALID_QUANTITY_MSG);
}
productIdToQuantity.put(productId, quantity);
}

public ImmutableMap<String, Integer> getProductIdToQuantity() {
public ImmutableMap<UUID, Integer> getProductIdToQuantity() {
return ImmutableMap.copyOf(productIdToQuantity);
}
}
Loading

0 comments on commit 71d07d4

Please sign in to comment.