From 1878ed8fe41d5da8781cd3209eb2b0a405171f60 Mon Sep 17 00:00:00 2001 From: Phan Huy Tran Date: Wed, 2 Apr 2025 09:15:37 +0200 Subject: [PATCH 1/6] feat: create lootbox and rewards entity --- .../szut/casino/lootboxes/LootBoxEntity.java | 34 +++++++++++++++++++ .../szut/casino/lootboxes/RewardEntity.java | 28 +++++++++++++++ .../src/main/resources/application.properties | 2 +- 3 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 backend/src/main/java/de/szut/casino/lootboxes/LootBoxEntity.java create mode 100644 backend/src/main/java/de/szut/casino/lootboxes/RewardEntity.java diff --git a/backend/src/main/java/de/szut/casino/lootboxes/LootBoxEntity.java b/backend/src/main/java/de/szut/casino/lootboxes/LootBoxEntity.java new file mode 100644 index 0000000..7138bf3 --- /dev/null +++ b/backend/src/main/java/de/szut/casino/lootboxes/LootBoxEntity.java @@ -0,0 +1,34 @@ +package de.szut.casino.lootboxes; + +import com.fasterxml.jackson.annotation.JsonBackReference; +import com.fasterxml.jackson.annotation.JsonIgnore; +import de.szut.casino.blackjack.CardEntity; +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.hibernate.annotations.SQLRestriction; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +@Entity +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class LootBoxEntity { + @Id + @GeneratedValue + private Long id; + + private String name; + + @Column(precision = 19, scale = 2) + private BigDecimal price; + + @OneToMany(mappedBy = "lootBox", cascade = CascadeType.ALL, orphanRemoval = true) + private List rewards = new ArrayList<>(); +} diff --git a/backend/src/main/java/de/szut/casino/lootboxes/RewardEntity.java b/backend/src/main/java/de/szut/casino/lootboxes/RewardEntity.java new file mode 100644 index 0000000..0c1d21d --- /dev/null +++ b/backend/src/main/java/de/szut/casino/lootboxes/RewardEntity.java @@ -0,0 +1,28 @@ +package de.szut.casino.lootboxes; + +import com.fasterxml.jackson.annotation.JsonBackReference; +import com.fasterxml.jackson.annotation.JsonManagedReference; +import de.szut.casino.blackjack.BlackJackGameEntity; +import jakarta.persistence.*; + +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +@Entity +public class RewardEntity { + @Id + @GeneratedValue + private Long id; + + @Column(precision = 19, scale = 2) + private BigDecimal value; + + @Column(precision = 5, scale = 2) + private BigDecimal probability; + + @ManyToOne + @JoinColumn(name = "lootBox_id", nullable = false) + @JsonBackReference + private LootBoxEntity lootBox; +} diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index a02bc80..e42fba6 100644 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -2,7 +2,7 @@ spring.datasource.url=jdbc:postgresql://${DB_HOST:localhost}:5432/postgresdb spring.datasource.username=postgres_user spring.datasource.password=postgres_pass server.port=8080 -spring.jpa.hibernate.ddl-auto=update +spring.jpa.hibernate.ddl-auto=create-drop stripe.secret.key=${STRIPE_SECRET_KEY:sk_test_51QrePYIvCfqz7ANgqam8rEwWcMeKiLOof3j6SCMgu2sl4sESP45DJxca16mWcYo1sQaiBv32CMR6Z4AAAGQPCJo300ubuZKO8I} stripe.webhook.secret=whsec_746b6a488665f6057118bdb4a2b32f4916f16c277109eeaed5e8f8e8b81b8c15 app.frontend-host=http://localhost:4200 From 084d478cd9e5b2387b0355c371635bdb9fb8cd80 Mon Sep 17 00:00:00 2001 From: Phan Huy Tran Date: Wed, 2 Apr 2025 09:18:17 +0200 Subject: [PATCH 2/6] feat: create repositories --- .../java/de/szut/casino/lootboxes/LootBoxRepository.java | 9 +++++++++ .../java/de/szut/casino/lootboxes/RewardRepository.java | 8 ++++++++ 2 files changed, 17 insertions(+) create mode 100644 backend/src/main/java/de/szut/casino/lootboxes/LootBoxRepository.java create mode 100644 backend/src/main/java/de/szut/casino/lootboxes/RewardRepository.java diff --git a/backend/src/main/java/de/szut/casino/lootboxes/LootBoxRepository.java b/backend/src/main/java/de/szut/casino/lootboxes/LootBoxRepository.java new file mode 100644 index 0000000..96ba188 --- /dev/null +++ b/backend/src/main/java/de/szut/casino/lootboxes/LootBoxRepository.java @@ -0,0 +1,9 @@ +package de.szut.casino.lootboxes; + +import de.szut.casino.blackjack.BlackJackGameEntity; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Service; + +@Service +public interface LootBoxRepository extends JpaRepository { +} diff --git a/backend/src/main/java/de/szut/casino/lootboxes/RewardRepository.java b/backend/src/main/java/de/szut/casino/lootboxes/RewardRepository.java new file mode 100644 index 0000000..7878000 --- /dev/null +++ b/backend/src/main/java/de/szut/casino/lootboxes/RewardRepository.java @@ -0,0 +1,8 @@ +package de.szut.casino.lootboxes; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Service; + +@Service +public interface RewardRepository extends JpaRepository { +} From e4bcd9d7910300ef47fb5de37a763377ae542f78 Mon Sep 17 00:00:00 2001 From: Phan Huy Tran Date: Wed, 2 Apr 2025 10:08:23 +0200 Subject: [PATCH 3/6] refactor: use many to many relation for lootboxes and rewards --- .../de/szut/casino/CasinoApplication.java | 69 +++++++++++++++++++ .../szut/casino/lootboxes/LootBoxEntity.java | 7 +- .../casino/lootboxes/LootBoxRepository.java | 1 - .../szut/casino/lootboxes/RewardEntity.java | 12 ++-- 4 files changed, 81 insertions(+), 8 deletions(-) diff --git a/backend/src/main/java/de/szut/casino/CasinoApplication.java b/backend/src/main/java/de/szut/casino/CasinoApplication.java index 8c99f02..cc22e2c 100644 --- a/backend/src/main/java/de/szut/casino/CasinoApplication.java +++ b/backend/src/main/java/de/szut/casino/CasinoApplication.java @@ -1,10 +1,19 @@ package de.szut.casino; +import de.szut.casino.lootboxes.LootBoxEntity; +import de.szut.casino.lootboxes.LootBoxRepository; +import de.szut.casino.lootboxes.RewardEntity; +import de.szut.casino.lootboxes.RewardRepository; +import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; +import java.math.BigDecimal; +import java.util.Arrays; +import java.util.List; + @SpringBootApplication public class CasinoApplication { @@ -16,4 +25,64 @@ public class CasinoApplication { public static RestTemplate restTemplate() { return new RestTemplate(); } + + @Bean + public CommandLineRunner initData(LootBoxRepository lootBoxRepository, RewardRepository rewardRepository) { + return _ -> { + if (lootBoxRepository.count() == 0) { + // Create basic LootBox + LootBoxEntity basicLootBox = new LootBoxEntity(); + basicLootBox.setName("Basic LootBox"); + basicLootBox.setPrice(new BigDecimal("1.99")); + + // Create premium LootBox + LootBoxEntity premiumLootBox = new LootBoxEntity(); + premiumLootBox.setName("Premium LootBox"); + premiumLootBox.setPrice(new BigDecimal("4.99")); + + // Save LootBoxes first to get IDs + lootBoxRepository.saveAll(Arrays.asList(basicLootBox, premiumLootBox)); + + // Create rewards for basic LootBox + RewardEntity commonReward = new RewardEntity(); + commonReward.setValue(new BigDecimal("0.50")); + commonReward.setProbability(new BigDecimal("70.00")); + commonReward.setLootBoxes(List.of(premiumLootBox)); + + RewardEntity rareReward = new RewardEntity(); + rareReward.setValue(new BigDecimal("2.00")); + rareReward.setProbability(new BigDecimal("25.00")); + rareReward.setLootBoxes(List.of(basicLootBox)); + + RewardEntity epicReward = new RewardEntity(); + epicReward.setValue(new BigDecimal("5.00")); + epicReward.setProbability(new BigDecimal("5.00")); + epicReward.setLootBoxes(List.of(basicLootBox)); + + // Create rewards for premium LootBox + RewardEntity premiumCommon = new RewardEntity(); + premiumCommon.setValue(new BigDecimal("2.00")); + premiumCommon.setProbability(new BigDecimal("60.00")); + premiumCommon.setLootBoxes(List.of(premiumLootBox)); + + RewardEntity premiumRare = new RewardEntity(); + premiumRare.setValue(new BigDecimal("5.00")); + premiumRare.setProbability(new BigDecimal("30.00")); + premiumRare.setLootBoxes(List.of(premiumLootBox)); + + RewardEntity legendaryReward = new RewardEntity(); + legendaryReward.setValue(new BigDecimal("15.00")); + legendaryReward.setProbability(new BigDecimal("10.00")); + legendaryReward.setLootBoxes(List.of(premiumLootBox)); + + rewardRepository.saveAll(Arrays.asList( + commonReward, rareReward, epicReward, + premiumCommon, premiumRare, legendaryReward + )); + System.out.println("Initial LootBoxes and rewards created successfully"); + } else { + System.out.println("LootBoxes already exist, skipping initialization"); + } + }; + } } diff --git a/backend/src/main/java/de/szut/casino/lootboxes/LootBoxEntity.java b/backend/src/main/java/de/szut/casino/lootboxes/LootBoxEntity.java index 7138bf3..bd6c588 100644 --- a/backend/src/main/java/de/szut/casino/lootboxes/LootBoxEntity.java +++ b/backend/src/main/java/de/szut/casino/lootboxes/LootBoxEntity.java @@ -29,6 +29,11 @@ public class LootBoxEntity { @Column(precision = 19, scale = 2) private BigDecimal price; - @OneToMany(mappedBy = "lootBox", cascade = CascadeType.ALL, orphanRemoval = true) + @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}) + @JoinTable( + name = "lootbox_reward", + joinColumns = @JoinColumn(name = "lootbox_id"), + inverseJoinColumns = @JoinColumn(name = "reward_id") + ) private List rewards = new ArrayList<>(); } diff --git a/backend/src/main/java/de/szut/casino/lootboxes/LootBoxRepository.java b/backend/src/main/java/de/szut/casino/lootboxes/LootBoxRepository.java index 96ba188..472388e 100644 --- a/backend/src/main/java/de/szut/casino/lootboxes/LootBoxRepository.java +++ b/backend/src/main/java/de/szut/casino/lootboxes/LootBoxRepository.java @@ -1,6 +1,5 @@ package de.szut.casino.lootboxes; -import de.szut.casino.blackjack.BlackJackGameEntity; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Service; diff --git a/backend/src/main/java/de/szut/casino/lootboxes/RewardEntity.java b/backend/src/main/java/de/szut/casino/lootboxes/RewardEntity.java index 0c1d21d..97ad6d1 100644 --- a/backend/src/main/java/de/szut/casino/lootboxes/RewardEntity.java +++ b/backend/src/main/java/de/szut/casino/lootboxes/RewardEntity.java @@ -1,14 +1,16 @@ package de.szut.casino.lootboxes; import com.fasterxml.jackson.annotation.JsonBackReference; -import com.fasterxml.jackson.annotation.JsonManagedReference; -import de.szut.casino.blackjack.BlackJackGameEntity; import jakarta.persistence.*; +import lombok.Getter; +import lombok.Setter; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; +@Getter +@Setter @Entity public class RewardEntity { @Id @@ -21,8 +23,6 @@ public class RewardEntity { @Column(precision = 5, scale = 2) private BigDecimal probability; - @ManyToOne - @JoinColumn(name = "lootBox_id", nullable = false) - @JsonBackReference - private LootBoxEntity lootBox; + @ManyToMany(mappedBy = "rewards") + private List lootBoxes = new ArrayList<>(); } From 8a6bc95c920a197011d0ff488da178856f068bf2 Mon Sep 17 00:00:00 2001 From: Phan Huy Tran Date: Wed, 2 Apr 2025 10:18:51 +0200 Subject: [PATCH 4/6] feat: add route to get all lootboxes --- backend/requests/lootboxes.http | 4 +++ .../de/szut/casino/CasinoApplication.java | 29 ++++++++++++------- .../casino/lootboxes/LootBoxController.java | 20 +++++++++++++ .../szut/casino/lootboxes/LootBoxEntity.java | 1 + .../szut/casino/lootboxes/RewardEntity.java | 2 ++ 5 files changed, 45 insertions(+), 11 deletions(-) create mode 100644 backend/requests/lootboxes.http create mode 100644 backend/src/main/java/de/szut/casino/lootboxes/LootBoxController.java diff --git a/backend/requests/lootboxes.http b/backend/requests/lootboxes.http new file mode 100644 index 0000000..2c7fe2e --- /dev/null +++ b/backend/requests/lootboxes.http @@ -0,0 +1,4 @@ +GET http://localhost:8080/lootboxes +Authorization: Bearer {{token}} +Content-Type: application/json + diff --git a/backend/src/main/java/de/szut/casino/CasinoApplication.java b/backend/src/main/java/de/szut/casino/CasinoApplication.java index cc22e2c..2499781 100644 --- a/backend/src/main/java/de/szut/casino/CasinoApplication.java +++ b/backend/src/main/java/de/szut/casino/CasinoApplication.java @@ -11,6 +11,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; import java.math.BigDecimal; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -30,55 +31,61 @@ public class CasinoApplication { public CommandLineRunner initData(LootBoxRepository lootBoxRepository, RewardRepository rewardRepository) { return _ -> { if (lootBoxRepository.count() == 0) { - // Create basic LootBox LootBoxEntity basicLootBox = new LootBoxEntity(); basicLootBox.setName("Basic LootBox"); basicLootBox.setPrice(new BigDecimal("1.99")); + basicLootBox.setRewards(new ArrayList<>()); // Initialize the list - // Create premium LootBox LootBoxEntity premiumLootBox = new LootBoxEntity(); premiumLootBox.setName("Premium LootBox"); premiumLootBox.setPrice(new BigDecimal("4.99")); + premiumLootBox.setRewards(new ArrayList<>()); // Initialize the list - // Save LootBoxes first to get IDs + // Save the loot boxes first lootBoxRepository.saveAll(Arrays.asList(basicLootBox, premiumLootBox)); - // Create rewards for basic LootBox RewardEntity commonReward = new RewardEntity(); commonReward.setValue(new BigDecimal("0.50")); commonReward.setProbability(new BigDecimal("70.00")); - commonReward.setLootBoxes(List.of(premiumLootBox)); RewardEntity rareReward = new RewardEntity(); rareReward.setValue(new BigDecimal("2.00")); rareReward.setProbability(new BigDecimal("25.00")); - rareReward.setLootBoxes(List.of(basicLootBox)); RewardEntity epicReward = new RewardEntity(); epicReward.setValue(new BigDecimal("5.00")); epicReward.setProbability(new BigDecimal("5.00")); - epicReward.setLootBoxes(List.of(basicLootBox)); - // Create rewards for premium LootBox RewardEntity premiumCommon = new RewardEntity(); premiumCommon.setValue(new BigDecimal("2.00")); premiumCommon.setProbability(new BigDecimal("60.00")); - premiumCommon.setLootBoxes(List.of(premiumLootBox)); RewardEntity premiumRare = new RewardEntity(); premiumRare.setValue(new BigDecimal("5.00")); premiumRare.setProbability(new BigDecimal("30.00")); - premiumRare.setLootBoxes(List.of(premiumLootBox)); RewardEntity legendaryReward = new RewardEntity(); legendaryReward.setValue(new BigDecimal("15.00")); legendaryReward.setProbability(new BigDecimal("10.00")); - legendaryReward.setLootBoxes(List.of(premiumLootBox)); + // Save all rewards rewardRepository.saveAll(Arrays.asList( commonReward, rareReward, epicReward, premiumCommon, premiumRare, legendaryReward )); + + // Add relationships from the owning side (LootBox) + basicLootBox.getRewards().add(rareReward); + basicLootBox.getRewards().add(epicReward); + + premiumLootBox.getRewards().add(commonReward); + premiumLootBox.getRewards().add(premiumCommon); + premiumLootBox.getRewards().add(premiumRare); + premiumLootBox.getRewards().add(legendaryReward); + + // Update the loot boxes to save the relationships + lootBoxRepository.saveAll(Arrays.asList(basicLootBox, premiumLootBox)); + System.out.println("Initial LootBoxes and rewards created successfully"); } else { System.out.println("LootBoxes already exist, skipping initialization"); diff --git a/backend/src/main/java/de/szut/casino/lootboxes/LootBoxController.java b/backend/src/main/java/de/szut/casino/lootboxes/LootBoxController.java new file mode 100644 index 0000000..c885b5d --- /dev/null +++ b/backend/src/main/java/de/szut/casino/lootboxes/LootBoxController.java @@ -0,0 +1,20 @@ +package de.szut.casino.lootboxes; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +@RestController +public class LootBoxController { + private final LootBoxRepository lootBoxRepository; + + public LootBoxController(LootBoxRepository lootBoxRepository) { + this.lootBoxRepository = lootBoxRepository; + } + + @GetMapping("/lootboxes") + public List getAllLootBoxes() { + return lootBoxRepository.findAll(); + } +} diff --git a/backend/src/main/java/de/szut/casino/lootboxes/LootBoxEntity.java b/backend/src/main/java/de/szut/casino/lootboxes/LootBoxEntity.java index bd6c588..49eb532 100644 --- a/backend/src/main/java/de/szut/casino/lootboxes/LootBoxEntity.java +++ b/backend/src/main/java/de/szut/casino/lootboxes/LootBoxEntity.java @@ -2,6 +2,7 @@ package de.szut.casino.lootboxes; import com.fasterxml.jackson.annotation.JsonBackReference; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonManagedReference; import de.szut.casino.blackjack.CardEntity; import jakarta.persistence.*; import lombok.AllArgsConstructor; diff --git a/backend/src/main/java/de/szut/casino/lootboxes/RewardEntity.java b/backend/src/main/java/de/szut/casino/lootboxes/RewardEntity.java index 97ad6d1..ce0c155 100644 --- a/backend/src/main/java/de/szut/casino/lootboxes/RewardEntity.java +++ b/backend/src/main/java/de/szut/casino/lootboxes/RewardEntity.java @@ -1,6 +1,7 @@ package de.szut.casino.lootboxes; import com.fasterxml.jackson.annotation.JsonBackReference; +import com.fasterxml.jackson.annotation.JsonManagedReference; import jakarta.persistence.*; import lombok.Getter; import lombok.Setter; @@ -24,5 +25,6 @@ public class RewardEntity { private BigDecimal probability; @ManyToMany(mappedBy = "rewards") + @JsonBackReference private List lootBoxes = new ArrayList<>(); } From b963595ab4ab0170b5f4e0233d5c3ce9183d19b1 Mon Sep 17 00:00:00 2001 From: Phan Huy Tran Date: Wed, 2 Apr 2025 11:04:20 +0200 Subject: [PATCH 5/6] feat: manage balance --- backend/requests/lootboxes.http | 5 ++ .../de/szut/casino/CasinoApplication.java | 21 +++---- .../casino/lootboxes/LootBoxController.java | 62 ++++++++++++++++++- .../src/main/resources/application.properties | 2 +- 4 files changed, 75 insertions(+), 15 deletions(-) diff --git a/backend/requests/lootboxes.http b/backend/requests/lootboxes.http index 2c7fe2e..126d237 100644 --- a/backend/requests/lootboxes.http +++ b/backend/requests/lootboxes.http @@ -2,3 +2,8 @@ GET http://localhost:8080/lootboxes Authorization: Bearer {{token}} Content-Type: application/json +### + +POST http://localhost:8080/lootboxes/1 +Authorization: Bearer {{token}} +Content-Type: application/json \ No newline at end of file diff --git a/backend/src/main/java/de/szut/casino/CasinoApplication.java b/backend/src/main/java/de/szut/casino/CasinoApplication.java index 2499781..4b47f5c 100644 --- a/backend/src/main/java/de/szut/casino/CasinoApplication.java +++ b/backend/src/main/java/de/szut/casino/CasinoApplication.java @@ -33,12 +33,12 @@ public class CasinoApplication { if (lootBoxRepository.count() == 0) { LootBoxEntity basicLootBox = new LootBoxEntity(); basicLootBox.setName("Basic LootBox"); - basicLootBox.setPrice(new BigDecimal("1.99")); + basicLootBox.setPrice(new BigDecimal("2")); basicLootBox.setRewards(new ArrayList<>()); // Initialize the list LootBoxEntity premiumLootBox = new LootBoxEntity(); premiumLootBox.setName("Premium LootBox"); - premiumLootBox.setPrice(new BigDecimal("4.99")); + premiumLootBox.setPrice(new BigDecimal("5")); premiumLootBox.setRewards(new ArrayList<>()); // Initialize the list // Save the loot boxes first @@ -46,27 +46,27 @@ public class CasinoApplication { RewardEntity commonReward = new RewardEntity(); commonReward.setValue(new BigDecimal("0.50")); - commonReward.setProbability(new BigDecimal("70.00")); + commonReward.setProbability(new BigDecimal("0.7")); RewardEntity rareReward = new RewardEntity(); rareReward.setValue(new BigDecimal("2.00")); - rareReward.setProbability(new BigDecimal("25.00")); + rareReward.setProbability(new BigDecimal("0.25")); RewardEntity epicReward = new RewardEntity(); epicReward.setValue(new BigDecimal("5.00")); - epicReward.setProbability(new BigDecimal("5.00")); + epicReward.setProbability(new BigDecimal("0.5")); RewardEntity premiumCommon = new RewardEntity(); premiumCommon.setValue(new BigDecimal("2.00")); - premiumCommon.setProbability(new BigDecimal("60.00")); + premiumCommon.setProbability(new BigDecimal("0.6")); RewardEntity premiumRare = new RewardEntity(); premiumRare.setValue(new BigDecimal("5.00")); - premiumRare.setProbability(new BigDecimal("30.00")); + premiumRare.setProbability(new BigDecimal("0.3")); RewardEntity legendaryReward = new RewardEntity(); legendaryReward.setValue(new BigDecimal("15.00")); - legendaryReward.setProbability(new BigDecimal("10.00")); + legendaryReward.setProbability(new BigDecimal("0.10")); // Save all rewards rewardRepository.saveAll(Arrays.asList( @@ -75,10 +75,9 @@ public class CasinoApplication { )); // Add relationships from the owning side (LootBox) - basicLootBox.getRewards().add(rareReward); - basicLootBox.getRewards().add(epicReward); + basicLootBox.getRewards().add(commonReward); + basicLootBox.getRewards().add(premiumRare); - premiumLootBox.getRewards().add(commonReward); premiumLootBox.getRewards().add(premiumCommon); premiumLootBox.getRewards().add(premiumRare); premiumLootBox.getRewards().add(legendaryReward); diff --git a/backend/src/main/java/de/szut/casino/lootboxes/LootBoxController.java b/backend/src/main/java/de/szut/casino/lootboxes/LootBoxController.java index c885b5d..716b02a 100644 --- a/backend/src/main/java/de/szut/casino/lootboxes/LootBoxController.java +++ b/backend/src/main/java/de/szut/casino/lootboxes/LootBoxController.java @@ -1,20 +1,76 @@ package de.szut.casino.lootboxes; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; +import de.szut.casino.user.UserEntity; +import de.szut.casino.user.UserRepository; +import de.szut.casino.user.UserService; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; +import java.math.BigDecimal; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.Optional; @RestController public class LootBoxController { private final LootBoxRepository lootBoxRepository; + private final UserRepository userRepository; + private final UserService userService; - public LootBoxController(LootBoxRepository lootBoxRepository) { + public LootBoxController(LootBoxRepository lootBoxRepository, UserRepository userRepository, UserService userService) { this.lootBoxRepository = lootBoxRepository; + this.userRepository = userRepository; + this.userService = userService; } @GetMapping("/lootboxes") public List getAllLootBoxes() { return lootBoxRepository.findAll(); } + + @PostMapping("/lootboxes/{id}") + public ResponseEntity purchaseLootBox(@PathVariable Long id, @RequestHeader("Authorization") String token) { + Optional optionalLootBox = lootBoxRepository.findById(id); + if (optionalLootBox.isEmpty()) { + return ResponseEntity.notFound().build(); + } + + LootBoxEntity lootBox = optionalLootBox.get(); + RewardEntity reward = determineReward(lootBox); + + Optional optionalUser = userService.getCurrentUser(token); + if (optionalUser.isEmpty()) { + return ResponseEntity.notFound().build(); + } + + UserEntity user = optionalUser.get(); + + if (user.getBalance().compareTo(lootBox.getPrice()) < 0) { + Map errorResponse = new HashMap<>(); + errorResponse.put("error", "Insufficient balance"); + return ResponseEntity.badRequest().body(errorResponse); + } + + user.setBalance(user.getBalance().subtract(lootBox.getPrice())); + user.setBalance(user.getBalance().add(reward.getValue())); + userRepository.save(user); + + return ResponseEntity.ok(determineReward(lootBox)); + } + + public RewardEntity determineReward(LootBoxEntity lootBox) { + double randomValue = Math.random(); + BigDecimal cumulativeProbability = BigDecimal.ZERO; + + for (RewardEntity reward : lootBox.getRewards()) { + cumulativeProbability = cumulativeProbability.add(reward.getProbability()); + if (randomValue <= cumulativeProbability.doubleValue()) { + return reward; + } + } + + return lootBox.getRewards().getLast(); + } + } diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties index e42fba6..a02bc80 100644 --- a/backend/src/main/resources/application.properties +++ b/backend/src/main/resources/application.properties @@ -2,7 +2,7 @@ spring.datasource.url=jdbc:postgresql://${DB_HOST:localhost}:5432/postgresdb spring.datasource.username=postgres_user spring.datasource.password=postgres_pass server.port=8080 -spring.jpa.hibernate.ddl-auto=create-drop +spring.jpa.hibernate.ddl-auto=update stripe.secret.key=${STRIPE_SECRET_KEY:sk_test_51QrePYIvCfqz7ANgqam8rEwWcMeKiLOof3j6SCMgu2sl4sESP45DJxca16mWcYo1sQaiBv32CMR6Z4AAAGQPCJo300ubuZKO8I} stripe.webhook.secret=whsec_746b6a488665f6057118bdb4a2b32f4916f16c277109eeaed5e8f8e8b81b8c15 app.frontend-host=http://localhost:4200 From 948240ba1e61d404adad56b4ed6ac96869ea7c23 Mon Sep 17 00:00:00 2001 From: Phan Huy Tran Date: Wed, 2 Apr 2025 11:15:08 +0200 Subject: [PATCH 6/6] fix: fix wrong reward getting returned, refactor to service --- backend/requests/lootboxes.http | 2 +- .../de/szut/casino/CasinoApplication.java | 4 -- .../casino/lootboxes/LootBoxController.java | 32 ++++----------- .../szut/casino/lootboxes/LootBoxService.java | 40 +++++++++++++++++++ 4 files changed, 48 insertions(+), 30 deletions(-) create mode 100644 backend/src/main/java/de/szut/casino/lootboxes/LootBoxService.java diff --git a/backend/requests/lootboxes.http b/backend/requests/lootboxes.http index 126d237..9059570 100644 --- a/backend/requests/lootboxes.http +++ b/backend/requests/lootboxes.http @@ -4,6 +4,6 @@ Content-Type: application/json ### -POST http://localhost:8080/lootboxes/1 +POST http://localhost:8080/lootboxes/2 Authorization: Bearer {{token}} Content-Type: application/json \ No newline at end of file diff --git a/backend/src/main/java/de/szut/casino/CasinoApplication.java b/backend/src/main/java/de/szut/casino/CasinoApplication.java index 4b47f5c..1d7e861 100644 --- a/backend/src/main/java/de/szut/casino/CasinoApplication.java +++ b/backend/src/main/java/de/szut/casino/CasinoApplication.java @@ -41,7 +41,6 @@ public class CasinoApplication { premiumLootBox.setPrice(new BigDecimal("5")); premiumLootBox.setRewards(new ArrayList<>()); // Initialize the list - // Save the loot boxes first lootBoxRepository.saveAll(Arrays.asList(basicLootBox, premiumLootBox)); RewardEntity commonReward = new RewardEntity(); @@ -68,13 +67,11 @@ public class CasinoApplication { legendaryReward.setValue(new BigDecimal("15.00")); legendaryReward.setProbability(new BigDecimal("0.10")); - // Save all rewards rewardRepository.saveAll(Arrays.asList( commonReward, rareReward, epicReward, premiumCommon, premiumRare, legendaryReward )); - // Add relationships from the owning side (LootBox) basicLootBox.getRewards().add(commonReward); basicLootBox.getRewards().add(premiumRare); @@ -82,7 +79,6 @@ public class CasinoApplication { premiumLootBox.getRewards().add(premiumRare); premiumLootBox.getRewards().add(legendaryReward); - // Update the loot boxes to save the relationships lootBoxRepository.saveAll(Arrays.asList(basicLootBox, premiumLootBox)); System.out.println("Initial LootBoxes and rewards created successfully"); diff --git a/backend/src/main/java/de/szut/casino/lootboxes/LootBoxController.java b/backend/src/main/java/de/szut/casino/lootboxes/LootBoxController.java index 716b02a..51a17e1 100644 --- a/backend/src/main/java/de/szut/casino/lootboxes/LootBoxController.java +++ b/backend/src/main/java/de/szut/casino/lootboxes/LootBoxController.java @@ -6,7 +6,6 @@ import de.szut.casino.user.UserService; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; -import java.math.BigDecimal; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -15,13 +14,13 @@ import java.util.Optional; @RestController public class LootBoxController { private final LootBoxRepository lootBoxRepository; - private final UserRepository userRepository; private final UserService userService; + private final LootBoxService lootBoxService; - public LootBoxController(LootBoxRepository lootBoxRepository, UserRepository userRepository, UserService userService) { + public LootBoxController(LootBoxRepository lootBoxRepository, UserRepository userRepository, UserService userService, LootBoxService lootBoxService) { this.lootBoxRepository = lootBoxRepository; - this.userRepository = userRepository; this.userService = userService; + this.lootBoxService = lootBoxService; } @GetMapping("/lootboxes") @@ -37,7 +36,6 @@ public class LootBoxController { } LootBoxEntity lootBox = optionalLootBox.get(); - RewardEntity reward = determineReward(lootBox); Optional optionalUser = userService.getCurrentUser(token); if (optionalUser.isEmpty()) { @@ -46,31 +44,15 @@ public class LootBoxController { UserEntity user = optionalUser.get(); - if (user.getBalance().compareTo(lootBox.getPrice()) < 0) { + if (lootBoxService.hasSufficientBalance(user, lootBox.getPrice())) { Map errorResponse = new HashMap<>(); errorResponse.put("error", "Insufficient balance"); return ResponseEntity.badRequest().body(errorResponse); } - user.setBalance(user.getBalance().subtract(lootBox.getPrice())); - user.setBalance(user.getBalance().add(reward.getValue())); - userRepository.save(user); + RewardEntity reward = lootBoxService.determineReward(lootBox); + lootBoxService.handleBalance(user, lootBox, reward); - return ResponseEntity.ok(determineReward(lootBox)); + return ResponseEntity.ok(reward); } - - public RewardEntity determineReward(LootBoxEntity lootBox) { - double randomValue = Math.random(); - BigDecimal cumulativeProbability = BigDecimal.ZERO; - - for (RewardEntity reward : lootBox.getRewards()) { - cumulativeProbability = cumulativeProbability.add(reward.getProbability()); - if (randomValue <= cumulativeProbability.doubleValue()) { - return reward; - } - } - - return lootBox.getRewards().getLast(); - } - } diff --git a/backend/src/main/java/de/szut/casino/lootboxes/LootBoxService.java b/backend/src/main/java/de/szut/casino/lootboxes/LootBoxService.java new file mode 100644 index 0000000..d80370e --- /dev/null +++ b/backend/src/main/java/de/szut/casino/lootboxes/LootBoxService.java @@ -0,0 +1,40 @@ +package de.szut.casino.lootboxes; + +import de.szut.casino.user.UserEntity; +import de.szut.casino.user.UserRepository; +import org.springframework.stereotype.Service; + +import java.math.BigDecimal; + +@Service +public class LootBoxService { + private final UserRepository userRepository; + + public LootBoxService(UserRepository userRepository) { + this.userRepository = userRepository; + } + + public boolean hasSufficientBalance(UserEntity user, BigDecimal price) { + return user.getBalance().compareTo(price) < 0; + } + + public RewardEntity determineReward(LootBoxEntity lootBox) { + double randomValue = Math.random(); + BigDecimal cumulativeProbability = BigDecimal.ZERO; + + for (RewardEntity reward : lootBox.getRewards()) { + cumulativeProbability = cumulativeProbability.add(reward.getProbability()); + if (randomValue <= cumulativeProbability.doubleValue()) { + return reward; + } + } + + return lootBox.getRewards().getLast(); + } + + public void handleBalance(UserEntity user, LootBoxEntity lootBox, RewardEntity reward) { + user.setBalance(user.getBalance().subtract(lootBox.getPrice())); + user.setBalance(user.getBalance().add(reward.getValue())); + userRepository.save(user); + } +}