From 1878ed8fe41d5da8781cd3209eb2b0a405171f60 Mon Sep 17 00:00:00 2001
From: Phan Huy Tran
Date: Wed, 2 Apr 2025 09:15:37 +0200
Subject: [PATCH 01/21] 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 02/21] 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 03/21] 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 04/21] 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 38f4617fb05f2bc8acf19e0ec030834bac2cafa5 Mon Sep 17 00:00:00 2001
From: Renovate Bot
Date: Wed, 2 Apr 2025 09:01:53 +0000
Subject: [PATCH 05/21] chore(deps): update devdependencies (non-major)
---
frontend/bun.lock | 102 ++++++++++++++++++++++++++++++++----------
frontend/package.json | 6 +--
2 files changed, 81 insertions(+), 27 deletions(-)
diff --git a/frontend/bun.lock b/frontend/bun.lock
index f4f97b2..e2d7dda 100644
--- a/frontend/bun.lock
+++ b/frontend/bun.lock
@@ -32,7 +32,7 @@
"@angular/cli": "^18.2.2",
"@angular/compiler-cli": "^18.2.0",
"@types/jasmine": "~5.1.0",
- "angular-eslint": "19.2.1",
+ "angular-eslint": "19.3.0",
"eslint": "^9.20.0",
"jasmine-core": "~5.6.0",
"karma": "~6.4.0",
@@ -41,8 +41,8 @@
"karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "~2.1.0",
"prettier": "^3.4.2",
- "typescript": "~5.5.0",
- "typescript-eslint": "8.26.1",
+ "typescript": "~5.8.0",
+ "typescript-eslint": "8.29.0",
},
},
},
@@ -61,19 +61,19 @@
"@angular-devkit/schematics": ["@angular-devkit/schematics@18.2.14", "", { "dependencies": { "@angular-devkit/core": "18.2.14", "jsonc-parser": "3.3.1", "magic-string": "0.30.11", "ora": "5.4.1", "rxjs": "7.8.1" } }, "sha512-mukjZIHHB7gWratq8fZwUq5WZ+1bF4feG/idXr1wgQ+/FqWjs2PP7HDesHVcPymmRulpTyCpB7TNB1O1fgnCpA=="],
- "@angular-eslint/builder": ["@angular-eslint/builder@19.2.1", "", { "dependencies": { "@angular-devkit/architect": ">= 0.1900.0 < 0.2000.0", "@angular-devkit/core": ">= 19.0.0 < 20.0.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": "*" } }, "sha512-iBs/4ZpjyISBFYU+dbfJOJi4Efh7U1hXPgQwaebU9r9Y4dMdcTw7MsaG9MfJX1gQJkIeXasYTxfSfuqoMFl9nQ=="],
+ "@angular-eslint/builder": ["@angular-eslint/builder@19.3.0", "", { "dependencies": { "@angular-devkit/architect": ">= 0.1900.0 < 0.2000.0", "@angular-devkit/core": ">= 19.0.0 < 20.0.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": "*" } }, "sha512-j9xNrzZJq29ONSG6EaeQHve0Squkm6u6Dm8fZgWP7crTFOrtLXn7Wxgxuyl9eddpbWY1Ov1gjFuwBVnxIdyAqg=="],
- "@angular-eslint/bundled-angular-compiler": ["@angular-eslint/bundled-angular-compiler@19.2.1", "", {}, "sha512-8/NY4OCpiRDSOaqnpIOW7kMirqqsTY1U751iuMH0z9gQImYZWubMLOI0tsLFWmz06pKpgiDZcjD2X9TK2b4Igg=="],
+ "@angular-eslint/bundled-angular-compiler": ["@angular-eslint/bundled-angular-compiler@19.3.0", "", {}, "sha512-63Zci4pvnUR1iSkikFlNbShF1tO5HOarYd8fvNfmOZwFfZ/1T3j3bCy9YbE+aM5SYrWqPaPP/OcwZ3wJ8WNvqA=="],
- "@angular-eslint/eslint-plugin": ["@angular-eslint/eslint-plugin@19.2.1", "", { "dependencies": { "@angular-eslint/bundled-angular-compiler": "19.2.1", "@angular-eslint/utils": "19.2.1" }, "peerDependencies": { "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": "*" } }, "sha512-wCjyH5cJb4fBchEnt3L6dQ6syaLHD+xeHCSynD/Lw3K6BcVEnFa+82SfSscgXtYLRPHlkK5CmYYs3AlALhA+/w=="],
+ "@angular-eslint/eslint-plugin": ["@angular-eslint/eslint-plugin@19.3.0", "", { "dependencies": { "@angular-eslint/bundled-angular-compiler": "19.3.0", "@angular-eslint/utils": "19.3.0" }, "peerDependencies": { "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": "*" } }, "sha512-nBLslLI20KnVbqlfNW7GcnI9R6cYCvRGjOE2QYhzxM316ciAQ62tvQuXP9ZVnRBLSKDAVnMeC0eTq9O4ysrxrQ=="],
- "@angular-eslint/eslint-plugin-template": ["@angular-eslint/eslint-plugin-template@19.2.1", "", { "dependencies": { "@angular-eslint/bundled-angular-compiler": "19.2.1", "@angular-eslint/utils": "19.2.1", "aria-query": "5.3.2", "axobject-query": "4.1.0" }, "peerDependencies": { "@typescript-eslint/types": "^7.11.0 || ^8.0.0", "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": "*" } }, "sha512-yBGut4PedTkZcGbm1sthQ671CXERkC72eXTaZlMRhKNQDf3R6zEVc60q5DQZoEIzvgeIbaZdWhZgsCLwlhfGrQ=="],
+ "@angular-eslint/eslint-plugin-template": ["@angular-eslint/eslint-plugin-template@19.3.0", "", { "dependencies": { "@angular-eslint/bundled-angular-compiler": "19.3.0", "@angular-eslint/utils": "19.3.0", "aria-query": "5.3.2", "axobject-query": "4.1.0" }, "peerDependencies": { "@typescript-eslint/types": "^7.11.0 || ^8.0.0", "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": "*" } }, "sha512-WyouppTpOYut+wvv13wlqqZ8EHoDrCZxNfGKuEUYK1BPmQlTB8EIZfQH4iR1rFVS28Rw+XRIiXo1x3oC0SOfnA=="],
- "@angular-eslint/schematics": ["@angular-eslint/schematics@19.2.1", "", { "dependencies": { "@angular-devkit/core": ">= 19.0.0 < 20.0.0", "@angular-devkit/schematics": ">= 19.0.0 < 20.0.0", "@angular-eslint/eslint-plugin": "19.2.1", "@angular-eslint/eslint-plugin-template": "19.2.1", "ignore": "7.0.3", "semver": "7.7.1", "strip-json-comments": "3.1.1" } }, "sha512-rfIHIIiXfsShwNbrVoUVu2ZzHkXghuJj8L9pXkdy92DoYSof0lqGURoPb7hv4wvZXGB3yo6S17cbw3IkeYJkzA=="],
+ "@angular-eslint/schematics": ["@angular-eslint/schematics@19.3.0", "", { "dependencies": { "@angular-devkit/core": ">= 19.0.0 < 20.0.0", "@angular-devkit/schematics": ">= 19.0.0 < 20.0.0", "@angular-eslint/eslint-plugin": "19.3.0", "@angular-eslint/eslint-plugin-template": "19.3.0", "ignore": "7.0.3", "semver": "7.7.1", "strip-json-comments": "3.1.1" } }, "sha512-Wl5sFQ4t84LUb8mJ2iVfhYFhtF55IugXu7rRhPHtgIu9Ty5s1v3HGUx4LKv51m2kWhPPeFOTmjeBv1APzFlmnQ=="],
- "@angular-eslint/template-parser": ["@angular-eslint/template-parser@19.2.1", "", { "dependencies": { "@angular-eslint/bundled-angular-compiler": "19.2.1", "eslint-scope": "^8.0.2" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": "*" } }, "sha512-fU16NUh8nY02zdkHRsAlGI9ruppsE1ko1Z1PIyB3oofYt4rCKsXb8yXWbXWn7qCjNPVqv4+oLx0BwhJQZwEX8w=="],
+ "@angular-eslint/template-parser": ["@angular-eslint/template-parser@19.3.0", "", { "dependencies": { "@angular-eslint/bundled-angular-compiler": "19.3.0", "eslint-scope": "^8.0.2" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": "*" } }, "sha512-VxMNgsHXMWbbmZeBuBX5i8pzsSSEaoACVpaE+j8Muk60Am4Mxc0PytJm4n3znBSvI3B7Kq2+vStSRYPkOER4lA=="],
- "@angular-eslint/utils": ["@angular-eslint/utils@19.2.1", "", { "dependencies": { "@angular-eslint/bundled-angular-compiler": "19.2.1" }, "peerDependencies": { "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": "*" } }, "sha512-TRIOtlDMbz1PqurLXPKMzSUl2iSs02c185g4EeOzTDX93sDvvVDLRj18jZ0IVcjQv5Vs21JK2KsKV/WdGe1OxA=="],
+ "@angular-eslint/utils": ["@angular-eslint/utils@19.3.0", "", { "dependencies": { "@angular-eslint/bundled-angular-compiler": "19.3.0" }, "peerDependencies": { "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": "*" } }, "sha512-ovvbQh96FIJfepHqLCMdKFkPXr3EbcvYc9kMj9hZyIxs/9/VxwPH7x25mMs4VsL6rXVgH2FgG5kR38UZlcTNNw=="],
"@angular/animations": ["@angular/animations@18.2.13", "", { "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { "@angular/core": "18.2.13" } }, "sha512-rG5J5Ek5Hg+Tz2NjkNOaG6PupiNK/lPfophXpsR1t/nWujqnMWX2krahD/i6kgD+jNWNKCJCYSOVvCx/BHOtKA=="],
@@ -633,21 +633,21 @@
"@types/ws": ["@types/ws@8.5.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw=="],
- "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.26.1", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.26.1", "@typescript-eslint/type-utils": "8.26.1", "@typescript-eslint/utils": "8.26.1", "@typescript-eslint/visitor-keys": "8.26.1", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-2X3mwqsj9Bd3Ciz508ZUtoQQYpOhU/kWoUqIf49H8Z0+Vbh6UF/y0OEYp0Q0axOGzaBGs7QxRwq0knSQ8khQNA=="],
+ "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.29.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.10.0", "@typescript-eslint/scope-manager": "8.29.0", "@typescript-eslint/type-utils": "8.29.0", "@typescript-eslint/utils": "8.29.0", "@typescript-eslint/visitor-keys": "8.29.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-PAIpk/U7NIS6H7TEtN45SPGLQaHNgB7wSjsQV/8+KYokAb2T/gloOA/Bee2yd4/yKVhPKe5LlaUGhAZk5zmSaQ=="],
- "@typescript-eslint/parser": ["@typescript-eslint/parser@8.26.1", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.26.1", "@typescript-eslint/types": "8.26.1", "@typescript-eslint/typescript-estree": "8.26.1", "@typescript-eslint/visitor-keys": "8.26.1", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-w6HZUV4NWxqd8BdeFf81t07d7/YV9s7TCWrQQbG5uhuvGUAW+fq1usZ1Hmz9UPNLniFnD8GLSsDpjP0hm1S4lQ=="],
+ "@typescript-eslint/parser": ["@typescript-eslint/parser@8.29.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.29.0", "@typescript-eslint/types": "8.29.0", "@typescript-eslint/typescript-estree": "8.29.0", "@typescript-eslint/visitor-keys": "8.29.0", "debug": "^4.3.4" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-8C0+jlNJOwQso2GapCVWWfW/rzaq7Lbme+vGUFKE31djwNncIpgXD7Cd4weEsDdkoZDjH0lwwr3QDQFuyrMg9g=="],
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.26.1", "", { "dependencies": { "@typescript-eslint/types": "8.26.1", "@typescript-eslint/visitor-keys": "8.26.1" } }, "sha512-6EIvbE5cNER8sqBu6V7+KeMZIC1664d2Yjt+B9EWUXrsyWpxx4lEZrmvxgSKRC6gX+efDL/UY9OpPZ267io3mg=="],
- "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.26.1", "", { "dependencies": { "@typescript-eslint/typescript-estree": "8.26.1", "@typescript-eslint/utils": "8.26.1", "debug": "^4.3.4", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-Kcj/TagJLwoY/5w9JGEFV0dclQdyqw9+VMndxOJKtoFSjfZhLXhYjzsQEeyza03rwHx2vFEGvrJWJBXKleRvZg=="],
+ "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.29.0", "", { "dependencies": { "@typescript-eslint/typescript-estree": "8.29.0", "@typescript-eslint/utils": "8.29.0", "debug": "^4.3.4", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-ahaWQ42JAOx+NKEf5++WC/ua17q5l+j1GFrbbpVKzFL/tKVc0aYY8rVSYUpUvt2hUP1YBr7mwXzx+E/DfUWI9Q=="],
- "@typescript-eslint/types": ["@typescript-eslint/types@8.24.0", "", {}, "sha512-VacJCBTyje7HGAw7xp11q439A+zeGG0p0/p2zsZwpnMzjPB5WteaWqt4g2iysgGFafrqvyLWqq6ZPZAOCoefCw=="],
+ "@typescript-eslint/types": ["@typescript-eslint/types@8.26.1", "", {}, "sha512-n4THUQW27VmQMx+3P+B0Yptl7ydfceUj4ON/AQILAASwgYdZ/2dhfymRMh5egRUrvK5lSmaOm77Ry+lmXPOgBQ=="],
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.26.1", "", { "dependencies": { "@typescript-eslint/types": "8.26.1", "@typescript-eslint/visitor-keys": "8.26.1", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-yUwPpUHDgdrv1QJ7YQal3cMVBGWfnuCdKbXw1yyjArax3353rEJP1ZA+4F8nOlQ3RfS2hUN/wze3nlY+ZOhvoA=="],
"@typescript-eslint/utils": ["@typescript-eslint/utils@8.26.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@typescript-eslint/scope-manager": "8.26.1", "@typescript-eslint/types": "8.26.1", "@typescript-eslint/typescript-estree": "8.26.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-V4Urxa/XtSUroUrnI7q6yUTD3hDtfJ2jzVfeT3VK0ciizfK2q/zGC0iDh1lFMUZR8cImRrep6/q0xd/1ZGPQpg=="],
- "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.26.1", "", { "dependencies": { "@typescript-eslint/types": "8.26.1", "eslint-visitor-keys": "^4.2.0" } }, "sha512-AjOC3zfnxd6S4Eiy3jwktJPclqhFHNyd8L6Gycf9WUPoKZpgM5PjkxY1X7uSy61xVpiJDhhk7XT2NVsN3ALTWg=="],
+ "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.29.0", "", { "dependencies": { "@typescript-eslint/types": "8.29.0", "eslint-visitor-keys": "^4.2.0" } }, "sha512-Sne/pVz8ryR03NFK21VpN88dZ2FdQXOlq3VIklbrTYEt8yXtRFr9tvUhqvCeKjqYk5FSim37sHbooT6vzBTZcg=="],
"@vitejs/plugin-basic-ssl": ["@vitejs/plugin-basic-ssl@1.1.0", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" } }, "sha512-wO4Dk/rm8u7RNhOf95ZzcEmC9rYOncYgvq4z3duaJrCgjN8BxAnDVyndanfcJZ0O6XZzHz6Q0hTimxTg8Y9g/A=="],
@@ -709,7 +709,7 @@
"ajv-keywords": ["ajv-keywords@5.1.0", "", { "dependencies": { "fast-deep-equal": "^3.1.3" }, "peerDependencies": { "ajv": "^8.8.2" } }, "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw=="],
- "angular-eslint": ["angular-eslint@19.2.1", "", { "dependencies": { "@angular-devkit/core": ">= 19.0.0 < 20.0.0", "@angular-devkit/schematics": ">= 19.0.0 < 20.0.0", "@angular-eslint/builder": "19.2.1", "@angular-eslint/eslint-plugin": "19.2.1", "@angular-eslint/eslint-plugin-template": "19.2.1", "@angular-eslint/schematics": "19.2.1", "@angular-eslint/template-parser": "19.2.1", "@typescript-eslint/types": "^8.0.0", "@typescript-eslint/utils": "^8.0.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": "*", "typescript-eslint": "^8.0.0" } }, "sha512-YQMHvbxn7G+vQ97KGr1vVSAvEFKCegcm2QcehN1eZqnTFvR4eaZyZUbIc/EaF0p9W8Jds2iKrtsVTi8zzDB+LA=="],
+ "angular-eslint": ["angular-eslint@19.3.0", "", { "dependencies": { "@angular-devkit/core": ">= 19.0.0 < 20.0.0", "@angular-devkit/schematics": ">= 19.0.0 < 20.0.0", "@angular-eslint/builder": "19.3.0", "@angular-eslint/eslint-plugin": "19.3.0", "@angular-eslint/eslint-plugin-template": "19.3.0", "@angular-eslint/schematics": "19.3.0", "@angular-eslint/template-parser": "19.3.0", "@typescript-eslint/types": "^8.0.0", "@typescript-eslint/utils": "^8.0.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": "*", "typescript-eslint": "^8.0.0" } }, "sha512-19hkkH3z/2wGhKk3LfttEBkl6CtQP/tFK6/mJoO/MbIkXV0SSJWtbPbOpEaxICLlfCw0oR6W9OoQqByWkwXjkQ=="],
"ansi-colors": ["ansi-colors@4.1.3", "", {}, "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw=="],
@@ -1757,9 +1757,9 @@
"typed-assert": ["typed-assert@1.0.9", "", {}, "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg=="],
- "typescript": ["typescript@5.5.4", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q=="],
+ "typescript": ["typescript@5.8.2", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ=="],
- "typescript-eslint": ["typescript-eslint@8.26.1", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.26.1", "@typescript-eslint/parser": "8.26.1", "@typescript-eslint/utils": "8.26.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-t/oIs9mYyrwZGRpDv3g+3K6nZ5uhKEMt2oNmAPwaY4/ye0+EH4nXIPYNtkYFS6QHm+1DFg34DbglYBz5P9Xysg=="],
+ "typescript-eslint": ["typescript-eslint@8.29.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.29.0", "@typescript-eslint/parser": "8.29.0", "@typescript-eslint/utils": "8.29.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-ep9rVd9B4kQsZ7ZnWCVxUE/xDLUUUsRzE0poAeNu+4CkFErLfuvPt/qtm2EpnSyfvsR0S6QzDFSrPCFBwf64fg=="],
"ua-parser-js": ["ua-parser-js@0.7.40", "", { "bin": { "ua-parser-js": "script/cli.js" } }, "sha512-us1E3K+3jJppDBa3Tl0L3MOJiGhe1C6P0+nIvQAFYbxlMAx0h81eOwLmU57xgqToduDDPx3y5QsdjPfDu+FgOQ=="],
@@ -1953,19 +1953,29 @@
"@types/express/@types/express-serve-static-core": ["@types/express-serve-static-core@4.19.6", "", { "dependencies": { "@types/node": "*", "@types/qs": "*", "@types/range-parser": "*", "@types/send": "*" } }, "sha512-N4LZ2xG7DatVqhCZzOGb1Yi5lMbXSZcmdLDe9EzSndPV2HpWYWzRbaerl2n27irrm94EPpprqa8KpskPT085+A=="],
- "@typescript-eslint/parser/@typescript-eslint/types": ["@typescript-eslint/types@8.26.1", "", {}, "sha512-n4THUQW27VmQMx+3P+B0Yptl7ydfceUj4ON/AQILAASwgYdZ/2dhfymRMh5egRUrvK5lSmaOm77Ry+lmXPOgBQ=="],
+ "@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.29.0", "", { "dependencies": { "@typescript-eslint/types": "8.29.0", "@typescript-eslint/visitor-keys": "8.29.0" } }, "sha512-aO1PVsq7Gm+tcghabUpzEnVSFMCU4/nYIgC2GOatJcllvWfnhrgW0ZEbnTxm36QsikmCN1K/6ZgM7fok2I7xNw=="],
- "@typescript-eslint/scope-manager/@typescript-eslint/types": ["@typescript-eslint/types@8.26.1", "", {}, "sha512-n4THUQW27VmQMx+3P+B0Yptl7ydfceUj4ON/AQILAASwgYdZ/2dhfymRMh5egRUrvK5lSmaOm77Ry+lmXPOgBQ=="],
+ "@typescript-eslint/eslint-plugin/@typescript-eslint/utils": ["@typescript-eslint/utils@8.29.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@typescript-eslint/scope-manager": "8.29.0", "@typescript-eslint/types": "8.29.0", "@typescript-eslint/typescript-estree": "8.29.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-gX/A0Mz9Bskm8avSWFcK0gP7cZpbY4AIo6B0hWYFCaIsz750oaiWR4Jr2CI+PQhfW1CpcQr9OlfPS+kMFegjXA=="],
- "@typescript-eslint/typescript-estree/@typescript-eslint/types": ["@typescript-eslint/types@8.26.1", "", {}, "sha512-n4THUQW27VmQMx+3P+B0Yptl7ydfceUj4ON/AQILAASwgYdZ/2dhfymRMh5egRUrvK5lSmaOm77Ry+lmXPOgBQ=="],
+ "@typescript-eslint/parser/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.29.0", "", { "dependencies": { "@typescript-eslint/types": "8.29.0", "@typescript-eslint/visitor-keys": "8.29.0" } }, "sha512-aO1PVsq7Gm+tcghabUpzEnVSFMCU4/nYIgC2GOatJcllvWfnhrgW0ZEbnTxm36QsikmCN1K/6ZgM7fok2I7xNw=="],
+
+ "@typescript-eslint/parser/@typescript-eslint/types": ["@typescript-eslint/types@8.29.0", "", {}, "sha512-wcJL/+cOXV+RE3gjCyl/V2G877+2faqvlgtso/ZRbTCnZazh0gXhe+7gbAnfubzN2bNsBtZjDvlh7ero8uIbzg=="],
+
+ "@typescript-eslint/parser/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.29.0", "", { "dependencies": { "@typescript-eslint/types": "8.29.0", "@typescript-eslint/visitor-keys": "8.29.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-yOfen3jE9ISZR/hHpU/bmNvTtBW1NjRbkSFdZOksL1N+ybPEE7UVGMwqvS6CP022Rp00Sb0tdiIkhSCe6NI8ow=="],
+
+ "@typescript-eslint/scope-manager/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.26.1", "", { "dependencies": { "@typescript-eslint/types": "8.26.1", "eslint-visitor-keys": "^4.2.0" } }, "sha512-AjOC3zfnxd6S4Eiy3jwktJPclqhFHNyd8L6Gycf9WUPoKZpgM5PjkxY1X7uSy61xVpiJDhhk7XT2NVsN3ALTWg=="],
+
+ "@typescript-eslint/type-utils/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.29.0", "", { "dependencies": { "@typescript-eslint/types": "8.29.0", "@typescript-eslint/visitor-keys": "8.29.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-yOfen3jE9ISZR/hHpU/bmNvTtBW1NjRbkSFdZOksL1N+ybPEE7UVGMwqvS6CP022Rp00Sb0tdiIkhSCe6NI8ow=="],
+
+ "@typescript-eslint/type-utils/@typescript-eslint/utils": ["@typescript-eslint/utils@8.29.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@typescript-eslint/scope-manager": "8.29.0", "@typescript-eslint/types": "8.29.0", "@typescript-eslint/typescript-estree": "8.29.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-gX/A0Mz9Bskm8avSWFcK0gP7cZpbY4AIo6B0hWYFCaIsz750oaiWR4Jr2CI+PQhfW1CpcQr9OlfPS+kMFegjXA=="],
+
+ "@typescript-eslint/typescript-estree/@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.26.1", "", { "dependencies": { "@typescript-eslint/types": "8.26.1", "eslint-visitor-keys": "^4.2.0" } }, "sha512-AjOC3zfnxd6S4Eiy3jwktJPclqhFHNyd8L6Gycf9WUPoKZpgM5PjkxY1X7uSy61xVpiJDhhk7XT2NVsN3ALTWg=="],
"@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"@typescript-eslint/typescript-estree/semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="],
- "@typescript-eslint/utils/@typescript-eslint/types": ["@typescript-eslint/types@8.26.1", "", {}, "sha512-n4THUQW27VmQMx+3P+B0Yptl7ydfceUj4ON/AQILAASwgYdZ/2dhfymRMh5egRUrvK5lSmaOm77Ry+lmXPOgBQ=="],
-
- "@typescript-eslint/visitor-keys/@typescript-eslint/types": ["@typescript-eslint/types@8.26.1", "", {}, "sha512-n4THUQW27VmQMx+3P+B0Yptl7ydfceUj4ON/AQILAASwgYdZ/2dhfymRMh5egRUrvK5lSmaOm77Ry+lmXPOgBQ=="],
+ "@typescript-eslint/visitor-keys/@typescript-eslint/types": ["@typescript-eslint/types@8.29.0", "", {}, "sha512-wcJL/+cOXV+RE3gjCyl/V2G877+2faqvlgtso/ZRbTCnZazh0gXhe+7gbAnfubzN2bNsBtZjDvlh7ero8uIbzg=="],
"accepts/negotiator": ["negotiator@0.6.3", "", {}, "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg=="],
@@ -2155,6 +2165,8 @@
"tar/mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="],
+ "typescript-eslint/@typescript-eslint/utils": ["@typescript-eslint/utils@8.29.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", "@typescript-eslint/scope-manager": "8.29.0", "@typescript-eslint/types": "8.29.0", "@typescript-eslint/typescript-estree": "8.29.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <5.9.0" } }, "sha512-gX/A0Mz9Bskm8avSWFcK0gP7cZpbY4AIo6B0hWYFCaIsz750oaiWR4Jr2CI+PQhfW1CpcQr9OlfPS+kMFegjXA=="],
+
"vite/esbuild": ["esbuild@0.21.5", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.21.5", "@esbuild/android-arm": "0.21.5", "@esbuild/android-arm64": "0.21.5", "@esbuild/android-x64": "0.21.5", "@esbuild/darwin-arm64": "0.21.5", "@esbuild/darwin-x64": "0.21.5", "@esbuild/freebsd-arm64": "0.21.5", "@esbuild/freebsd-x64": "0.21.5", "@esbuild/linux-arm": "0.21.5", "@esbuild/linux-arm64": "0.21.5", "@esbuild/linux-ia32": "0.21.5", "@esbuild/linux-loong64": "0.21.5", "@esbuild/linux-mips64el": "0.21.5", "@esbuild/linux-ppc64": "0.21.5", "@esbuild/linux-riscv64": "0.21.5", "@esbuild/linux-s390x": "0.21.5", "@esbuild/linux-x64": "0.21.5", "@esbuild/netbsd-x64": "0.21.5", "@esbuild/openbsd-x64": "0.21.5", "@esbuild/sunos-x64": "0.21.5", "@esbuild/win32-arm64": "0.21.5", "@esbuild/win32-ia32": "0.21.5", "@esbuild/win32-x64": "0.21.5" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw=="],
"webpack/eslint-scope": ["eslint-scope@5.1.1", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^4.1.1" } }, "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw=="],
@@ -2205,6 +2217,26 @@
"@tufjs/models/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
+ "@typescript-eslint/eslint-plugin/@typescript-eslint/scope-manager/@typescript-eslint/types": ["@typescript-eslint/types@8.29.0", "", {}, "sha512-wcJL/+cOXV+RE3gjCyl/V2G877+2faqvlgtso/ZRbTCnZazh0gXhe+7gbAnfubzN2bNsBtZjDvlh7ero8uIbzg=="],
+
+ "@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/types": ["@typescript-eslint/types@8.29.0", "", {}, "sha512-wcJL/+cOXV+RE3gjCyl/V2G877+2faqvlgtso/ZRbTCnZazh0gXhe+7gbAnfubzN2bNsBtZjDvlh7ero8uIbzg=="],
+
+ "@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.29.0", "", { "dependencies": { "@typescript-eslint/types": "8.29.0", "@typescript-eslint/visitor-keys": "8.29.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-yOfen3jE9ISZR/hHpU/bmNvTtBW1NjRbkSFdZOksL1N+ybPEE7UVGMwqvS6CP022Rp00Sb0tdiIkhSCe6NI8ow=="],
+
+ "@typescript-eslint/parser/@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
+
+ "@typescript-eslint/parser/@typescript-eslint/typescript-estree/semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="],
+
+ "@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/@typescript-eslint/types": ["@typescript-eslint/types@8.29.0", "", {}, "sha512-wcJL/+cOXV+RE3gjCyl/V2G877+2faqvlgtso/ZRbTCnZazh0gXhe+7gbAnfubzN2bNsBtZjDvlh7ero8uIbzg=="],
+
+ "@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
+
+ "@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="],
+
+ "@typescript-eslint/type-utils/@typescript-eslint/utils/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.29.0", "", { "dependencies": { "@typescript-eslint/types": "8.29.0", "@typescript-eslint/visitor-keys": "8.29.0" } }, "sha512-aO1PVsq7Gm+tcghabUpzEnVSFMCU4/nYIgC2GOatJcllvWfnhrgW0ZEbnTxm36QsikmCN1K/6ZgM7fok2I7xNw=="],
+
+ "@typescript-eslint/type-utils/@typescript-eslint/utils/@typescript-eslint/types": ["@typescript-eslint/types@8.29.0", "", {}, "sha512-wcJL/+cOXV+RE3gjCyl/V2G877+2faqvlgtso/ZRbTCnZazh0gXhe+7gbAnfubzN2bNsBtZjDvlh7ero8uIbzg=="],
+
"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
"ajv-formats/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
@@ -2295,6 +2327,12 @@
"tar/fs-minipass/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
+ "typescript-eslint/@typescript-eslint/utils/@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.29.0", "", { "dependencies": { "@typescript-eslint/types": "8.29.0", "@typescript-eslint/visitor-keys": "8.29.0" } }, "sha512-aO1PVsq7Gm+tcghabUpzEnVSFMCU4/nYIgC2GOatJcllvWfnhrgW0ZEbnTxm36QsikmCN1K/6ZgM7fok2I7xNw=="],
+
+ "typescript-eslint/@typescript-eslint/utils/@typescript-eslint/types": ["@typescript-eslint/types@8.29.0", "", {}, "sha512-wcJL/+cOXV+RE3gjCyl/V2G877+2faqvlgtso/ZRbTCnZazh0gXhe+7gbAnfubzN2bNsBtZjDvlh7ero8uIbzg=="],
+
+ "typescript-eslint/@typescript-eslint/utils/@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.29.0", "", { "dependencies": { "@typescript-eslint/types": "8.29.0", "@typescript-eslint/visitor-keys": "8.29.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.0.1" }, "peerDependencies": { "typescript": ">=4.8.4 <5.9.0" } }, "sha512-yOfen3jE9ISZR/hHpU/bmNvTtBW1NjRbkSFdZOksL1N+ybPEE7UVGMwqvS6CP022Rp00Sb0tdiIkhSCe6NI8ow=="],
+
"vite/esbuild/@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.21.5", "", { "os": "aix", "cpu": "ppc64" }, "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ=="],
"vite/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.21.5", "", { "os": "android", "cpu": "arm" }, "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg=="],
@@ -2361,6 +2399,14 @@
"@npmcli/package-json/glob/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
+ "@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
+
+ "@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/typescript-estree/semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="],
+
+ "@typescript-eslint/parser/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
+
+ "@typescript-eslint/type-utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
+
"angular-eslint/@angular-devkit/core/ajv/json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
"cacache/glob/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
@@ -2385,14 +2431,22 @@
"sass/chokidar/readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
+ "typescript-eslint/@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
+
+ "typescript-eslint/@typescript-eslint/utils/@typescript-eslint/typescript-estree/semver": ["semver@7.7.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA=="],
+
"webpack-dev-server/chokidar/readdirp/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"webpack-dev-server/rimraf/glob/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
+ "@typescript-eslint/eslint-plugin/@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
+
"karma-coverage/istanbul-lib-instrument/@babel/core/@babel/generator/jsesc": ["jsesc@3.1.0", "", { "bin": { "jsesc": "bin/jsesc" } }, "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA=="],
"pkg-dir/find-up/locate-path/p-locate/p-limit": ["p-limit@4.0.0", "", { "dependencies": { "yocto-queue": "^1.0.0" } }, "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ=="],
+ "typescript-eslint/@typescript-eslint/utils/@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
+
"webpack-dev-server/rimraf/glob/minimatch/brace-expansion": ["brace-expansion@2.0.1", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA=="],
"pkg-dir/find-up/locate-path/p-locate/p-limit/yocto-queue": ["yocto-queue@1.1.1", "", {}, "sha512-b4JR1PFR10y1mKjhHY9LaGo6tmrgjit7hxVIeAmyMw3jegXR4dhYqLaQF5zMXZxY7tLpMyJeLjr1C4rLmkVe8g=="],
diff --git a/frontend/package.json b/frontend/package.json
index d83ed30..17eef9b 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -41,7 +41,7 @@
"@angular/cli": "^18.2.2",
"@angular/compiler-cli": "^18.2.0",
"@types/jasmine": "~5.1.0",
- "angular-eslint": "19.2.1",
+ "angular-eslint": "19.3.0",
"eslint": "^9.20.0",
"jasmine-core": "~5.6.0",
"karma": "~6.4.0",
@@ -50,7 +50,7 @@
"karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "~2.1.0",
"prettier": "^3.4.2",
- "typescript": "~5.5.0",
- "typescript-eslint": "8.26.1"
+ "typescript": "~5.8.0",
+ "typescript-eslint": "8.29.0"
}
}
From b963595ab4ab0170b5f4e0233d5c3ce9183d19b1 Mon Sep 17 00:00:00 2001
From: Phan Huy Tran
Date: Wed, 2 Apr 2025 11:04:20 +0200
Subject: [PATCH 06/21] 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