diff --git a/pom.xml b/pom.xml index c1aff9a7bfec687b28f889fd930a75df8f9a215b..9fc25b111bd50b12eaf76e10e9fcfd26253df060 100644 --- a/pom.xml +++ b/pom.xml @@ -182,6 +182,12 @@ </excludes> </configuration> </plugin> + <!-- spring-javaformat-maven-plugin --> + <plugin> + <groupId>io.spring.javaformat</groupId> + <artifactId>spring-javaformat-maven-plugin</artifactId> + <version>0.0.41</version> + </plugin> <!-- Plugin that generates a site for the current project --> <plugin> <groupId>org.apache.maven.plugins</groupId> diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/SparestiApplication.java b/src/main/java/no/ntnu/idi/stud/savingsapp/SparestiApplication.java index b080fcf4d66fe7f78b6646468e15850cc5bb526c..cb33fb5e9a9c494e901e2a9c76c75dc8ee4fc193 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/SparestiApplication.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/SparestiApplication.java @@ -4,8 +4,8 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** - * The main class for the Sparesti application. - * This class bootstraps the Spring application and configures it for execution. + * The main class for the Sparesti application. This class bootstraps the Spring + * application and configures it for execution. */ @SpringBootApplication public class SparestiApplication { @@ -20,7 +20,7 @@ public class SparestiApplication { /** * Returns the URL for the frontend application. - * @return the URL for the frontend application + * @return the URL for the frontend application */ public static String getFrontendURL() { return System.getProperty("FRONTEND_URL", "http://localhost"); @@ -28,9 +28,10 @@ public class SparestiApplication { /** * Returns the URL for the backend application. - * @return the URL for the backend application + * @return the URL for the backend application */ public static String getBackendURL() { return System.getProperty("API_URL", "http://localhost:8080"); } + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/controller/AccountController.java b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/controller/AccountController.java index f5c0c919edb9c405cf39c791264d7edab4c9d0d1..089b34496fbe9eef74613f24ec894243f7274e47 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/controller/AccountController.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/controller/AccountController.java @@ -30,70 +30,61 @@ import org.springframework.web.bind.annotation.RestController; @Slf4j public class AccountController { - @Autowired - private AccountService accountService; + @Autowired + private AccountService accountService; - @Autowired - private ModelMapper modelMapper; + @Autowired + private ModelMapper modelMapper; - @Operation(summary = "Get user accounts", description = "Get accounts associated with a user by" - + " providing their bank profile id") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully got accounts"), - @ApiResponse(responseCode = "200", description = "No accounts associated with a bank user"), - @ApiResponse(responseCode = "404", description = "Bank profile id does not exist") - }) - @GetMapping("/accounts/profile/{bankProfileId}") - public ResponseEntity<List<Account>> getAccounts(@PathVariable Long bankProfileId) { - List<Account> accounts = accountService.getAccountsByBankProfileId(bankProfileId); - log.info("[AccountController:getAccounts] bankProfileId: {}", bankProfileId); - for (Account account : accounts) { - log.info("[AccountController:getAccounts] accountBban: {}", account.getBban()); - } - return ResponseEntity.ok(accounts); - } + @Operation(summary = "Get user accounts", + description = "Get accounts associated with a user by" + " providing their bank profile id") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully got accounts"), + @ApiResponse(responseCode = "200", description = "No accounts associated with a bank user"), + @ApiResponse(responseCode = "404", description = "Bank profile id does not exist") }) + @GetMapping("/accounts/profile/{bankProfileId}") + public ResponseEntity<List<Account>> getAccounts(@PathVariable Long bankProfileId) { + List<Account> accounts = accountService.getAccountsByBankProfileId(bankProfileId); + log.info("[AccountController:getAccounts] bankProfileId: {}", bankProfileId); + for (Account account : accounts) { + log.info("[AccountController:getAccounts] accountBban: {}", account.getBban()); + } + return ResponseEntity.ok(accounts); + } - @Operation(summary = "Get user accounts", description = "Get accounts associated with a user by" - + " providing their social security number") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully got accounts"), - @ApiResponse(responseCode = "200", description = "No accounts associated with a bank user"), - @ApiResponse(responseCode = "404", description = "Social security number does not exist") - }) - @GetMapping("/accounts/ssn/{ssn}") - public ResponseEntity<List<Account>> getAccountsBySsn(@PathVariable Long ssn) { - List<Account> accounts = accountService.getAccountsBySsn(ssn); - log.info("[AccountController:getAccountsBySsn] ssn: {}", ssn); - for (Account account : accounts) { - log.info("[AccountController:getAccountsBySsn] accountBban: {}", account.getBban()); - } - return ResponseEntity.ok(accounts); - } + @Operation(summary = "Get user accounts", + description = "Get accounts associated with a user by" + " providing their social security number") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully got accounts"), + @ApiResponse(responseCode = "200", description = "No accounts associated with a bank user"), + @ApiResponse(responseCode = "404", description = "Social security number does not exist") }) + @GetMapping("/accounts/ssn/{ssn}") + public ResponseEntity<List<Account>> getAccountsBySsn(@PathVariable Long ssn) { + List<Account> accounts = accountService.getAccountsBySsn(ssn); + log.info("[AccountController:getAccountsBySsn] ssn: {}", ssn); + for (Account account : accounts) { + log.info("[AccountController:getAccountsBySsn] accountBban: {}", account.getBban()); + } + return ResponseEntity.ok(accounts); + } - @Operation(summary = "Create account", description = "Create account with random balance") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully created account"), - @ApiResponse(responseCode = "404", description = "Provided bban could not be " - + "found") - }) - @GetMapping("/balance/{bban}") - public ResponseEntity<BalanceDTO> getAccountsByBBAN(@PathVariable Long bban) { - log.info("[AccountController:getAccountsByBBAN] bban: {}", bban); - Account account = accountService.getAccountByBban(bban); - BalanceDTO balanceDTO = modelMapper.map(account, BalanceDTO.class); - return ResponseEntity.ok(balanceDTO); - } + @Operation(summary = "Create account", description = "Create account with random balance") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully created account"), + @ApiResponse(responseCode = "404", description = "Provided bban could not be " + "found") }) + @GetMapping("/balance/{bban}") + public ResponseEntity<BalanceDTO> getAccountsByBBAN(@PathVariable Long bban) { + log.info("[AccountController:getAccountsByBBAN] bban: {}", bban); + Account account = accountService.getAccountByBban(bban); + BalanceDTO balanceDTO = modelMapper.map(account, BalanceDTO.class); + return ResponseEntity.ok(balanceDTO); + } + + @Operation(summary = "Create account", description = "Create account with random balance") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully created account"), + @ApiResponse(responseCode = "404", description = "Provided bank profile id could not be " + "found") }) + @PostMapping("/create-account") + public ResponseEntity<AccountResponseDTO> createAccount(@RequestBody AccountRequestDTO accountRequestDTO) { + AccountResponseDTO accountResponseDTO = accountService.saveAccount(accountRequestDTO); + log.info("[AccountController:createAccount] accountBankProfileId: {}", accountResponseDTO.getBankProfileId()); + return ResponseEntity.ok(accountResponseDTO); + } - @Operation(summary = "Create account", description = "Create account with random balance") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully created account"), - @ApiResponse(responseCode = "404", description = "Provided bank profile id could not be " - + "found") - }) - @PostMapping("/create-account") - public ResponseEntity<AccountResponseDTO> createAccount(@RequestBody AccountRequestDTO accountRequestDTO) { - AccountResponseDTO accountResponseDTO = accountService.saveAccount(accountRequestDTO); - log.info("[AccountController:createAccount] accountBankProfileId: {}", accountResponseDTO.getBankProfileId()); - return ResponseEntity.ok(accountResponseDTO); - } } \ No newline at end of file diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/controller/BankProfileController.java b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/controller/BankProfileController.java index 2905a6b43cb933eae51099bdda7f75a0a28817a8..7e0f9e9901cbf0a806623daa4f8d349e116e012e 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/controller/BankProfileController.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/controller/BankProfileController.java @@ -23,19 +23,17 @@ import org.springframework.web.bind.annotation.RestController; @Slf4j public class BankProfileController { - @Autowired - private BankProfileService bankProfileService; + @Autowired + private BankProfileService bankProfileService; - @Operation(summary = "Create bank profile", description = "Create a bank profile by providing a" - + " social security number") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully created a bank profile"), - @ApiResponse(responseCode = "400", description = "Could not create profile") - }) - @PostMapping("/create-profile") - public BankProfileResponseDTO createBankProfile(@RequestBody BankProfileDTO bankProfileDTO) { - log.info("[BankProfileController:createBankProfile] bank-profileSsn: {}", bankProfileDTO.getSsn()); - return bankProfileService.saveBankProfile(bankProfileDTO); - } + @Operation(summary = "Create bank profile", + description = "Create a bank profile by providing a" + " social security number") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully created a bank profile"), + @ApiResponse(responseCode = "400", description = "Could not create profile") }) + @PostMapping("/create-profile") + public BankProfileResponseDTO createBankProfile(@RequestBody BankProfileDTO bankProfileDTO) { + log.info("[BankProfileController:createBankProfile] bank-profileSsn: {}", bankProfileDTO.getSsn()); + return bankProfileService.saveBankProfile(bankProfileDTO); + } } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/controller/TransactionController.java b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/controller/TransactionController.java index 9abda39988fb35a827f2aacab0f8b110b87b2073..f3700bf5984fd535aa4d7d19acc48f798a36a47b 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/controller/TransactionController.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/controller/TransactionController.java @@ -23,20 +23,21 @@ import org.springframework.web.bind.annotation.RestController; @Slf4j public class TransactionController { - @Autowired - private TransactionService transactionService; + @Autowired + private TransactionService transactionService; + + @Operation(summary = "Transfer to account", + description = "Transfer money from a users account " + "to another account of the same user") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully got accounts"), + @ApiResponse(responseCode = "200", description = "No accounts associated with a bank user"), + @ApiResponse(responseCode = "404", description = "Bank profile id does not exist") }) + @PostMapping("/norwegian-domestic-payment-to-self") + public ResponseEntity<TransactionDTO> transferToSelf(@RequestBody TransactionDTO transactionRequest) { + transactionService.saveTransaction(transactionRequest); + log.info("[TransactionController:transferToSelf] transaction amount {} from: {} -> {}", + transactionRequest.getAmount(), transactionRequest.getCreditorBBAN(), + transactionRequest.getDebtorBBAN()); + return ResponseEntity.ok(transactionRequest); + } - @Operation(summary = "Transfer to account", description = "Transfer money from a users account " - + "to another account of the same user") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully got accounts"), - @ApiResponse(responseCode = "200", description = "No accounts associated with a bank user"), - @ApiResponse(responseCode = "404", description = "Bank profile id does not exist") - }) - @PostMapping("/norwegian-domestic-payment-to-self") - public ResponseEntity<TransactionDTO> transferToSelf(@RequestBody TransactionDTO transactionRequest) { - transactionService.saveTransaction(transactionRequest); - log.info("[TransactionController:transferToSelf] transaction amount {} from: {} -> {}", transactionRequest.getAmount(), transactionRequest.getCreditorBBAN(), transactionRequest.getDebtorBBAN()); - return ResponseEntity.ok(transactionRequest); - } } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/dto/AccountRequestDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/dto/AccountRequestDTO.java index b3988ccf2048928121a19f5afd7f111f77c0d958..9c0bf0b2c54cd6f170ba0c25a53dc151a8c50794 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/dto/AccountRequestDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/dto/AccountRequestDTO.java @@ -8,6 +8,6 @@ import lombok.Data; @Data public class AccountRequestDTO { - private Long ssn; + private Long ssn; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/dto/AccountResponseDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/dto/AccountResponseDTO.java index 14fda6a74d3f85fc6562f14189d0f6f23352e7ea..7ef21f72aafc383cbc04965bcc070e107708d475 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/dto/AccountResponseDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/dto/AccountResponseDTO.java @@ -9,7 +9,8 @@ import lombok.Data; @Data public class AccountResponseDTO { - private Long bankProfileId; - private BigDecimal balance; + private Long bankProfileId; + + private BigDecimal balance; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/dto/BalanceDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/dto/BalanceDTO.java index 76f30ebd3a9ae7b584809e3ccf9c4f49f2fa446a..24a253ec48e631dfb918fce65e9e0cb76223672e 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/dto/BalanceDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/dto/BalanceDTO.java @@ -6,6 +6,8 @@ import lombok.Data; @Data public final class BalanceDTO { - private Long bban; - private BigDecimal balance; + private Long bban; + + private BigDecimal balance; + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/dto/BankProfileDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/dto/BankProfileDTO.java index 3f74a5affaaa5f717de9a88259106b5b347d334a..f1e5e0580605e1f78ef0a31cf699316a37f45c48 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/dto/BankProfileDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/dto/BankProfileDTO.java @@ -8,6 +8,6 @@ import lombok.Data; @Data public class BankProfileDTO { - private Long ssn; + private Long ssn; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/dto/BankProfileResponseDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/dto/BankProfileResponseDTO.java index ecc7f67d9341cf1817d6460d5dcf90cd7584daf7..3f6a0125b9784f508d124b781a8ab753dad2a267 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/dto/BankProfileResponseDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/dto/BankProfileResponseDTO.java @@ -10,7 +10,8 @@ import no.ntnu.idi.stud.savingsapp.bank.model.Account; @Data public class BankProfileResponseDTO { - private Long ssn; - List<Account> accounts; + private Long ssn; + + List<Account> accounts; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/dto/TransactionDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/dto/TransactionDTO.java index 0bf8b153e8b8f0780fcb32e0bf4ce133e20fc7e3..14e1dbe724c31fda7fde63d5974dca68d08e552d 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/dto/TransactionDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/dto/TransactionDTO.java @@ -9,7 +9,10 @@ import lombok.Data; @Data public class TransactionDTO { - private Long debtorBBAN; - private Long creditorBBAN; - private BigDecimal amount; + private Long debtorBBAN; + + private Long creditorBBAN; + + private BigDecimal amount; + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/model/Account.java b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/model/Account.java index 40bef06043707ded3948383760e24977b8b67ef9..7bc4aba38440a780f6a220e05c651f36ebfbcc6c 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/model/Account.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/model/Account.java @@ -23,24 +23,25 @@ import no.ntnu.idi.stud.savingsapp.bank.model.generated.RandomValue; @Table(name = "account") public class Account { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "bban") - private Long bban; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "bban") + private Long bban; - @Column(name = "balance") - private BigDecimal balance; + @Column(name = "balance") + private BigDecimal balance; - @ManyToOne - @JsonBackReference - @JoinColumn(name = "bank_profile_id") - private BankProfile bankProfile; + @ManyToOne + @JsonBackReference + @JoinColumn(name = "bank_profile_id") + private BankProfile bankProfile; + + /** + * Constructor for account. Generate a random balance for the account when an instance + * is created. + */ + public Account() { + this.balance = RandomValue.generateAccountBalance(); + } - /** - * Constructor for account. - * Generate a random balance for the account when an instance is created. - */ - public Account() { - this.balance = RandomValue.generateAccountBalance(); - } } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/model/BankProfile.java b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/model/BankProfile.java index 9f084a672ad9aa5f6695dc7d4de44aae0157d315..4faf3af2b80911196479746b385dcf32acfb28e6 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/model/BankProfile.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/model/BankProfile.java @@ -15,8 +15,8 @@ import lombok.Data; import lombok.NoArgsConstructor; /** - * Entity that represents a bank profile in the system. - * This profile consists of both an id and a social security number. + * Entity that represents a bank profile in the system. This profile consists of both an + * id and a social security number. */ @Data @AllArgsConstructor @@ -25,16 +25,17 @@ import lombok.NoArgsConstructor; @Table(name = "bank_profile") public class BankProfile { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "bank_profile_id") - private Long id; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "bank_profile_id") + private Long id; - @Column(name = "ssn") - private Long ssn; + @Column(name = "ssn") + private Long ssn; + + @OneToMany() + @JsonManagedReference + @JoinColumn(name = "bank_profile_id") + private List<Account> accounts; - @OneToMany() - @JsonManagedReference - @JoinColumn(name = "bank_profile_id") - private List<Account> accounts; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/model/Transaction.java b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/model/Transaction.java index e7fdf07b6e01414e0b6445a2c7a611bb09ca65bc..c858786429a655669378475a0414f4c05dc97918 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/model/Transaction.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/model/Transaction.java @@ -26,27 +26,27 @@ import lombok.NoArgsConstructor; @Table(name = "transaction") public class Transaction { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "transaction_id") - private Long id; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "transaction_id") + private Long id; - @Column(name = "amount") - private BigDecimal amount; + @Column(name = "amount") + private BigDecimal amount; - @ManyToOne() - @JoinColumn(name = "debtor_account_bban") - private Account debtorAccount; + @ManyToOne() + @JoinColumn(name = "debtor_account_bban") + private Account debtorAccount; - @ManyToOne() - @JoinColumn(name = "creditor_account_bban") - private Account creditorAccount; + @ManyToOne() + @JoinColumn(name = "creditor_account_bban") + private Account creditorAccount; - @Column(name = "created_at") - private Timestamp createdAt; + @Column(name = "created_at") + private Timestamp createdAt; - @Enumerated(EnumType.STRING) - @Column(name = "transaction_type") - private TransactionType transactionType; + @Enumerated(EnumType.STRING) + @Column(name = "transaction_type") + private TransactionType transactionType; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/model/TransactionType.java b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/model/TransactionType.java index f5a0e8f0b0928efe1560f69562759ec3d5a8dcb2..b5d4d6a53b8af3b1eb6ab0ac8988b7f6f63c7a66 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/model/TransactionType.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/model/TransactionType.java @@ -1,20 +1,9 @@ package no.ntnu.idi.stud.savingsapp.bank.model; public enum TransactionType { - NO_COFFEE, - NO_CAR, - SHORTER_SHOWER, - SPEND_LESS_ON_FOOD, - BUY_USED_CLOTHES, - LESS_SHOPPING, - DROP_SUBSCRIPTION, - SELL_SOMETHING, - BUY_USED, - EAT_PACKED_LUCH, - STOP_SHOPPING, - ZERO_SPENDING, - RENT_YOUR_STUFF, - MEATLESS_MONTH, - SCREEN_TIME_LIMIT, - UNPLUGGED_ENTERTAINMENT, + + NO_COFFEE, NO_CAR, SHORTER_SHOWER, SPEND_LESS_ON_FOOD, BUY_USED_CLOTHES, LESS_SHOPPING, DROP_SUBSCRIPTION, + SELL_SOMETHING, BUY_USED, EAT_PACKED_LUCH, STOP_SHOPPING, ZERO_SPENDING, RENT_YOUR_STUFF, MEATLESS_MONTH, + SCREEN_TIME_LIMIT, UNPLUGGED_ENTERTAINMENT, + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/model/generated/RandomValue.java b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/model/generated/RandomValue.java index 5601de7b42da2862a76247ad3b2d4f302b022598..a7e93d62aa8b21aedef93d4cb7d3c604efa193b0 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/model/generated/RandomValue.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/model/generated/RandomValue.java @@ -5,22 +5,21 @@ import java.math.RoundingMode; import java.util.Random; /** - * Class for generating random values. - * This class is used in the bank application to generate random values for test data. + * Class for generating random values. This class is used in the bank application to + * generate random values for test data. */ public class RandomValue { - /** - * Generates a random {@link BigDecimal} number between 100 and 100_000. - * - * @return A random number. - */ - public static BigDecimal generateAccountBalance() { - Random random = new Random(); - double minBalance = 100.0; - double maxBalance = 100_000.0; - double randomBalance = minBalance + (maxBalance - minBalance) * random.nextDouble(); - return BigDecimal.valueOf(randomBalance).setScale(2, RoundingMode.HALF_UP); - } + /** + * Generates a random {@link BigDecimal} number between 100 and 100_000. + * @return A random number. + */ + public static BigDecimal generateAccountBalance() { + Random random = new Random(); + double minBalance = 100.0; + double maxBalance = 100_000.0; + double randomBalance = minBalance + (maxBalance - minBalance) * random.nextDouble(); + return BigDecimal.valueOf(randomBalance).setScale(2, RoundingMode.HALF_UP); + } } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/repository/AccountRepository.java b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/repository/AccountRepository.java index 5890ede0aafec64954aee56540a675a377f3041b..c0f3c8baea116ae0c57646fe3b808df5afe06b8f 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/repository/AccountRepository.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/repository/AccountRepository.java @@ -17,40 +17,38 @@ import org.springframework.transaction.annotation.Transactional; @Repository public interface AccountRepository extends JpaRepository<Account, Long> { - /** - * Get all accounts that belong to a user with a specified id. - * - * @param bankProfileId The id of the bank profile that belongs to the desired accounts. - * @return A list of accounts. - */ - @Query("SELECT a FROM Account a WHERE a.bankProfile.id = :bankProfileId") - List<Account> findAllByBankProfileId(@Param("bankProfileId") Long bankProfileId); + /** + * Get all accounts that belong to a user with a specified id. + * @param bankProfileId The id of the bank profile that belongs to the desired + * accounts. + * @return A list of accounts. + */ + @Query("SELECT a FROM Account a WHERE a.bankProfile.id = :bankProfileId") + List<Account> findAllByBankProfileId(@Param("bankProfileId") Long bankProfileId); - /** - * Get all accounts that belong to a user with a specified social security number. - * - * @param ssn The Social Security Number of the user. - * @return A list of accounts. - */ - List<Account> findAllByBankProfileSsn(Long ssn); + /** + * Get all accounts that belong to a user with a specified social security number. + * @param ssn The Social Security Number of the user. + * @return A list of accounts. + */ + List<Account> findAllByBankProfileSsn(Long ssn); - /** - * Update the balance of an account. - * - * @param amount The new balance of the account. - * @param bban The Basic Bank Account Number, specifying which account is updated. - * @return The number of affected rows. - */ - @Modifying - @Transactional - @Query(value = "UPDATE account a SET a.balance = :amount WHERE a.bban = :bban", nativeQuery = true) - int updateBalance(@Param("amount") BigDecimal amount,@Param("bban") Long bban); + /** + * Update the balance of an account. + * @param amount The new balance of the account. + * @param bban The Basic Bank Account Number, specifying which account is updated. + * @return The number of affected rows. + */ + @Modifying + @Transactional + @Query(value = "UPDATE account a SET a.balance = :amount WHERE a.bban = :bban", nativeQuery = true) + int updateBalance(@Param("amount") BigDecimal amount, @Param("bban") Long bban); + + /** + * Get an account given the Basic Bank Account Number + * @param bban The Basic Bank Account Number belonging to the account. + * @return The account if it exists, if not: return empty. + */ + Optional<Account> findAccountByBban(Long bban); - /** - * Get an account given the Basic Bank Account Number - * - * @param bban The Basic Bank Account Number belonging to the account. - * @return The account if it exists, if not: return empty. - */ - Optional<Account> findAccountByBban(Long bban); } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/repository/BankProfileRepository.java b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/repository/BankProfileRepository.java index e60871105896034369a99c72766b643befefb116..95d8043541e2c9bfc39038d1c8a3ed8753ab3512 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/repository/BankProfileRepository.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/repository/BankProfileRepository.java @@ -11,12 +11,11 @@ import org.springframework.stereotype.Repository; @Repository public interface BankProfileRepository extends JpaRepository<BankProfile, Long> { - /** - * Get the bank profile associated with a Social Security Number. - * - * @param ssn The Social Security Number of the user. - * @return The user if it exists, if not: returns empty. - */ - Optional<BankProfile> findBySsn(Long ssn); + /** + * Get the bank profile associated with a Social Security Number. + * @param ssn The Social Security Number of the user. + * @return The user if it exists, if not: returns empty. + */ + Optional<BankProfile> findBySsn(Long ssn); } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/service/AccountService.java b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/service/AccountService.java index 71e266abf675d08ea31cda48d542fb62e4bc2560..8c8c71ac39e60ffcd99b028d99ffe9a456362288 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/service/AccountService.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/service/AccountService.java @@ -12,37 +12,34 @@ import org.springframework.stereotype.Service; @Service public interface AccountService { - /** - * Get a list of accounts of a bank profile by providing the associated id of the bank profile. - * - * @param id The id of the bank profile. - * @return A list of accounts. - */ - List<Account> getAccountsByBankProfileId(Long id); + /** + * Get a list of accounts of a bank profile by providing the associated id of the bank + * profile. + * @param id The id of the bank profile. + * @return A list of accounts. + */ + List<Account> getAccountsByBankProfileId(Long id); - /** - * Get a list of accounts of a bank profile by providing the associated Social Security Number - * of the bank profile. - * - * @param ssn The Social Security Number of the bank profile. - * @return A list of accounts. - */ - List<Account> getAccountsBySsn(Long ssn); + /** + * Get a list of accounts of a bank profile by providing the associated Social + * Security Number of the bank profile. + * @param ssn The Social Security Number of the bank profile. + * @return A list of accounts. + */ + List<Account> getAccountsBySsn(Long ssn); - /** - * Saves an account to the database. - * - * @param accountRequestDto The DTO containing the bank profile id. - * @return The saved account. - */ - AccountResponseDTO saveAccount(AccountRequestDTO accountRequestDto); + /** + * Saves an account to the database. + * @param accountRequestDto The DTO containing the bank profile id. + * @return The saved account. + */ + AccountResponseDTO saveAccount(AccountRequestDTO accountRequestDto); - /** - * Get an account given the Basic Bank Account Number - * - * @param bban The Basic Bank Account Number belonging to the account. - * @return The account if it exists, if not: return empty. - */ - Account getAccountByBban(Long bban); + /** + * Get an account given the Basic Bank Account Number + * @param bban The Basic Bank Account Number belonging to the account. + * @return The account if it exists, if not: return empty. + */ + Account getAccountByBban(Long bban); } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/service/BankProfileService.java b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/service/BankProfileService.java index c92a7301d696e3f2e1a86abbd15c1c2ed32d0152..2d5b7ccb0ad9a84837d7ba8891a8200d9bdcc615 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/service/BankProfileService.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/service/BankProfileService.java @@ -10,11 +10,11 @@ import org.springframework.stereotype.Service; @Service public interface BankProfileService { - /** - * Create a new bank profile. - * - * @param bankProfileDTO The DTO containing the user's Social Security Number. - * @return a {@link BankProfileResponseDTO} containing profile information. - */ - BankProfileResponseDTO saveBankProfile(BankProfileDTO bankProfileDTO); + /** + * Create a new bank profile. + * @param bankProfileDTO The DTO containing the user's Social Security Number. + * @return a {@link BankProfileResponseDTO} containing profile information. + */ + BankProfileResponseDTO saveBankProfile(BankProfileDTO bankProfileDTO); + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/service/TransactionService.java b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/service/TransactionService.java index dc01a15b1386266057cfcb1c1ab21ed09faf653b..2173ec9ab1f2165721c06207751302d13877098b 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/service/TransactionService.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/service/TransactionService.java @@ -9,12 +9,12 @@ import org.springframework.stereotype.Service; @Service public interface TransactionService { - /** - * Performs and saves a transaction between two accounts. - * - * @param transactionRequest The transaction to be performed, containing the bban of the creditor - * and debitor accounts in addition to the amount that is being - * transferred. - */ - void saveTransaction(TransactionDTO transactionRequest); + /** + * Performs and saves a transaction between two accounts. + * @param transactionRequest The transaction to be performed, containing the bban of + * the creditor and debitor accounts in addition to the amount that is being + * transferred. + */ + void saveTransaction(TransactionDTO transactionRequest); + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/service/impl/AccountServiceImpl.java b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/service/impl/AccountServiceImpl.java index e373afb421b27f1ab4cfa634f1a090dcf10e9b33..5cc0c962bdf64cdeb1d400ea8c4a7afa8e2c0fb4 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/service/impl/AccountServiceImpl.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/service/impl/AccountServiceImpl.java @@ -22,100 +22,99 @@ import org.springframework.web.server.ResponseStatusException; @Service public class AccountServiceImpl implements AccountService { - @Autowired - private AccountRepository accountRepository; + @Autowired + private AccountRepository accountRepository; - @Autowired - private BankProfileRepository bankProfileRepository; + @Autowired + private BankProfileRepository bankProfileRepository; - /** - * Get a list of accounts of a bank profile by providing the associated id of the bank profile. - * - * @param id The id of the bank profile. - * @return A list of accounts. - */ - @Override - public List<Account> getAccountsByBankProfileId(Long id) { - List<Account> accountList; - Optional<BankProfile> bankProfile = bankProfileRepository.findById(id); - if (bankProfile.isEmpty()) { - log.error("[AccountServiceImpl:getAccountsByBankProfileId] bank: Bank profile not found"); - throw new ResponseStatusException(HttpStatusCode.valueOf(404), "Bank profile not found"); - } - accountList = accountRepository.findAllByBankProfileId(id); - log.info("[AccountServiceImpl:getAccountsByBankProfileId] bankProfileId: {}", id); - for (Account account : accountList) { - log.info("[AccountServiceImpl:getAccountsByBankProfileId] accountBban: {}", account.getBban()); - } - return accountList; - } + /** + * Get a list of accounts of a bank profile by providing the associated id of the bank + * profile. + * @param id The id of the bank profile. + * @return A list of accounts. + */ + @Override + public List<Account> getAccountsByBankProfileId(Long id) { + List<Account> accountList; + Optional<BankProfile> bankProfile = bankProfileRepository.findById(id); + if (bankProfile.isEmpty()) { + log.error("[AccountServiceImpl:getAccountsByBankProfileId] bank: Bank profile not found"); + throw new ResponseStatusException(HttpStatusCode.valueOf(404), "Bank profile not found"); + } + accountList = accountRepository.findAllByBankProfileId(id); + log.info("[AccountServiceImpl:getAccountsByBankProfileId] bankProfileId: {}", id); + for (Account account : accountList) { + log.info("[AccountServiceImpl:getAccountsByBankProfileId] accountBban: {}", account.getBban()); + } + return accountList; + } - /** - * Get a list of accounts of a bank profile by providing the associated Social Security Number - * of the bank profile. - * - * @param ssn The Social Security Number of the bank profile. - * @return A list of accounts. - */ - @Override - public List<Account> getAccountsBySsn(Long ssn) { - List<Account> accountList; - Optional<BankProfile> bankProfile = bankProfileRepository.findBySsn(ssn); - if (bankProfile.isEmpty()) { - log.error("[AccountServiceImpl:getAccountsBySsn] bank: Bank profile not found"); - throw new ResponseStatusException(HttpStatusCode.valueOf(404), "Bank profile not found"); - } - accountList = accountRepository.findAllByBankProfileSsn(ssn); - log.info("[AccountServiceImpl:getAccountsBySsn] ssn: {}", ssn); - for (Account account : accountList) { - log.info("[AccountServiceImpl:getAccountsBySsn] accountBban: {}", account.getBban()); - } - return accountList; - } + /** + * Get a list of accounts of a bank profile by providing the associated Social + * Security Number of the bank profile. + * @param ssn The Social Security Number of the bank profile. + * @return A list of accounts. + */ + @Override + public List<Account> getAccountsBySsn(Long ssn) { + List<Account> accountList; + Optional<BankProfile> bankProfile = bankProfileRepository.findBySsn(ssn); + if (bankProfile.isEmpty()) { + log.error("[AccountServiceImpl:getAccountsBySsn] bank: Bank profile not found"); + throw new ResponseStatusException(HttpStatusCode.valueOf(404), "Bank profile not found"); + } + accountList = accountRepository.findAllByBankProfileSsn(ssn); + log.info("[AccountServiceImpl:getAccountsBySsn] ssn: {}", ssn); + for (Account account : accountList) { + log.info("[AccountServiceImpl:getAccountsBySsn] accountBban: {}", account.getBban()); + } + return accountList; + } - /** - * Saves an account to the database. - * - * @param accountRequestDto The DTO containing the bank profile id. - * @return The saved account. - * @throws ResponseStatusException if the profile was not found, or the account could not be - * created - */ - @Override - public AccountResponseDTO saveAccount(AccountRequestDTO accountRequestDto) throws ResponseStatusException { - AccountResponseDTO accountResponseDTO = new AccountResponseDTO(); - try { - Optional<BankProfile> profile = bankProfileRepository.findBySsn(accountRequestDto.getSsn()); - if (profile.isEmpty()) { - log.error("[AccountServiceImpl:saveAccount] bank: Bank profile not found"); - throw new ResponseStatusException(HttpStatusCode.valueOf(404), "Bank profile not found"); - } - Account newAccount = new Account(); - newAccount.setBankProfile(profile.get()); - accountRepository.save(newAccount); - accountResponseDTO.setBalance(newAccount.getBalance()); - accountResponseDTO.setBankProfileId(newAccount.getBankProfile().getId()); - log.info("[AccountServiceImpl:saveAccount] accountBban: {}", newAccount.getBban()); - } catch (Exception e) { - throw new ResponseStatusException(HttpStatusCode.valueOf(400), e.getMessage()); - } - return accountResponseDTO; - } + /** + * Saves an account to the database. + * @param accountRequestDto The DTO containing the bank profile id. + * @return The saved account. + * @throws ResponseStatusException if the profile was not found, or the account could + * not be created + */ + @Override + public AccountResponseDTO saveAccount(AccountRequestDTO accountRequestDto) throws ResponseStatusException { + AccountResponseDTO accountResponseDTO = new AccountResponseDTO(); + try { + Optional<BankProfile> profile = bankProfileRepository.findBySsn(accountRequestDto.getSsn()); + if (profile.isEmpty()) { + log.error("[AccountServiceImpl:saveAccount] bank: Bank profile not found"); + throw new ResponseStatusException(HttpStatusCode.valueOf(404), "Bank profile not found"); + } + Account newAccount = new Account(); + newAccount.setBankProfile(profile.get()); + accountRepository.save(newAccount); + accountResponseDTO.setBalance(newAccount.getBalance()); + accountResponseDTO.setBankProfileId(newAccount.getBankProfile().getId()); + log.info("[AccountServiceImpl:saveAccount] accountBban: {}", newAccount.getBban()); + } + catch (Exception e) { + throw new ResponseStatusException(HttpStatusCode.valueOf(400), e.getMessage()); + } + return accountResponseDTO; + } + + /** + * Get an account given the Basic Bank Account Number + * @param bban The Basic Bank Account Number belonging to the account. + * @return The account if it exists, if not: return empty. + */ + @Override + public Account getAccountByBban(Long bban) { + Optional<Account> account = accountRepository.findAccountByBban(bban); + if (account.isEmpty()) { + log.error("[AccountServiceImpl:getAccountByBban] account: Account not found {}", bban); + throw new ResponseStatusException(HttpStatusCode.valueOf(404), "Account not found"); + } + log.info("[AccountServiceImpl:getAccountByBban] accountBban: {}", account.get().getBban()); + return account.get(); + } - /** - * Get an account given the Basic Bank Account Number - * - * @param bban The Basic Bank Account Number belonging to the account. - * @return The account if it exists, if not: return empty. - */ - @Override - public Account getAccountByBban(Long bban) { - Optional<Account> account = accountRepository.findAccountByBban(bban); - if (account.isEmpty()) { - log.error("[AccountServiceImpl:getAccountByBban] account: Account not found {}", bban); - throw new ResponseStatusException(HttpStatusCode.valueOf(404), "Account not found"); - } - log.info("[AccountServiceImpl:getAccountByBban] accountBban: {}", account.get().getBban()); - return account.get(); - } } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/service/impl/BankProfileServiceImpl.java b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/service/impl/BankProfileServiceImpl.java index 331a4c898ac5fb42c5e77ed02f205f9cd409f2e2..f8e60abf5581ca0fa5645b3133f14a14f3b193dc 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/service/impl/BankProfileServiceImpl.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/service/impl/BankProfileServiceImpl.java @@ -15,45 +15,45 @@ import org.springframework.stereotype.Service; import org.springframework.web.server.ResponseStatusException; /** - * Implementation of the {@link BankProfileService} interface for bank profile related operations. + * Implementation of the {@link BankProfileService} interface for bank profile related + * operations. */ @Slf4j @Service public class BankProfileServiceImpl implements BankProfileService { - @Autowired - private BankProfileRepository bankProfileRepository; - - /** - * Create a new bank profile. - * - * @param bankProfileDTO The DTO containing the user's Social Security Number. - * @return a {@link BankProfileResponseDTO} containing profile information. - */ - @Override - public BankProfileResponseDTO saveBankProfile(BankProfileDTO bankProfileDTO) { - - if (bankProfileDTO.getSsn() < 1) { - log.error("[BankProfileServiceImpl:saveBankProfile] Negative ssn: {}", bankProfileDTO.getSsn()); - throw new ResponseStatusException(HttpStatusCode.valueOf(400), "Negative ssn"); - } - - BankProfile newBankProfile = new BankProfile(); - List<Account> newEmptyAccountList = new ArrayList<>(); - BankProfileResponseDTO savedProfileResponse = new BankProfileResponseDTO(); - - newBankProfile.setSsn(bankProfileDTO.getSsn()); - try { - BankProfile savedBankProfile = bankProfileRepository.save(newBankProfile); - savedProfileResponse.setSsn(savedBankProfile.getSsn()); - savedProfileResponse.setAccounts(newEmptyAccountList); - } catch (Exception e) { - log.error("[BankProfileServiceImpl:saveBankProfile] Negative ssn: {}", bankProfileDTO.getSsn()); - throw new ResponseStatusException( - HttpStatusCode.valueOf(400), - "Could not create bank profile"); - } - log.info("[BankProfileServiceImpl:saveBankProfile] bank-profileSsn: {}", bankProfileDTO.getSsn()); - return savedProfileResponse; - } + @Autowired + private BankProfileRepository bankProfileRepository; + + /** + * Create a new bank profile. + * @param bankProfileDTO The DTO containing the user's Social Security Number. + * @return a {@link BankProfileResponseDTO} containing profile information. + */ + @Override + public BankProfileResponseDTO saveBankProfile(BankProfileDTO bankProfileDTO) { + + if (bankProfileDTO.getSsn() < 1) { + log.error("[BankProfileServiceImpl:saveBankProfile] Negative ssn: {}", bankProfileDTO.getSsn()); + throw new ResponseStatusException(HttpStatusCode.valueOf(400), "Negative ssn"); + } + + BankProfile newBankProfile = new BankProfile(); + List<Account> newEmptyAccountList = new ArrayList<>(); + BankProfileResponseDTO savedProfileResponse = new BankProfileResponseDTO(); + + newBankProfile.setSsn(bankProfileDTO.getSsn()); + try { + BankProfile savedBankProfile = bankProfileRepository.save(newBankProfile); + savedProfileResponse.setSsn(savedBankProfile.getSsn()); + savedProfileResponse.setAccounts(newEmptyAccountList); + } + catch (Exception e) { + log.error("[BankProfileServiceImpl:saveBankProfile] Negative ssn: {}", bankProfileDTO.getSsn()); + throw new ResponseStatusException(HttpStatusCode.valueOf(400), "Could not create bank profile"); + } + log.info("[BankProfileServiceImpl:saveBankProfile] bank-profileSsn: {}", bankProfileDTO.getSsn()); + return savedProfileResponse; + } + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/service/impl/TransactionServiceImpl.java b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/service/impl/TransactionServiceImpl.java index 8015b5272cd4b8072b04c227d31423aa6b48dc6b..81b0c2a4428cbd50fd4d9d6dee2e3e15a2015c2a 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/bank/service/impl/TransactionServiceImpl.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/bank/service/impl/TransactionServiceImpl.java @@ -15,75 +15,75 @@ import org.springframework.stereotype.Service; import org.springframework.web.server.ResponseStatusException; /** - * Implementation of the {@link TransactionService} interface for transaction related operations. + * Implementation of the {@link TransactionService} interface for transaction related + * operations. */ @Service @Slf4j public class TransactionServiceImpl implements TransactionService { - @Autowired - private TransactionRepository transactionRepository; + @Autowired + private TransactionRepository transactionRepository; - @Autowired - private AccountRepository accountRepository; + @Autowired + private AccountRepository accountRepository; - /** - * Performs and saves a transaction between two accounts. - * - * @param transactionRequest The transaction to be performed, containing the bban of the creditor - * and debitor accounts in addition to the amount that is being - * transferred. - */ - @Override - public void saveTransaction(TransactionDTO transactionRequest){ + /** + * Performs and saves a transaction between two accounts. + * @param transactionRequest The transaction to be performed, containing the bban of + * the creditor and debitor accounts in addition to the amount that is being + * transferred. + */ + @Override + public void saveTransaction(TransactionDTO transactionRequest) { - boolean negativeTransactionAmount = (transactionRequest.getAmount().signum() == -1); + boolean negativeTransactionAmount = (transactionRequest.getAmount().signum() == -1); - if (negativeTransactionAmount) { - log.error("[TransactionService:saveTransaction] Negative transfer amount: {}", transactionRequest.getAmount()); - throw new ResponseStatusException(HttpStatusCode.valueOf(400), "Negative transfer amount"); - } + if (negativeTransactionAmount) { + log.error("[TransactionService:saveTransaction] Negative transfer amount: {}", + transactionRequest.getAmount()); + throw new ResponseStatusException(HttpStatusCode.valueOf(400), "Negative transfer amount"); + } - Optional<Account> debtorAccount = - accountRepository.findAccountByBban(transactionRequest.getDebtorBBAN()); - if (debtorAccount.isEmpty()) { - log.error("[TransactionService:saveTransaction] Debtor account not found: {}", transactionRequest.getDebtorBBAN()); - throw new ResponseStatusException(HttpStatusCode.valueOf(404), "Debtor account not found"); - } - Optional<Account> creditorAccount = - accountRepository.findAccountByBban(transactionRequest.getCreditorBBAN()); - if (creditorAccount.isEmpty()) { - log.error("[TransactionService:saveTransaction] Creditor account not found: {}", transactionRequest.getDebtorBBAN()); - throw new ResponseStatusException(HttpStatusCode.valueOf(404), "Creditor account not found"); - } + Optional<Account> debtorAccount = accountRepository.findAccountByBban(transactionRequest.getDebtorBBAN()); + if (debtorAccount.isEmpty()) { + log.error("[TransactionService:saveTransaction] Debtor account not found: {}", + transactionRequest.getDebtorBBAN()); + throw new ResponseStatusException(HttpStatusCode.valueOf(404), "Debtor account not found"); + } + Optional<Account> creditorAccount = accountRepository.findAccountByBban(transactionRequest.getCreditorBBAN()); + if (creditorAccount.isEmpty()) { + log.error("[TransactionService:saveTransaction] Creditor account not found: {}", + transactionRequest.getDebtorBBAN()); + throw new ResponseStatusException(HttpStatusCode.valueOf(404), "Creditor account not found"); + } - boolean negativeFunds = ((debtorAccount.get().getBalance().subtract(transactionRequest.getAmount())).signum() == -1); - if (negativeFunds) { - log.error("[TransactionService:saveTransaction] Insufficient funds: {}", transactionRequest.getAmount()); - throw new ResponseStatusException(HttpStatusCode.valueOf(402), "Insufficient funds"); - } + boolean negativeFunds = ((debtorAccount.get().getBalance().subtract(transactionRequest.getAmount())) + .signum() == -1); + if (negativeFunds) { + log.error("[TransactionService:saveTransaction] Insufficient funds: {}", transactionRequest.getAmount()); + throw new ResponseStatusException(HttpStatusCode.valueOf(402), "Insufficient funds"); + } - try { - Transaction savedTransaction = new Transaction(); - savedTransaction.setDebtorAccount(debtorAccount.get()); - savedTransaction.setCreditorAccount(creditorAccount.get()); - savedTransaction.setAmount(transactionRequest.getAmount()); + try { + Transaction savedTransaction = new Transaction(); + savedTransaction.setDebtorAccount(debtorAccount.get()); + savedTransaction.setCreditorAccount(creditorAccount.get()); + savedTransaction.setAmount(transactionRequest.getAmount()); - BigDecimal debtorBalance = ( - debtorAccount.get().getBalance()).subtract(transactionRequest.getAmount() - ); + BigDecimal debtorBalance = (debtorAccount.get().getBalance()).subtract(transactionRequest.getAmount()); - BigDecimal creditorBalance = ( - creditorAccount.get().getBalance().add(transactionRequest.getAmount()) - ); + BigDecimal creditorBalance = (creditorAccount.get().getBalance().add(transactionRequest.getAmount())); + + accountRepository.updateBalance(debtorBalance, debtorAccount.get().getBban()); + accountRepository.updateBalance(creditorBalance, creditorAccount.get().getBban()); + transactionRepository.save(savedTransaction); + log.info("[TransactionService:saveTransaction] saved transaction with id: {}", savedTransaction.getId()); + } + catch (Exception e) { + log.error("[TransactionService:saveTransaction] Transaction failed"); + throw new ResponseStatusException(HttpStatusCode.valueOf(400), e.getMessage()); + } + } - accountRepository.updateBalance(debtorBalance, debtorAccount.get().getBban()); - accountRepository.updateBalance(creditorBalance, creditorAccount.get().getBban()); - transactionRepository.save(savedTransaction); - log.info("[TransactionService:saveTransaction] saved transaction with id: {}", savedTransaction.getId()); - } catch (Exception e) { - log.error("[TransactionService:saveTransaction] Transaction failed"); - throw new ResponseStatusException(HttpStatusCode.valueOf(400), e.getMessage()); - } - } } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/config/ModelMapperConfig.java b/src/main/java/no/ntnu/idi/stud/savingsapp/config/ModelMapperConfig.java index dae50d1b1071390ab78ea8a480d09ea3d3f43144..d2c5796cc35c84b5946a1912b297816fb2f26553 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/config/ModelMapperConfig.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/config/ModelMapperConfig.java @@ -10,13 +10,13 @@ import org.springframework.context.annotation.Configuration; @Configuration public class ModelMapperConfig { - /** - * Configures and provides the ModelMapper bean. - * - * @return ModelMapper bean configured with custom mappings. - */ - @Bean - public ModelMapper modelMapper() { - return new ModelMapper(); - } + /** + * Configures and provides the ModelMapper bean. + * @return ModelMapper bean configured with custom mappings. + */ + @Bean + public ModelMapper modelMapper() { + return new ModelMapper(); + } + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/config/OpenAPIConfig.java b/src/main/java/no/ntnu/idi/stud/savingsapp/config/OpenAPIConfig.java index 20d9d1b0d310d3ace41347d7bf414f98779eb082..11a99c91d5dfccdf66ccc0a26bd1fdbc804b430e 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/config/OpenAPIConfig.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/config/OpenAPIConfig.java @@ -9,28 +9,29 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** - * Configuration class for OpenAPI documentation generation. - * This class defines beans for configuring the OpenAPI documentation of the API. + * Configuration class for OpenAPI documentation generation. This class defines beans for + * configuring the OpenAPI documentation of the API. */ @Configuration public class OpenAPIConfig { - /** - * Creates and configures the OpenAPI bean for the API. - * @return The configured OpenAPI object representing the API documentation. - */ - @Bean - public OpenAPI openAPI() { - return new OpenAPI().addSecurityItem(new SecurityRequirement().addList("Bearer Authentication")) - .components(new Components().addSecuritySchemes("Bearer Authentication", createAPIKeyScheme())) - .info(new Info().title("Sparesti API").description("The Sparesti API").version("3.0")); - } + /** + * Creates and configures the OpenAPI bean for the API. + * @return The configured OpenAPI object representing the API documentation. + */ + @Bean + public OpenAPI openAPI() { + return new OpenAPI().addSecurityItem(new SecurityRequirement().addList("Bearer Authentication")) + .components(new Components().addSecuritySchemes("Bearer Authentication", createAPIKeyScheme())) + .info(new Info().title("Sparesti API").description("The Sparesti API").version("3.0")); + } + + /** + * Creates a SecurityScheme object representing the API key (Bearer token) scheme. + * @return The configured SecurityScheme object for API key authentication. + */ + private SecurityScheme createAPIKeyScheme() { + return new SecurityScheme().type(SecurityScheme.Type.HTTP).bearerFormat("JWT").scheme("bearer"); + } - /** - * Creates a SecurityScheme object representing the API key (Bearer token) scheme. - * @return The configured SecurityScheme object for API key authentication. - */ - private SecurityScheme createAPIKeyScheme() { - return new SecurityScheme().type(SecurityScheme.Type.HTTP).bearerFormat("JWT").scheme("bearer"); - } } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/controller/authentication/AuthenticationController.java b/src/main/java/no/ntnu/idi/stud/savingsapp/controller/authentication/AuthenticationController.java index 101f331739a11dbfae7daa7d3d8acc9e0a877ff8..c230a96c241be790691a43e200a253bf9a3f2b8a 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/controller/authentication/AuthenticationController.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/controller/authentication/AuthenticationController.java @@ -41,117 +41,108 @@ import org.springframework.web.bind.annotation.*; @Slf4j public class AuthenticationController { - @Autowired - private UserService userService; + @Autowired + private UserService userService; - @Autowired - private ModelMapper modelMapper; + @Autowired + private ModelMapper modelMapper; - /** - * Handles user login requests. - * - * @param request The login request. - * @return ResponseEntity containing the authentication response. - * @throws InvalidCredentialsException if the provided credentials are invalid. - * @throws UserNotFoundException if the user is not found. - */ - @Operation(summary = "User Login", description = "Log in with an existing user") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully logged in"), - @ApiResponse(responseCode = "401", description = "Invalid credentials", - content = @Content(schema = @Schema(implementation = ExceptionResponse.class))), - @ApiResponse(responseCode = "404", description = "User not found", - content = @Content(schema = @Schema(implementation = ExceptionResponse.class))) - }) - @SecurityRequirements - @PostMapping(value = "/login", produces = MediaType.APPLICATION_JSON_VALUE, - consumes = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<AuthenticationResponse> login(@RequestBody @Valid LoginRequest request) { - User user = userService.login(request.getEmail(), request.getPassword()); - String token = TokenUtils.generateToken(user); - log.info("[AuthenticationController:login] Successfully logged in") ; - return ResponseEntity.ok(new AuthenticationResponse(user.getFirstName(), - user.getLastName(), user.getId(), user.getProfileImage(), user.getRole().name(), - user.getSubscriptionLevel().name(), token)); - } + /** + * Handles user login requests. + * @param request The login request. + * @return ResponseEntity containing the authentication response. + * @throws InvalidCredentialsException if the provided credentials are invalid. + * @throws UserNotFoundException if the user is not found. + */ + @Operation(summary = "User Login", description = "Log in with an existing user") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully logged in"), + @ApiResponse(responseCode = "401", description = "Invalid credentials", + content = @Content(schema = @Schema(implementation = ExceptionResponse.class))), + @ApiResponse(responseCode = "404", description = "User not found", + content = @Content(schema = @Schema(implementation = ExceptionResponse.class))) }) + @SecurityRequirements + @PostMapping(value = "/login", produces = MediaType.APPLICATION_JSON_VALUE, + consumes = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<AuthenticationResponse> login(@RequestBody @Valid LoginRequest request) { + User user = userService.login(request.getEmail(), request.getPassword()); + String token = TokenUtils.generateToken(user); + log.info("[AuthenticationController:login] Successfully logged in"); + return ResponseEntity.ok(new AuthenticationResponse(user.getFirstName(), user.getLastName(), user.getId(), + user.getProfileImage(), user.getRole().name(), user.getSubscriptionLevel().name(), token)); + } - /** - * Handles user signup requests. - * - * @param request The signup request. - * @return ResponseEntity containing the authentication response. - * @throws EmailAlreadyExistsException if the email is registered with an existing user. - */ - @Operation(summary = "User Signup", description = "Sign up a new user") - @ApiResponses(value = { - @ApiResponse(responseCode = "201", description = "Successfully signed up"), - @ApiResponse(responseCode = "409", description = "Email already exists", - content = @Content(schema = @Schema(implementation = ExceptionResponse.class))) - }) - @SecurityRequirements - @PostMapping(value = "/signup", produces = MediaType.APPLICATION_JSON_VALUE, - consumes = MediaType.APPLICATION_JSON_VALUE) - @ResponseStatus(value = HttpStatus.CREATED) - public ResponseEntity<AuthenticationResponse> signup(@RequestBody @Valid SignUpRequest request) { - User requestUser = modelMapper.map(request, User.class); - User user = userService.register(requestUser); - String token = TokenUtils.generateToken(user); - log.info("[AuthenticationController:signup] Successfully signed up") ; - return ResponseEntity.status(HttpStatus.CREATED).body(new AuthenticationResponse(user.getFirstName(), - user.getLastName(), user.getId(), user.getProfileImage(), user.getRole().name(), - user.getSubscriptionLevel().name(), token)); - } + /** + * Handles user signup requests. + * @param request The signup request. + * @return ResponseEntity containing the authentication response. + * @throws EmailAlreadyExistsException if the email is registered with an existing + * user. + */ + @Operation(summary = "User Signup", description = "Sign up a new user") + @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "Successfully signed up"), + @ApiResponse(responseCode = "409", description = "Email already exists", + content = @Content(schema = @Schema(implementation = ExceptionResponse.class))) }) + @SecurityRequirements + @PostMapping(value = "/signup", produces = MediaType.APPLICATION_JSON_VALUE, + consumes = MediaType.APPLICATION_JSON_VALUE) + @ResponseStatus(value = HttpStatus.CREATED) + public ResponseEntity<AuthenticationResponse> signup(@RequestBody @Valid SignUpRequest request) { + User requestUser = modelMapper.map(request, User.class); + User user = userService.register(requestUser); + String token = TokenUtils.generateToken(user); + log.info("[AuthenticationController:signup] Successfully signed up"); + return ResponseEntity.status(HttpStatus.CREATED) + .body(new AuthenticationResponse(user.getFirstName(), user.getLastName(), user.getId(), + user.getProfileImage(), user.getRole().name(), user.getSubscriptionLevel().name(), token)); + } - /** - * Handles authentication requests using BankID. - * This method processes an authentication request by taking a unique code and state from the BankID request, - * verifies the user, and returns an authentication token along with user details. - * - * @param request The request body containing the authentication details required by BankID, - * specifically a 'code' and 'state' used for user verification. - * @return A ResponseEntity object containing the user's authentication details including a JWT token - * if the authentication is successful. - * @apiNote This method is protected by security requirements that must be met before the - * authentication can proceed. - */ - @Operation(summary = "Authenticate a BankID request", description = "Authenticate a BankID request") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "If the authentication is successful") - }) - @SecurityRequirements - @PostMapping(value = "/bank-id") - public ResponseEntity<AuthenticationResponse> bankIdAuthentication(@RequestBody BankIDRequest request) { - User user = userService.bankIDAuth(request.getCode(), request.getState()); - String token = TokenUtils.generateToken(user); - log.info("[AuthenticationController:bankIdAuthentication] BankId Authenticated successfully"); - return ResponseEntity.status(HttpStatus.CREATED).body(new AuthenticationResponse(user.getFirstName(), - user.getLastName(), user.getId(), user.getProfileImage(), user.getRole().name(), - user.getSubscriptionLevel().name(), token)); - } + /** + * Handles authentication requests using BankID. This method processes an + * authentication request by taking a unique code and state from the BankID request, + * verifies the user, and returns an authentication token along with user details. + * @param request The request body containing the authentication details required by + * BankID, specifically a 'code' and 'state' used for user verification. + * @return A ResponseEntity object containing the user's authentication details + * including a JWT token if the authentication is successful. + * @apiNote This method is protected by security requirements that must be met before + * the authentication can proceed. + */ + @Operation(summary = "Authenticate a BankID request", description = "Authenticate a BankID request") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "If the authentication is successful") }) + @SecurityRequirements + @PostMapping(value = "/bank-id") + public ResponseEntity<AuthenticationResponse> bankIdAuthentication(@RequestBody BankIDRequest request) { + User user = userService.bankIDAuth(request.getCode(), request.getState()); + String token = TokenUtils.generateToken(user); + log.info("[AuthenticationController:bankIdAuthentication] BankId Authenticated successfully"); + return ResponseEntity.status(HttpStatus.CREATED) + .body(new AuthenticationResponse(user.getFirstName(), user.getLastName(), user.getId(), + user.getProfileImage(), user.getRole().name(), user.getSubscriptionLevel().name(), token)); + } + + /** + * Validates an email. + * @param email The email. + * @return ResponseEntity. + * @throws EmailAlreadyExistsException if the email is registered with an existing + * user. + */ + @Operation(summary = "Validate email", description = "Check that the given email is valid") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Email is valid"), + @ApiResponse(responseCode = "409", description = "Email already exists", + content = @Content(schema = @Schema(implementation = ExceptionResponse.class))) }) + @SecurityRequirements + @PostMapping(value = "/valid-email/{email}") + public ResponseEntity<?> validateEmail(@PathVariable @Email(message = "Invalid email") String email) { + try { + userService.findByEmail(email); + log.error("[AuthenticationController:validateEmail] email already exists: {}", email); + throw new EmailAlreadyExistsException(); + } + catch (UserNotFoundException e) { + log.info("[AuthenticationController:validateEmail] email is valid: {}", email); + return ResponseEntity.ok().build(); + } + } - /** - * Validates an email. - * - * @param email The email. - * @return ResponseEntity. - * @throws EmailAlreadyExistsException if the email is registered with an existing user. - */ - @Operation(summary = "Validate email", description = "Check that the given email is valid") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Email is valid"), - @ApiResponse(responseCode = "409", description = "Email already exists", - content = @Content(schema = @Schema(implementation = ExceptionResponse.class))) - }) - @SecurityRequirements - @PostMapping(value = "/valid-email/{email}") - public ResponseEntity<?> validateEmail(@PathVariable @Email(message = "Invalid email") String email) { - try { - userService.findByEmail(email); - log.error("[AuthenticationController:validateEmail] email already exists: {}", email); - throw new EmailAlreadyExistsException(); - } catch (UserNotFoundException e) { - log.info("[AuthenticationController:validateEmail] email is valid: {}", email); - return ResponseEntity.ok().build(); - } - } } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/controller/badge/BadgeController.java b/src/main/java/no/ntnu/idi/stud/savingsapp/controller/badge/BadgeController.java index ffbabf712bcc0ff18736607a84ebaef7e882e78b..e9e3a7f05383667a0551953421d0010e46f5e9b0 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/controller/badge/BadgeController.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/controller/badge/BadgeController.java @@ -41,157 +41,142 @@ import org.springframework.web.bind.annotation.RestController; @Slf4j public class BadgeController { - @Autowired - private BadgeService badgeService; + @Autowired + private BadgeService badgeService; - @Autowired - private UserService userService; + @Autowired + private UserService userService; - @Autowired - private NotificationService notificationService; + @Autowired + private NotificationService notificationService; - @Autowired - private ModelMapper modelMapper; + @Autowired + private ModelMapper modelMapper; - /** - * Retrieves a badge by its id. - * - * @param badgeId The id of the badge to retrieve. - * @return ResponseEntity containing the BadgeDTO. - */ - @Operation(summary = "Get the budget", description = "Get budget by its id ") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully got budget"), - @ApiResponse(responseCode = "500", description = "Badge is not found"), - }) - @GetMapping(value = "/{badgeId}", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<BadgeDTO> getBadge(@PathVariable long badgeId) { - Badge badge = badgeService.findBadgeByBadgeId(badgeId); - BadgeDTO response = modelMapper.map(badge, BadgeDTO.class); - log.info("[BadgeController:getBadge] badge: {}", badge.getId()); - return ResponseEntity.ok(response); - } + /** + * Retrieves a badge by its id. + * @param badgeId The id of the badge to retrieve. + * @return ResponseEntity containing the BadgeDTO. + */ + @Operation(summary = "Get the budget", description = "Get budget by its id ") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully got budget"), + @ApiResponse(responseCode = "500", description = "Badge is not found"), }) + @GetMapping(value = "/{badgeId}", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<BadgeDTO> getBadge(@PathVariable long badgeId) { + Badge badge = badgeService.findBadgeByBadgeId(badgeId); + BadgeDTO response = modelMapper.map(badge, BadgeDTO.class); + log.info("[BadgeController:getBadge] badge: {}", badge.getId()); + return ResponseEntity.ok(response); + } - /** - * Retrieves all the badges. - * - * @return ResponseEntity containing a list of BadgeDTOs. - * @apiNote This endpoint is used to fetch all the badges stored in the database. - */ - @Operation(summary = "Get the list of badges", description = "Get all badges stored " + - "in the database") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully got badges") - }) - @GetMapping(value = "", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<List<BadgeDTO>> getAllBadges() { - List<Badge> badges = badgeService.findAllBadges(); - List<BadgeDTO> badgeDTOS = badges.stream().map(badge -> modelMapper.map(badge, BadgeDTO.class)).toList(); - for(BadgeDTO badgeDTO : badgeDTOS) { - log.info("[BadgeController:getAllBadges] badge: {}", badgeDTO.getId()); - } - return ResponseEntity.ok(badgeDTOS); - } + /** + * Retrieves all the badges. + * @return ResponseEntity containing a list of BadgeDTOs. + * @apiNote This endpoint is used to fetch all the badges stored in the database. + */ + @Operation(summary = "Get the list of badges", description = "Get all badges stored " + "in the database") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully got badges") }) + @GetMapping(value = "", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<List<BadgeDTO>> getAllBadges() { + List<Badge> badges = badgeService.findAllBadges(); + List<BadgeDTO> badgeDTOS = badges.stream().map(badge -> modelMapper.map(badge, BadgeDTO.class)).toList(); + for (BadgeDTO badgeDTO : badgeDTOS) { + log.info("[BadgeController:getAllBadges] badge: {}", badgeDTO.getId()); + } + return ResponseEntity.ok(badgeDTOS); + } - /** - * Retrieves all the badges unlocked by active user. - * - * @param identity The security context of the authenticated user. - * @return ResponseEntity containing a list of BadgeDTOs. - * @apiNote This endpoint is used to fetch all the badges that are unlocked by the active user. - */ - @Operation(summary = "Get the list of badges", description = "Get all badges unlocked " + - "by the user") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully got badges") - }) - @GetMapping(value = "unlocked", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<List<BadgeDTO>> getBadgesUnlockedByActiveUser(@AuthenticationPrincipal AuthIdentity identity) { - List<Badge> badges = badgeService.findBadgesUnlockedByUser(identity.getId()); - List<BadgeDTO> badgeDTOS = badges.stream().map(badge -> modelMapper.map(badge, BadgeDTO.class)).toList(); - log.info("[BadgeController:getBadgesUnlockedByUser] userId: {}", identity.getId()); - for(BadgeDTO badgeDTO : badgeDTOS) { - log.info("[BadgeController:getBadgesUnlockedByUser] badge: {}", badgeDTO.getId()); - } - return ResponseEntity.ok(badgeDTOS); - } + /** + * Retrieves all the badges unlocked by active user. + * @param identity The security context of the authenticated user. + * @return ResponseEntity containing a list of BadgeDTOs. + * @apiNote This endpoint is used to fetch all the badges that are unlocked by the + * active user. + */ + @Operation(summary = "Get the list of badges", description = "Get all badges unlocked " + "by the user") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully got badges") }) + @GetMapping(value = "unlocked", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<List<BadgeDTO>> getBadgesUnlockedByActiveUser( + @AuthenticationPrincipal AuthIdentity identity) { + List<Badge> badges = badgeService.findBadgesUnlockedByUser(identity.getId()); + List<BadgeDTO> badgeDTOS = badges.stream().map(badge -> modelMapper.map(badge, BadgeDTO.class)).toList(); + log.info("[BadgeController:getBadgesUnlockedByUser] userId: {}", identity.getId()); + for (BadgeDTO badgeDTO : badgeDTOS) { + log.info("[BadgeController:getBadgesUnlockedByUser] badge: {}", badgeDTO.getId()); + } + return ResponseEntity.ok(badgeDTOS); + } - /** - * Retrieves all the badges unlocked by the user. - * - * @param userId The is of the user. - * @return ResponseEntity containing a list of BadgeDTOs. - * @apiNote This endpoint is used to fetch all the badges that are unlocked by the user. - */ - @Operation(summary = "Get the list of badges", description = "Get all badges unlocked " + - "by the user") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully got badges") - }) - @GetMapping(value = "unlocked/{userId}", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<List<BadgeDTO>> getBadgesUnlockedByUser(@PathVariable Long userId) { - List<Badge> badges = badgeService.findBadgesUnlockedByUser(userId); - List<BadgeDTO> badgeDTOS = badges.stream().map(badge -> modelMapper.map(badge, BadgeDTO.class)).toList(); - log.info("[BadgeController:getBadgesUnlockedByUser] userId: {}", userId); - for(BadgeDTO badgeDTO : badgeDTOS) { - log.info("[BadgeController:getBadgesUnlockedByUser] badge: {}", badgeDTO.getId()); - } - return ResponseEntity.ok(badgeDTOS); - } + /** + * Retrieves all the badges unlocked by the user. + * @param userId The is of the user. + * @return ResponseEntity containing a list of BadgeDTOs. + * @apiNote This endpoint is used to fetch all the badges that are unlocked by the + * user. + */ + @Operation(summary = "Get the list of badges", description = "Get all badges unlocked " + "by the user") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully got badges") }) + @GetMapping(value = "unlocked/{userId}", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<List<BadgeDTO>> getBadgesUnlockedByUser(@PathVariable Long userId) { + List<Badge> badges = badgeService.findBadgesUnlockedByUser(userId); + List<BadgeDTO> badgeDTOS = badges.stream().map(badge -> modelMapper.map(badge, BadgeDTO.class)).toList(); + log.info("[BadgeController:getBadgesUnlockedByUser] userId: {}", userId); + for (BadgeDTO badgeDTO : badgeDTOS) { + log.info("[BadgeController:getBadgesUnlockedByUser] badge: {}", badgeDTO.getId()); + } + return ResponseEntity.ok(badgeDTOS); + } - /** - * Retrieves all the badges not unlocked by the active user. - * - * @param identity The security context of the authenticated user. - * @return ResponseEntity containing a list of BadgeDTOs. - * @apiNote This endpoint is used to fetch all the badges that are not unlocked by the user. - */ - @Operation(summary = "Get the list of badges", description = "Get all badges not " + - "unlocked by the user") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully got badges") - }) - @GetMapping(value = "locked", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<List<BadgeDTO>> getBadgesNotUnlockedByActiveUser(@AuthenticationPrincipal AuthIdentity identity) { - List<Badge> badges = badgeService.findBadgesNotUnlockedByUser(identity.getId()); - List<BadgeDTO> badgeDTOS = badges.stream().map(badge -> modelMapper.map(badge, BadgeDTO.class)).toList(); - log.info("[BadgeController:getBadgesNotUnlockedByUser] userId: {}", identity.getId()); - for(BadgeDTO badgeDTO : badgeDTOS) { - log.info("[BadgeController:getBadgesNotUnlockedByUser] badge: {}", badgeDTO.getId()); - } - return ResponseEntity.ok(badgeDTOS); - } + /** + * Retrieves all the badges not unlocked by the active user. + * @param identity The security context of the authenticated user. + * @return ResponseEntity containing a list of BadgeDTOs. + * @apiNote This endpoint is used to fetch all the badges that are not unlocked by the + * user. + */ + @Operation(summary = "Get the list of badges", description = "Get all badges not " + "unlocked by the user") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully got badges") }) + @GetMapping(value = "locked", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<List<BadgeDTO>> getBadgesNotUnlockedByActiveUser( + @AuthenticationPrincipal AuthIdentity identity) { + List<Badge> badges = badgeService.findBadgesNotUnlockedByUser(identity.getId()); + List<BadgeDTO> badgeDTOS = badges.stream().map(badge -> modelMapper.map(badge, BadgeDTO.class)).toList(); + log.info("[BadgeController:getBadgesNotUnlockedByUser] userId: {}", identity.getId()); + for (BadgeDTO badgeDTO : badgeDTOS) { + log.info("[BadgeController:getBadgesNotUnlockedByUser] badge: {}", badgeDTO.getId()); + } + return ResponseEntity.ok(badgeDTOS); + } + + /** + * Updates the unlocked badges for the active user by checking if a user's score + * matches the badges criteria, and if so adds the badge to the user and sends a + * notification that the badge is unlocked. + * @param identity The security context of the authenticated user. + * @return ResponseEntity containing a list of newly unlocked badges. + */ + @Operation(summary = "Updates unlocked badges", + description = "Checks if a user " + "has met the criteria for unlocking badges") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully updated badges") }) + @GetMapping(value = "update", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<?> updateUnlockedBadges(@AuthenticationPrincipal AuthIdentity identity) { + User user = userService.findById(identity.getId()); + System.out.println(user.getPoint().getTotalEarnedPoints()); + List<Badge> badges = badgeService.findNewlyUnlockedBadgesByUserId(identity.getId()); + for (Badge badge : badges) { + BadgeUserId badgeUserId = new BadgeUserId(badge, user); + badgeService.addBadgeToUser(badgeUserId); + // Send a notification that a new badge is unlocked + Notification notification = new Notification(null, user, + "You have unlocked a new badge " + badge.getBadgeName(), true, NotificationType.BADGE, + Timestamp.from(Instant.now())); + notificationService.updateNotification(notification); + } + List<BadgeDTO> badgeDTOS = badges.stream().map(badge -> modelMapper.map(badge, BadgeDTO.class)).toList(); + for (BadgeDTO badgeDTO : badgeDTOS) { + log.info("[BadgeController:updateUnlockedBadges] badge: {}", badgeDTO.getId()); + } + return ResponseEntity.ok(badgeDTOS); + } - /** - * Updates the unlocked badges for the active user by checking if - * a user's score matches the badges criteria, and if so adds - * the badge to the user and sends a notification that the badge is unlocked. - * - * @param identity The security context of the authenticated user. - * @return ResponseEntity containing a list of newly unlocked badges. - */ - @Operation(summary = "Updates unlocked badges", description = "Checks if a user " + - "has met the criteria for unlocking badges") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully updated badges") - }) - @GetMapping(value = "update", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<?> updateUnlockedBadges(@AuthenticationPrincipal AuthIdentity identity) { - User user = userService.findById(identity.getId()); - System.out.println(user.getPoint().getTotalEarnedPoints()); - List<Badge> badges = badgeService.findNewlyUnlockedBadgesByUserId(identity.getId()); - for (Badge badge : badges) { - BadgeUserId badgeUserId = new BadgeUserId(badge, user); - badgeService.addBadgeToUser(badgeUserId); - // Send a notification that a new badge is unlocked - Notification notification = new Notification(null, user, "You have unlocked a new badge " + badge.getBadgeName(), true, - NotificationType.BADGE, Timestamp.from(Instant.now())); - notificationService.updateNotification(notification); - } - List<BadgeDTO> badgeDTOS = badges.stream().map(badge -> modelMapper.map(badge, BadgeDTO.class)).toList(); - for(BadgeDTO badgeDTO : badgeDTOS) { - log.info("[BadgeController:updateUnlockedBadges] badge: {}", badgeDTO.getId()); - } - return ResponseEntity.ok(badgeDTOS); - } } \ No newline at end of file diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/controller/budget/BudgetController.java b/src/main/java/no/ntnu/idi/stud/savingsapp/controller/budget/BudgetController.java index 1ebb7caba862d444d6e145fbdaf918ec401a2385..29bbce5794858ee091c9730fb4d1d954ad317ad6 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/controller/budget/BudgetController.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/controller/budget/BudgetController.java @@ -46,205 +46,182 @@ import org.springframework.web.bind.annotation.RestController; @Slf4j public class BudgetController { - @Autowired - private BudgetService budgetService; + @Autowired + private BudgetService budgetService; - @Autowired - private UserService userService; + @Autowired + private UserService userService; - @Autowired - private ModelMapper modelMapper; + @Autowired + private ModelMapper modelMapper; - /** - * Retrieves all the budgets belonging to authenticated user. - * - * @param identity The security context of the authenticated user. - * @return ResponseEntity containing the list of BudgetResponseDTO of the authenticated user. - * @apiNote This endpoint is used to fetch all the budget's related to the authenticated user. - * It uses the user's ID stored in the authentication principal to filter for budgets. - */ - @Operation(summary = "Get the list of budgets", description = "Get all budgets related to " + - "the authenticated user") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully got budgets") - }) - @GetMapping(value = "", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<List<BudgetResponseDTO>> getBudgetsByUser(@AuthenticationPrincipal AuthIdentity identity) { - List<Budget> budgets = budgetService.findBudgetsByUserId(identity.getId()); - List<BudgetResponseDTO> budgetDTOs = new ArrayList<>(); - for (Budget budget : budgets) { - budgetDTOs.add(modelMapper.map(budget, BudgetResponseDTO.class)); - log.info("[BudgetController:getBudgetsByUser] budget: {}", budget.getId()); - } - Collections.reverse(budgetDTOs); - return ResponseEntity.ok(budgetDTOs); - } + /** + * Retrieves all the budgets belonging to authenticated user. + * @param identity The security context of the authenticated user. + * @return ResponseEntity containing the list of BudgetResponseDTO of the + * authenticated user. + * @apiNote This endpoint is used to fetch all the budget's related to the + * authenticated user. It uses the user's ID stored in the authentication principal to + * filter for budgets. + */ + @Operation(summary = "Get the list of budgets", + description = "Get all budgets related to " + "the authenticated user") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully got budgets") }) + @GetMapping(value = "", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<List<BudgetResponseDTO>> getBudgetsByUser(@AuthenticationPrincipal AuthIdentity identity) { + List<Budget> budgets = budgetService.findBudgetsByUserId(identity.getId()); + List<BudgetResponseDTO> budgetDTOs = new ArrayList<>(); + for (Budget budget : budgets) { + budgetDTOs.add(modelMapper.map(budget, BudgetResponseDTO.class)); + log.info("[BudgetController:getBudgetsByUser] budget: {}", budget.getId()); + } + Collections.reverse(budgetDTOs); + return ResponseEntity.ok(budgetDTOs); + } - /** - * Retrieves a budget by its id. - * - * @param budgetId The id of the budget to be retrieved. - * @return ResponseEntity containing the BudgetResponseDTO. - */ - @Operation(summary = "Get the budget", description = "Get budget by its id ") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully got budget"), - @ApiResponse(responseCode = "500", description = "Budget is not found"), - }) - @GetMapping(value = "/{budgetId}", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<BudgetResponseDTO> getBudget(@PathVariable long budgetId) { - Budget budget = budgetService.findBudgetById(budgetId); - BudgetResponseDTO response = modelMapper.map(budget, BudgetResponseDTO.class); - log.info("[BudgetController:getBudget] budget: {}", response.getId()); - return ResponseEntity.ok(response); - } + /** + * Retrieves a budget by its id. + * @param budgetId The id of the budget to be retrieved. + * @return ResponseEntity containing the BudgetResponseDTO. + */ + @Operation(summary = "Get the budget", description = "Get budget by its id ") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully got budget"), + @ApiResponse(responseCode = "500", description = "Budget is not found"), }) + @GetMapping(value = "/{budgetId}", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<BudgetResponseDTO> getBudget(@PathVariable long budgetId) { + Budget budget = budgetService.findBudgetById(budgetId); + BudgetResponseDTO response = modelMapper.map(budget, BudgetResponseDTO.class); + log.info("[BudgetController:getBudget] budget: {}", response.getId()); + return ResponseEntity.ok(response); + } - /** - * Creates a new budget . - * - * @param identity The security context of the authenticated user. - * @param request The budget request. - * @return ResponseEntity. - */ - @Operation(summary = "Create a new budget", description = "Create a new budget with based on the budget request") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully created new budget") - }) - @PostMapping(value = "/create", produces = MediaType.APPLICATION_JSON_VALUE, - consumes = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<?> createBudget(@AuthenticationPrincipal AuthIdentity identity, - @RequestBody BudgetRequestDTO request) { - Budget budget = modelMapper.map(request, Budget.class); - budget.setUser(userService.findById(identity.getId())); - budget.setCreatedAt(Timestamp.from(Instant.now())); - budgetService.createBudget(budget); - log.info("[BudgetController:createBudget] budget created: {}", budget.getId()); - return ResponseEntity.ok().build(); - } + /** + * Creates a new budget . + * @param identity The security context of the authenticated user. + * @param request The budget request. + * @return ResponseEntity. + */ + @Operation(summary = "Create a new budget", description = "Create a new budget with based on the budget request") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully created new budget") }) + @PostMapping(value = "/create", produces = MediaType.APPLICATION_JSON_VALUE, + consumes = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<?> createBudget(@AuthenticationPrincipal AuthIdentity identity, + @RequestBody BudgetRequestDTO request) { + Budget budget = modelMapper.map(request, Budget.class); + budget.setUser(userService.findById(identity.getId())); + budget.setCreatedAt(Timestamp.from(Instant.now())); + budgetService.createBudget(budget); + log.info("[BudgetController:createBudget] budget created: {}", budget.getId()); + return ResponseEntity.ok().build(); + } - /** - * Updates a budget. - * - * @param budgetId The budget's id. - * @param request The budget request. - * @return ResponseEntity. - */ - @Operation(summary = "Updates a budget", description = "Updates a budget based on the budget request") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully updated budget"), - @ApiResponse(responseCode = "500", description = "Budget is not found") - }) - @PostMapping(value = "/update/{budgetId}", produces = MediaType.APPLICATION_JSON_VALUE, - consumes = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<?> updateBudget(@PathVariable Long budgetId, @RequestBody BudgetRequestDTO request) { - Budget budget = budgetService.findBudgetById(budgetId); - budget.setBudgetName(request.getBudgetName()); - budget.setBudgetAmount(request.getBudgetAmount()); - budget.setExpenseAmount(request.getExpenseAmount()); - budgetService.updateBudget(budget); - log.info("[BudgetController:updateBudget] budget updated: {}", budget.getId()); - return ResponseEntity.ok().build(); - } + /** + * Updates a budget. + * @param budgetId The budget's id. + * @param request The budget request. + * @return ResponseEntity. + */ + @Operation(summary = "Updates a budget", description = "Updates a budget based on the budget request") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully updated budget"), + @ApiResponse(responseCode = "500", description = "Budget is not found") }) + @PostMapping(value = "/update/{budgetId}", produces = MediaType.APPLICATION_JSON_VALUE, + consumes = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<?> updateBudget(@PathVariable Long budgetId, @RequestBody BudgetRequestDTO request) { + Budget budget = budgetService.findBudgetById(budgetId); + budget.setBudgetName(request.getBudgetName()); + budget.setBudgetAmount(request.getBudgetAmount()); + budget.setExpenseAmount(request.getExpenseAmount()); + budgetService.updateBudget(budget); + log.info("[BudgetController:updateBudget] budget updated: {}", budget.getId()); + return ResponseEntity.ok().build(); + } - /** - * Deletes a budget. - * - * @param budgetId The budget's id. - * @return ResponseEntity. - */ - @Operation(summary = "Deletes a budget", description = "Deletes a budget based on provided budget id") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully deleted budget"), - @ApiResponse(responseCode = "500", description = "Budget is not found") - }) - @GetMapping(value = "/delete/{budgetId}", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<?> deleteBudget(@PathVariable long budgetId) { - budgetService.deleteBudgetById(budgetId); - log.info("[BudgetController:deleteBudget] budget deleted, id: {}", budgetId); - return ResponseEntity.ok().build(); - } + /** + * Deletes a budget. + * @param budgetId The budget's id. + * @return ResponseEntity. + */ + @Operation(summary = "Deletes a budget", description = "Deletes a budget based on provided budget id") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully deleted budget"), + @ApiResponse(responseCode = "500", description = "Budget is not found") }) + @GetMapping(value = "/delete/{budgetId}", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<?> deleteBudget(@PathVariable long budgetId) { + budgetService.deleteBudgetById(budgetId); + log.info("[BudgetController:deleteBudget] budget deleted, id: {}", budgetId); + return ResponseEntity.ok().build(); + } - /** - * Creates/Updates an expense. - * - * @param budgetId The budget id to the budget where the expense is stored. - * @return ResponseEntity. - */ - @Operation(summary = "Created/Updates an expense", description = "Creates/Updates a budget based on the budget request") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully updated budget"), - @ApiResponse(responseCode = "500", description = "Budget is not found"), - @ApiResponse(responseCode = "500", description = "Error updating expense") - }) - @PostMapping(value = "/update/expense/{budgetId}", produces = MediaType.APPLICATION_JSON_VALUE, - consumes = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<?> updateExpense(@PathVariable Long budgetId, @RequestBody ExpenseRequestDTO request) { - Budget budget = budgetService.findBudgetById(budgetId); - Expense expense = modelMapper.map(request, Expense.class); - expense.setBudget(budget); - budgetService.createExpense(expense); - log.info("[BudgetController:updateExpense] expense updated: {}", expense.getId()); - return ResponseEntity.ok(request); - } + /** + * Creates/Updates an expense. + * @param budgetId The budget id to the budget where the expense is stored. + * @return ResponseEntity. + */ + @Operation(summary = "Created/Updates an expense", + description = "Creates/Updates a budget based on the budget request") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully updated budget"), + @ApiResponse(responseCode = "500", description = "Budget is not found"), + @ApiResponse(responseCode = "500", description = "Error updating expense") }) + @PostMapping(value = "/update/expense/{budgetId}", produces = MediaType.APPLICATION_JSON_VALUE, + consumes = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<?> updateExpense(@PathVariable Long budgetId, @RequestBody ExpenseRequestDTO request) { + Budget budget = budgetService.findBudgetById(budgetId); + Expense expense = modelMapper.map(request, Expense.class); + expense.setBudget(budget); + budgetService.createExpense(expense); + log.info("[BudgetController:updateExpense] expense updated: {}", expense.getId()); + return ResponseEntity.ok(request); + } - /** - * Retrieves an expense by its id. - * - * @param expenseId The id of the expense to be retrieved. - * @return ResponseEntity containing the ExpenseResponseDTO. - */ - @Operation(summary = "Get the expense", description = "Get expense by its id ") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully got expense"), - @ApiResponse(responseCode = "500", description = "Expense is not found"), - }) - @GetMapping(value = "/expense/{expenseId}", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<ExpenseResponseDTO> getExpense(@PathVariable Long expenseId) { - Expense expense = budgetService.findExpenseById(expenseId); - ExpenseResponseDTO response = modelMapper.map(expense, ExpenseResponseDTO.class); - log.info("[BudgetController:getExpense] expense: {}", response.getExpenseId()); - return ResponseEntity.ok(response); - } + /** + * Retrieves an expense by its id. + * @param expenseId The id of the expense to be retrieved. + * @return ResponseEntity containing the ExpenseResponseDTO. + */ + @Operation(summary = "Get the expense", description = "Get expense by its id ") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully got expense"), + @ApiResponse(responseCode = "500", description = "Expense is not found"), }) + @GetMapping(value = "/expense/{expenseId}", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<ExpenseResponseDTO> getExpense(@PathVariable Long expenseId) { + Expense expense = budgetService.findExpenseById(expenseId); + ExpenseResponseDTO response = modelMapper.map(expense, ExpenseResponseDTO.class); + log.info("[BudgetController:getExpense] expense: {}", response.getExpenseId()); + return ResponseEntity.ok(response); + } - /** - * Retrieves all expenses belonging to a budget. - * - * @param budgetId The id of the budget where the expenses are stored. - * @return ResponseEntity containing the list of ExpenseResponseDTO of the budget. - */ - @Operation(summary = "Get the list of budgets", description = "Get all budgets related to " + - "the authenticated user") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully got expenses") - }) - @GetMapping(value = "/expenses/{budgetId}", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<List<ExpenseResponseDTO>> getExpenses(@PathVariable Long budgetId) { - List<Expense> expenses = budgetService.findExpensesByBudgetId(budgetId); - List<ExpenseResponseDTO> expenseDTOs = new ArrayList<>(); - log.info("[BudgetController:getExpenses] budget: {}", budgetId); - for (Expense expense : expenses) { - expenseDTOs.add(modelMapper.map(expense, ExpenseResponseDTO.class)); - log.info("[BudgetController:getExpenses] expense: {}", expense.getId()); - } - Collections.reverse(expenseDTOs); - return ResponseEntity.ok(expenseDTOs); - } + /** + * Retrieves all expenses belonging to a budget. + * @param budgetId The id of the budget where the expenses are stored. + * @return ResponseEntity containing the list of ExpenseResponseDTO of the budget. + */ + @Operation(summary = "Get the list of budgets", + description = "Get all budgets related to " + "the authenticated user") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully got expenses") }) + @GetMapping(value = "/expenses/{budgetId}", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<List<ExpenseResponseDTO>> getExpenses(@PathVariable Long budgetId) { + List<Expense> expenses = budgetService.findExpensesByBudgetId(budgetId); + List<ExpenseResponseDTO> expenseDTOs = new ArrayList<>(); + log.info("[BudgetController:getExpenses] budget: {}", budgetId); + for (Expense expense : expenses) { + expenseDTOs.add(modelMapper.map(expense, ExpenseResponseDTO.class)); + log.info("[BudgetController:getExpenses] expense: {}", expense.getId()); + } + Collections.reverse(expenseDTOs); + return ResponseEntity.ok(expenseDTOs); + } + + /** + * Deletes an expense. + * @param expenseId The expense's id. + * @return ResponseEntity. + */ + @Operation(summary = "Deletes an expense", description = "Deletes an expense based on provided expense id") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully deleted expense"), + @ApiResponse(responseCode = "500", description = "Expense is not found") }) + @GetMapping(value = "/delete/expense/{expenseId}", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<?> deleteExpense(@PathVariable Long expenseId) { + budgetService.deleteExpenseById(expenseId); + log.info("[BudgetController:deleteExpense] expense deleted, id: {}", expenseId); + return ResponseEntity.ok().build(); + } - /** - * Deletes an expense. - * - * @param expenseId The expense's id. - * @return ResponseEntity. - */ - @Operation(summary = "Deletes an expense", description = "Deletes an expense based on provided expense id") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully deleted expense"), - @ApiResponse(responseCode = "500", description = "Expense is not found") - }) - @GetMapping(value = "/delete/expense/{expenseId}", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<?> deleteExpense(@PathVariable Long expenseId) { - budgetService.deleteExpenseById(expenseId); - log.info("[BudgetController:deleteExpense] expense deleted, id: {}", expenseId); - return ResponseEntity.ok().build(); - } } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/controller/friend/FriendController.java b/src/main/java/no/ntnu/idi/stud/savingsapp/controller/friend/FriendController.java index c2f0c6ad77dd26b1ad80bf480dc5f485f5aeeea3..931da8329ec33aecf4e4a8e049c3db2229c19f1c 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/controller/friend/FriendController.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/controller/friend/FriendController.java @@ -42,115 +42,117 @@ import org.springframework.web.bind.annotation.RestController; @Slf4j public class FriendController { - private final UserService userService; - private final FriendService friendService; - private final NotificationService notificationService; - private final ModelMapper modelMapper; - - public FriendController(UserService userService, FriendService friendService, NotificationService notificationService, ModelMapper modelMapper) { - this.userService = userService; - this.friendService = friendService; - this.notificationService = notificationService; - this.modelMapper = modelMapper; - } - - @Operation(summary = "Get all friends", description = "Returns a list of all friends.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "Successfully retrieved list of friends") - }) - @GetMapping - public ResponseEntity<List<UserDTO>> getFriends(@AuthenticationPrincipal AuthIdentity identity) { - List<User> friendsUser = userService.getFriends(identity.getId()); - log.info("[FriendController:getFriends] user: {}", identity.getId()); - for (User user : friendsUser) { - log.info("[FriendController:getFriends] friend: {}", user.getId()); - } - return ResponseEntity.ok(convertToDto(friendsUser)); - } - - @Operation(summary = "Get friend requests", description = "Returns a list of all users who have sent a friend request.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "Successfully retrieved friend requests") - }) - @GetMapping("/requests") - public ResponseEntity<List<UserDTO>> getFriendRequests(@AuthenticationPrincipal AuthIdentity identity) { - List<User> friendsUser = userService.getFriendRequests(identity.getId()); - log.info("[FriendController:getFriendRequests] user: {}", identity.getId()); - for (User user : friendsUser) { - log.info("[FriendController:getFriendRequests] friend requests: {}", user.getId()); - } - return ResponseEntity.ok(convertToDto(friendsUser)); - } - - @Operation(summary = "Send a friend request", description = "Sends a new friend request to another user. A notification is sent to this user") - @ApiResponses({ - @ApiResponse(responseCode = "201", description = "Friend request successfully created") - }) - @PostMapping("/{userId}") - @ResponseStatus(HttpStatus.CREATED) - public void addFriendRequest(@AuthenticationPrincipal AuthIdentity identity, @PathVariable long userId) { - User user = userService.findById(identity.getId()); - User friend = userService.findById(userId); - friendService.addFriendRequest(user, friend); - Notification notification = new Notification(null, friend, "You have received a new friend request from " + user.getFirstName(), true, - NotificationType.FRIEND_REQUEST, Timestamp.from(Instant.now())); - notificationService.updateNotification(notification); - log.info("[FriendController:addFriendRequest] from: {} to: {}", user.getId(), friend.getId()); - } - - @Operation(summary = "Accept a friend request", description = "Accepts a friend request from another user.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "Friend request successfully accepted"), - @ApiResponse(responseCode = "404", description = "Friend request not found"), - }) - @PutMapping("/{friendId}") - public ResponseEntity<?> acceptFriendRequest(@AuthenticationPrincipal AuthIdentity identity, @PathVariable long friendId) { - User user = userService.findById(identity.getId()); - User friend = userService.findById(friendId); - Friend friendRequest = friendService.getFriendRequest(user, friend); - if (friendRequest == null) { - log.error("[FriendController:acceptFriendRequest] No friend request found"); - return ResponseEntity.status(HttpStatus.NOT_FOUND).body("No friend request found."); - } - friendService.acceptFriendRequest(friendRequest); - log.info("[FriendController:acceptFriendRequest] Friend request successfully accepted between: {} and: {}", user.getId(), friend.getId()); - return ResponseEntity.ok().build(); - } - - @Operation(summary = "Delete a friend or cancel a friend request", description = "Deletes an existing friend from your friend list or cancels a received friend request.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "Friend successfully deleted or friend request cancelled"), - @ApiResponse(responseCode = "404", description = "Friend or friend request not found"), - }) - @DeleteMapping("/{friendId}") - public ResponseEntity<?> deleteFriendOrFriendRequest(@AuthenticationPrincipal AuthIdentity identity, @PathVariable long friendId) { - User user = userService.findById(identity.getId()); - User friend = userService.findById(friendId); - - Friend friendStatus = friendService.getFriendStatus(user, friend); - if (friendStatus == null) { - log.error("[FriendController:deleteFriendOrFriendRequest] No friend relationship or friend request found"); - return ResponseEntity.status(HttpStatus.NOT_FOUND).body("No friend relationship or friend request found."); - } - - friendService.deleteFriendOrFriendRequest(friendStatus); - log.info("[FriendController:acceptFriendRequest] Friend request successfully deleted between: {} and: {}", user.getId(), friend.getId()); - return ResponseEntity.ok().build(); - } - - /** - * Converts a list of {@link User} objects to a list of - * {@link UserDTO} objects. - * - * @param users the list of users to convert - * @return The converted list of UserDTO objects - */ - private List<UserDTO> convertToDto(List<User> users) { - List<UserDTO> userDTOs = new ArrayList<>(); - for(User user : users) { - UserDTO userDTO = modelMapper.map(user, UserDTO.class); - userDTOs.add(userDTO); - } - return userDTOs; - } + private final UserService userService; + + private final FriendService friendService; + + private final NotificationService notificationService; + + private final ModelMapper modelMapper; + + public FriendController(UserService userService, FriendService friendService, + NotificationService notificationService, ModelMapper modelMapper) { + this.userService = userService; + this.friendService = friendService; + this.notificationService = notificationService; + this.modelMapper = modelMapper; + } + + @Operation(summary = "Get all friends", description = "Returns a list of all friends.") + @ApiResponses({ @ApiResponse(responseCode = "200", description = "Successfully retrieved list of friends") }) + @GetMapping + public ResponseEntity<List<UserDTO>> getFriends(@AuthenticationPrincipal AuthIdentity identity) { + List<User> friendsUser = userService.getFriends(identity.getId()); + log.info("[FriendController:getFriends] user: {}", identity.getId()); + for (User user : friendsUser) { + log.info("[FriendController:getFriends] friend: {}", user.getId()); + } + return ResponseEntity.ok(convertToDto(friendsUser)); + } + + @Operation(summary = "Get friend requests", + description = "Returns a list of all users who have sent a friend request.") + @ApiResponses({ @ApiResponse(responseCode = "200", description = "Successfully retrieved friend requests") }) + @GetMapping("/requests") + public ResponseEntity<List<UserDTO>> getFriendRequests(@AuthenticationPrincipal AuthIdentity identity) { + List<User> friendsUser = userService.getFriendRequests(identity.getId()); + log.info("[FriendController:getFriendRequests] user: {}", identity.getId()); + for (User user : friendsUser) { + log.info("[FriendController:getFriendRequests] friend requests: {}", user.getId()); + } + return ResponseEntity.ok(convertToDto(friendsUser)); + } + + @Operation(summary = "Send a friend request", + description = "Sends a new friend request to another user. A notification is sent to this user") + @ApiResponses({ @ApiResponse(responseCode = "201", description = "Friend request successfully created") }) + @PostMapping("/{userId}") + @ResponseStatus(HttpStatus.CREATED) + public void addFriendRequest(@AuthenticationPrincipal AuthIdentity identity, @PathVariable long userId) { + User user = userService.findById(identity.getId()); + User friend = userService.findById(userId); + friendService.addFriendRequest(user, friend); + Notification notification = new Notification(null, friend, + "You have received a new friend request from " + user.getFirstName(), true, + NotificationType.FRIEND_REQUEST, Timestamp.from(Instant.now())); + notificationService.updateNotification(notification); + log.info("[FriendController:addFriendRequest] from: {} to: {}", user.getId(), friend.getId()); + } + + @Operation(summary = "Accept a friend request", description = "Accepts a friend request from another user.") + @ApiResponses({ @ApiResponse(responseCode = "200", description = "Friend request successfully accepted"), + @ApiResponse(responseCode = "404", description = "Friend request not found"), }) + @PutMapping("/{friendId}") + public ResponseEntity<?> acceptFriendRequest(@AuthenticationPrincipal AuthIdentity identity, + @PathVariable long friendId) { + User user = userService.findById(identity.getId()); + User friend = userService.findById(friendId); + Friend friendRequest = friendService.getFriendRequest(user, friend); + if (friendRequest == null) { + log.error("[FriendController:acceptFriendRequest] No friend request found"); + return ResponseEntity.status(HttpStatus.NOT_FOUND).body("No friend request found."); + } + friendService.acceptFriendRequest(friendRequest); + log.info("[FriendController:acceptFriendRequest] Friend request successfully accepted between: {} and: {}", + user.getId(), friend.getId()); + return ResponseEntity.ok().build(); + } + + @Operation(summary = "Delete a friend or cancel a friend request", + description = "Deletes an existing friend from your friend list or cancels a received friend request.") + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "Friend successfully deleted or friend request cancelled"), + @ApiResponse(responseCode = "404", description = "Friend or friend request not found"), }) + @DeleteMapping("/{friendId}") + public ResponseEntity<?> deleteFriendOrFriendRequest(@AuthenticationPrincipal AuthIdentity identity, + @PathVariable long friendId) { + User user = userService.findById(identity.getId()); + User friend = userService.findById(friendId); + + Friend friendStatus = friendService.getFriendStatus(user, friend); + if (friendStatus == null) { + log.error("[FriendController:deleteFriendOrFriendRequest] No friend relationship or friend request found"); + return ResponseEntity.status(HttpStatus.NOT_FOUND).body("No friend relationship or friend request found."); + } + + friendService.deleteFriendOrFriendRequest(friendStatus); + log.info("[FriendController:acceptFriendRequest] Friend request successfully deleted between: {} and: {}", + user.getId(), friend.getId()); + return ResponseEntity.ok().build(); + } + + /** + * Converts a list of {@link User} objects to a list of {@link UserDTO} objects. + * @param users the list of users to convert + * @return The converted list of UserDTO objects + */ + private List<UserDTO> convertToDto(List<User> users) { + List<UserDTO> userDTOs = new ArrayList<>(); + for (User user : users) { + UserDTO userDTO = modelMapper.map(user, UserDTO.class); + userDTOs.add(userDTO); + } + return userDTOs; + } + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/controller/goal/GoalController.java b/src/main/java/no/ntnu/idi/stud/savingsapp/controller/goal/GoalController.java index 5490170fc90b5f61162cadb9da4e2e61713ca0c6..adf024ca8db243f130164596ffaf864494498c49 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/controller/goal/GoalController.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/controller/goal/GoalController.java @@ -36,125 +36,120 @@ import java.util.List; @Slf4j public class GoalController { - @Autowired - private GoalService goalService; + @Autowired + private GoalService goalService; - @Autowired - private ChallengeService challengeService; + @Autowired + private ChallengeService challengeService; - @Autowired - private ModelMapper modelMapper; + @Autowired + private ModelMapper modelMapper; - /** - * Creates a new goal based on the provided goal data. - * - * @param identity The security context of the authenticated user. - * @param request The data transfer object containing the details needed to create a goal. - * @return ResponseEntity containing the newly created GoalDTO and the HTTP status. - */ - @Operation(summary = "Create a goal", description = "Create a new goal") - @ApiResponses(value = { - @ApiResponse(responseCode = "201", description = "Successfully created a goal") - }) - @ResponseStatus(HttpStatus.CREATED) - @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<GoalDTO> createGoal(@AuthenticationPrincipal AuthIdentity identity, - @RequestBody CreateGoalDTO request) { - Goal createGoal = modelMapper.map(request, Goal.class); - Goal goal = goalService.createGoal(createGoal, request.getDistribution(), identity.getId()); - GoalDTO goalDTO = modelMapper.map(goal, GoalDTO.class); - log.info("[GoalController:createGoal] goal: {}", goalDTO.getId()); - return ResponseEntity.status(HttpStatus.CREATED).body(goalDTO); - } + /** + * Creates a new goal based on the provided goal data. + * @param identity The security context of the authenticated user. + * @param request The data transfer object containing the details needed to create a + * goal. + * @return ResponseEntity containing the newly created GoalDTO and the HTTP status. + */ + @Operation(summary = "Create a goal", description = "Create a new goal") + @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "Successfully created a goal") }) + @ResponseStatus(HttpStatus.CREATED) + @PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<GoalDTO> createGoal(@AuthenticationPrincipal AuthIdentity identity, + @RequestBody CreateGoalDTO request) { + Goal createGoal = modelMapper.map(request, Goal.class); + Goal goal = goalService.createGoal(createGoal, request.getDistribution(), identity.getId()); + GoalDTO goalDTO = modelMapper.map(goal, GoalDTO.class); + log.info("[GoalController:createGoal] goal: {}", goalDTO.getId()); + return ResponseEntity.status(HttpStatus.CREATED).body(goalDTO); + } - /** - * Retrieves all goals associated with the authenticated user. - * - * @param identity The security context of the authenticated user. - * @return ResponseEntity containing a list of GoalDTOs for the user's goals and the HTTP status. - */ - @Operation(summary = "Get goals", description = "Get the goals of the authenticated user") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully retrieved the goals") - }) - @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<List<GoalDTO>> getGoals(@AuthenticationPrincipal AuthIdentity identity) { - List<Goal> goals = goalService.getGoals(identity.getId()); - List<GoalDTO> goalsDTO = goals.stream().map(goal -> modelMapper.map(goal, GoalDTO.class)).toList(); - log.info("[GoalController:getGoals] user: {}", identity.getId()); - for(GoalDTO goalDTO : goalsDTO) { - log.info("[GoalController:getGoals] goal: {}", goalDTO.getId()); - } - return ResponseEntity.ok(goalsDTO); - } + /** + * Retrieves all goals associated with the authenticated user. + * @param identity The security context of the authenticated user. + * @return ResponseEntity containing a list of GoalDTOs for the user's goals and the + * HTTP status. + */ + @Operation(summary = "Get goals", description = "Get the goals of the authenticated user") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully retrieved the goals") }) + @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<List<GoalDTO>> getGoals(@AuthenticationPrincipal AuthIdentity identity) { + List<Goal> goals = goalService.getGoals(identity.getId()); + List<GoalDTO> goalsDTO = goals.stream().map(goal -> modelMapper.map(goal, GoalDTO.class)).toList(); + log.info("[GoalController:getGoals] user: {}", identity.getId()); + for (GoalDTO goalDTO : goalsDTO) { + log.info("[GoalController:getGoals] goal: {}", goalDTO.getId()); + } + return ResponseEntity.ok(goalsDTO); + } - /** - * Updates the progress of a specific challenge by marking a particular day as completed. - * This method allows users to record progress on challenges associated with their goals. - * - * @param identity The security context of the authenticated user, including user identification. - * @param request The data transfer object containing the challenge ID, the day to mark, and the amount saved. - * @return A ResponseEntity indicating the status of the operation. - * @apiNote This endpoint returns HTTP 202 (Accepted) on successful update, and may return HTTP 401 - * if the specified day is already marked as completed or is outside the allowed range. - * Error details are provided in the response body. - */ - @Operation(summary = "Update a challenge", description = "Update a challenge day as completed") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully updated the challenge"), - @ApiResponse(responseCode = "401", description = "Day is already completed or day outside of range", - content = @Content(schema = @Schema(implementation = ExceptionResponse.class))) - }) - @PostMapping(value = "/update-challenge", consumes = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<Void> updateChallenge(@AuthenticationPrincipal AuthIdentity identity, - @RequestBody MarkChallengeDTO request) { - challengeService.updateProgress(identity.getId(), request.getId(), - request.getDay(), request.getAmount()); - log.info("[GoalController:updateChallenge] challenge: {}", request.getId()); - return ResponseEntity.status(HttpStatus.ACCEPTED).build(); - } + /** + * Updates the progress of a specific challenge by marking a particular day as + * completed. This method allows users to record progress on challenges associated + * with their goals. + * @param identity The security context of the authenticated user, including user + * identification. + * @param request The data transfer object containing the challenge ID, the day to + * mark, and the amount saved. + * @return A ResponseEntity indicating the status of the operation. + * @apiNote This endpoint returns HTTP 202 (Accepted) on successful update, and may + * return HTTP 401 if the specified day is already marked as completed or is outside + * the allowed range. Error details are provided in the response body. + */ + @Operation(summary = "Update a challenge", description = "Update a challenge day as completed") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully updated the challenge"), + @ApiResponse(responseCode = "401", description = "Day is already completed or day outside of range", + content = @Content(schema = @Schema(implementation = ExceptionResponse.class))) }) + @PostMapping(value = "/update-challenge", consumes = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<Void> updateChallenge(@AuthenticationPrincipal AuthIdentity identity, + @RequestBody MarkChallengeDTO request) { + challengeService.updateProgress(identity.getId(), request.getId(), request.getDay(), request.getAmount()); + log.info("[GoalController:updateChallenge] challenge: {}", request.getId()); + return ResponseEntity.status(HttpStatus.ACCEPTED).build(); + } - /** - * Updates the saving amount for a specific challenge. This allows users to modify the potential - * savings target for any challenge associated with their goals. - * - * @param identity The security context of the authenticated user. - * @param request The data transfer object containing the challenge ID and the new saving amount. - * @return A ResponseEntity indicating the success of the update operation. - * @apiNote This endpoint returns HTTP 202 (Accepted) on a successful update of the challenge amount. - */ - @Operation(summary = "Update challenge saving amount", description = "Update the challenge saving amount") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully updated the challenge") - }) - @PostMapping(value = "/update-challenge-amount", consumes = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<Void> updateChallengeAmount(@AuthenticationPrincipal AuthIdentity identity, - @RequestBody MarkChallengeDTO request) { - challengeService.updateSavingAmount(identity.getId(), request.getId(), request.getAmount()); - log.info("[GoalController:updateChallengeAmount] challenge: {}", request.getId()); - return ResponseEntity.status(HttpStatus.ACCEPTED).build(); - } + /** + * Updates the saving amount for a specific challenge. This allows users to modify the + * potential savings target for any challenge associated with their goals. + * @param identity The security context of the authenticated user. + * @param request The data transfer object containing the challenge ID and the new + * saving amount. + * @return A ResponseEntity indicating the success of the update operation. + * @apiNote This endpoint returns HTTP 202 (Accepted) on a successful update of the + * challenge amount. + */ + @Operation(summary = "Update challenge saving amount", description = "Update the challenge saving amount") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully updated the challenge") }) + @PostMapping(value = "/update-challenge-amount", consumes = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<Void> updateChallengeAmount(@AuthenticationPrincipal AuthIdentity identity, + @RequestBody MarkChallengeDTO request) { + challengeService.updateSavingAmount(identity.getId(), request.getId(), request.getAmount()); + log.info("[GoalController:updateChallengeAmount] challenge: {}", request.getId()); + return ResponseEntity.status(HttpStatus.ACCEPTED).build(); + } - @GetMapping(value = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<GoalDTO> getGoal(@PathVariable Long id) { - Goal goal = goalService.getGoal(id); - GoalDTO goalDTO = modelMapper.map(goal, GoalDTO.class); - log.info("[GoalController:getGoal] goal: {}", goalDTO.getId()); - return ResponseEntity.ok(goalDTO); - } + @GetMapping(value = "/{id}", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<GoalDTO> getGoal(@PathVariable Long id) { + Goal goal = goalService.getGoal(id); + GoalDTO goalDTO = modelMapper.map(goal, GoalDTO.class); + log.info("[GoalController:getGoal] goal: {}", goalDTO.getId()); + return ResponseEntity.ok(goalDTO); + } - @PatchMapping(value = "/challenge/{id}", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<ChallengeDTO> regenerateChallenge(@AuthenticationPrincipal AuthIdentity identity, - @PathVariable Long id) { - Challenge challenge = challengeService.regenerateChallenge(identity.getId(), id); - ChallengeDTO challengeDTO = modelMapper.map(challenge, ChallengeDTO.class); - return ResponseEntity.ok(challengeDTO); - } + @PatchMapping(value = "/challenge/{id}", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<ChallengeDTO> regenerateChallenge(@AuthenticationPrincipal AuthIdentity identity, + @PathVariable Long id) { + Challenge challenge = challengeService.regenerateChallenge(identity.getId(), id); + ChallengeDTO challengeDTO = modelMapper.map(challenge, ChallengeDTO.class); + return ResponseEntity.ok(challengeDTO); + } + + @GetMapping(value = "/group/{goalId}", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<List<GoalDTO>> getGroupInfo(@PathVariable Long goalId) { + Group group = goalService.getGroup(goalId); + List<GoalDTO> goals = group.getGoals().stream().map(g -> modelMapper.map(g, GoalDTO.class)).toList(); + return ResponseEntity.ok(goals); + } - @GetMapping(value ="/group/{goalId}", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<List<GoalDTO>> getGroupInfo(@PathVariable Long goalId) { - Group group = goalService.getGroup(goalId); - List<GoalDTO> goals = group.getGoals().stream().map(g -> modelMapper.map(g, GoalDTO.class)).toList(); - return ResponseEntity.ok(goals); - } } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/controller/image/ImageController.java b/src/main/java/no/ntnu/idi/stud/savingsapp/controller/image/ImageController.java index 4d673777af4c902901d0e9aefd422f56a4df6485..b8843767195fb0f5406c39be83efc2b63cf62d82 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/controller/image/ImageController.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/controller/image/ImageController.java @@ -36,48 +36,43 @@ import java.io.IOException; @Slf4j public class ImageController { - @Autowired - private ImageService imageService; + @Autowired + private ImageService imageService; - /** - * Uploads an image to the server and stores it. - * The image data is extracted from a multipart file upload. - * - * @param file The MultipartFile object containing the image to be uploaded. - * @return ResponseEntity containing the unique ID of the stored image. - * @throws IOException If an error occurs while reading the file data. - */ - @Operation(summary = "Upload an image", description = "Upload an image to the server") - @ApiResponses(value = { - @ApiResponse(responseCode = "201", description = "Successfully uploaded the image") - }) - @ResponseStatus(HttpStatus.CREATED) - @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - public ResponseEntity<Long> uploadImage(@RequestParam("file") MultipartFile file) throws IOException { - byte[] imageBytes = file.getBytes(); - Image image = imageService.saveImage(file.getName(), imageBytes); - log.info("[ImageController:uploadImage] image name: {}", image.getName()); - return ResponseEntity.ok().body(image.getId()); - } + /** + * Uploads an image to the server and stores it. The image data is extracted from a + * multipart file upload. + * @param file The MultipartFile object containing the image to be uploaded. + * @return ResponseEntity containing the unique ID of the stored image. + * @throws IOException If an error occurs while reading the file data. + */ + @Operation(summary = "Upload an image", description = "Upload an image to the server") + @ApiResponses(value = { @ApiResponse(responseCode = "201", description = "Successfully uploaded the image") }) + @ResponseStatus(HttpStatus.CREATED) + @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public ResponseEntity<Long> uploadImage(@RequestParam("file") MultipartFile file) throws IOException { + byte[] imageBytes = file.getBytes(); + Image image = imageService.saveImage(file.getName(), imageBytes); + log.info("[ImageController:uploadImage] image name: {}", image.getName()); + return ResponseEntity.ok().body(image.getId()); + } + + /** + * Retrieves an image from the server based on its unique ID. Returns the image data + * as a byte array, suitable for direct display in web browsers or image views. + * @param id The unique identifier of the image to retrieve. + * @return ResponseEntity containing the raw image data as a byte array. + */ + @Operation(summary = "Retrieve an image", description = "Retrieve an image from the server") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully retrieved the image"), + @ApiResponse(responseCode = "404", description = "Image not found", + content = @Content(schema = @Schema(implementation = ExceptionResponse.class))) }) + @SecurityRequirements + @GetMapping(value = "/{id}") + public ResponseEntity<Resource> getImage(@PathVariable long id) { + Image image = imageService.getImage(id); + log.info("[ImageController:getImage] image id: {}", id); + return ResponseEntity.ok().body(new ByteArrayResource(image.getData())); + } - /** - * Retrieves an image from the server based on its unique ID. - * Returns the image data as a byte array, suitable for direct display in web browsers or image views. - * - * @param id The unique identifier of the image to retrieve. - * @return ResponseEntity containing the raw image data as a byte array. - */ - @Operation(summary = "Retrieve an image", description = "Retrieve an image from the server") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully retrieved the image"), - @ApiResponse(responseCode = "404", description = "Image not found", - content = @Content(schema = @Schema(implementation = ExceptionResponse.class))) - }) - @SecurityRequirements - @GetMapping(value = "/{id}") - public ResponseEntity<Resource> getImage(@PathVariable long id) { - Image image = imageService.getImage(id); - log.info("[ImageController:getImage] image id: {}", id); - return ResponseEntity.ok().body(new ByteArrayResource(image.getData())); - } } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/controller/item/ItemController.java b/src/main/java/no/ntnu/idi/stud/savingsapp/controller/item/ItemController.java index e742dc3fc4e6a6786c34d5d2d673a672b15f5fff..a75a60d45e77d4147b1abdb1229f9f958bba8176 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/controller/item/ItemController.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/controller/item/ItemController.java @@ -38,84 +38,86 @@ import org.springframework.web.bind.annotation.*; @Tag(name = "Item", description = "Endpoints for managing store and user inventory.") @Slf4j public class ItemController { - @Autowired - private ItemService itemService; - @Autowired - private UserService userService; + @Autowired + private ItemService itemService; - @Autowired - private ModelMapper modelMapper; + @Autowired + private UserService userService; - - @Operation(summary = "Get available store items", description = "Retrieves all items available in the store and a flag indicating whether the user has purchased each item.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "List of store items fetched successfully") - }) - @GetMapping("/store") - public ResponseEntity<List<ItemDTO>> getStore(@AuthenticationPrincipal AuthIdentity identity) { - List<Item> store = itemService.getStore(); - List<Item> inventory = itemService.getInventory(identity.getId()); - List<ItemDTO> storeDTO = new ArrayList<>(); - for(Item item : store) { - ItemDTO itemDTO = modelMapper.map(item, ItemDTO.class); - if(inventory.contains(item)) { - itemDTO.setAlreadyBought(true); - } - log.info("[ItemController:getStore] item: {}", itemDTO.getId()); - storeDTO.add(itemDTO); - } - return ResponseEntity.ok(storeDTO); - } + @Autowired + private ModelMapper modelMapper; - @Operation(summary = "Get the active user's inventory items", description = "Retrieves a list of all items currently in the inventory of the active user.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "List of inventory items fetched successfully") - }) - @GetMapping("/inventory") - public ResponseEntity<List<InventoryDTO>> getInventory(@AuthenticationPrincipal AuthIdentity identity) { - List<Item> inventory = itemService.getInventory(identity.getId()); - List<InventoryDTO> inventoryDTO = new ArrayList<>(); - for(Item item : inventory) { - inventoryDTO.add(modelMapper.map(item, InventoryDTO.class)); - log.info("[ItemController:getInventory] item: {}", item.getId()); - } - return ResponseEntity.ok(inventoryDTO); - } + @Operation(summary = "Get available store items", + description = "Retrieves all items available in the store and a flag indicating whether the user has purchased each item.") + @ApiResponses({ @ApiResponse(responseCode = "200", description = "List of store items fetched successfully") }) + @GetMapping("/store") + public ResponseEntity<List<ItemDTO>> getStore(@AuthenticationPrincipal AuthIdentity identity) { + List<Item> store = itemService.getStore(); + List<Item> inventory = itemService.getInventory(identity.getId()); + List<ItemDTO> storeDTO = new ArrayList<>(); + for (Item item : store) { + ItemDTO itemDTO = modelMapper.map(item, ItemDTO.class); + if (inventory.contains(item)) { + itemDTO.setAlreadyBought(true); + } + log.info("[ItemController:getStore] item: {}", itemDTO.getId()); + storeDTO.add(itemDTO); + } + return ResponseEntity.ok(storeDTO); + } - @Operation(summary = "Get user inventory items", description = "Retrieves a list of all items currently in the inventory of the user.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "List of inventory items fetched successfully") - }) - @GetMapping("/inventory/{userId}") - public ResponseEntity<List<InventoryDTO>> getInventoryByUserId(@PathVariable Long userId) { - List<Item> inventory = itemService.getInventory(userId); - List<InventoryDTO> inventoryDTO = new ArrayList<>(); - for(Item item : inventory) { - inventoryDTO.add(modelMapper.map(item, InventoryDTO.class)); - log.info("[ItemController:getInventoryByUserId] item: {}", item.getId()); - } - return ResponseEntity.ok(inventoryDTO); - } + @Operation(summary = "Get the active user's inventory items", + description = "Retrieves a list of all items currently in the inventory of the active user.") + @ApiResponses({ @ApiResponse(responseCode = "200", description = "List of inventory items fetched successfully") }) + @GetMapping("/inventory") + public ResponseEntity<List<InventoryDTO>> getInventory(@AuthenticationPrincipal AuthIdentity identity) { + List<Item> inventory = itemService.getInventory(identity.getId()); + List<InventoryDTO> inventoryDTO = new ArrayList<>(); + for (Item item : inventory) { + inventoryDTO.add(modelMapper.map(item, InventoryDTO.class)); + log.info("[ItemController:getInventory] item: {}", item.getId()); + } + return ResponseEntity.ok(inventoryDTO); + } - @Operation(summary = "Purchase an item", description = "Performs a purchase of the item by the user. Points will be deducted from the user.") - @ApiResponses({ - @ApiResponse(responseCode = "201", description = "Item purchased and added to inventory successfully", content = @Content(mediaType = "application/json")), - @ApiResponse(responseCode = "403", description = "Insufficient points to purchase the item", content = @Content(mediaType = "application/json", schema = @Schema(implementation = String.class))) - }) - @PostMapping("/{itemId}") - @ResponseStatus(HttpStatus.CREATED) - public ResponseEntity<String> buyItem(@AuthenticationPrincipal AuthIdentity identity, @PathVariable long itemId) { - Item item = itemService.getItemFromId(itemId); - User user = userService.findById(identity.getId()); - boolean purchaseSuccessful = itemService.addItem(user, item); + @Operation(summary = "Get user inventory items", + description = "Retrieves a list of all items currently in the inventory of the user.") + @ApiResponses({ @ApiResponse(responseCode = "200", description = "List of inventory items fetched successfully") }) + @GetMapping("/inventory/{userId}") + public ResponseEntity<List<InventoryDTO>> getInventoryByUserId(@PathVariable Long userId) { + List<Item> inventory = itemService.getInventory(userId); + List<InventoryDTO> inventoryDTO = new ArrayList<>(); + for (Item item : inventory) { + inventoryDTO.add(modelMapper.map(item, InventoryDTO.class)); + log.info("[ItemController:getInventoryByUserId] item: {}", item.getId()); + } + return ResponseEntity.ok(inventoryDTO); + } + + @Operation(summary = "Purchase an item", + description = "Performs a purchase of the item by the user. Points will be deducted from the user.") + @ApiResponses({ + @ApiResponse(responseCode = "201", description = "Item purchased and added to inventory successfully", + content = @Content(mediaType = "application/json")), + @ApiResponse(responseCode = "403", description = "Insufficient points to purchase the item", + content = @Content(mediaType = "application/json", + schema = @Schema(implementation = String.class))) }) + @PostMapping("/{itemId}") + @ResponseStatus(HttpStatus.CREATED) + public ResponseEntity<String> buyItem(@AuthenticationPrincipal AuthIdentity identity, @PathVariable long itemId) { + Item item = itemService.getItemFromId(itemId); + User user = userService.findById(identity.getId()); + boolean purchaseSuccessful = itemService.addItem(user, item); + + if (purchaseSuccessful) { + log.info("[ItemController:buyItem] item: {}, user: {}", item.getId(), user.getId()); + return ResponseEntity.status(HttpStatus.CREATED).build(); + } + else { + log.error("[ItemController:buyItem] Insufficient points to purchase the item"); + return ResponseEntity.status(HttpStatus.FORBIDDEN).body("Insufficient points to purchase the item"); + } + } - if (purchaseSuccessful) { - log.info("[ItemController:buyItem] item: {}, user: {}", item.getId(), user.getId()); - return ResponseEntity.status(HttpStatus.CREATED).build(); - } else { - log.error("[ItemController:buyItem] Insufficient points to purchase the item"); - return ResponseEntity.status(HttpStatus.FORBIDDEN).body("Insufficient points to purchase the item"); - } - } } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/controller/leaderboard/LeaderboardController.java b/src/main/java/no/ntnu/idi/stud/savingsapp/controller/leaderboard/LeaderboardController.java index 3547801e3f7d42219eb3487979570543ebd690a9..67285db9d0a7ac24c0b4d14e3c85caad0c5732ef 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/controller/leaderboard/LeaderboardController.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/controller/leaderboard/LeaderboardController.java @@ -34,78 +34,71 @@ import org.springframework.web.bind.annotation.RestController; @Slf4j public class LeaderboardController { - @Autowired - private LeaderboardService leaderboardService; + @Autowired + private LeaderboardService leaderboardService; - @Autowired - private ModelMapper modelMapper; + @Autowired + private ModelMapper modelMapper; - /** - * Retrieves the leaderboard entries based on the specified type, filter, and entry count. - * - * @param identity The authenticated user's identity. - * @param type The type of leaderboard. - * @param filter The filter for the leaderboard entries. - * @param entryCount The number of leaderboard entries to retrieve. - * @return ResponseEntity containing the leaderboard data. - */ - @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<LeaderboardDTO> getLeaderboard( - @AuthenticationPrincipal AuthIdentity identity, - @RequestParam @Enumerator(value = LeaderboardType.class, - message = "Invalid type") String type, - @RequestParam @Enumerator(value = LeaderboardFilter.class, - message = "Invalid filter") String filter, - @RequestParam(defaultValue = "10", required = false) int entryCount) { - Leaderboard leaderboard = leaderboardService.getTopUsers( - LeaderboardType.valueOf(type), LeaderboardFilter.valueOf(filter), entryCount, identity.getId()); - LeaderboardDTO leaderboardDTO = modelMapper.map(leaderboard, LeaderboardDTO.class); - log.info("[LeaderboardController:getLeaderboard] type: {}, filter: {}, count: {}", - type, filter, entryCount); - for(LeaderboardEntryDTO leaderboardEntryDTO : leaderboardDTO.getEntries()) { - log.info("[LeaderboardController:getLeaderboard] entry: {}, rank: {}, score: {}", - leaderboardEntryDTO.getUser().getId(), leaderboardEntryDTO.getRank(), leaderboardEntryDTO.getScore()); - } - return ResponseEntity.ok(leaderboardDTO); - } + /** + * Retrieves the leaderboard entries based on the specified type, filter, and entry + * count. + * @param identity The authenticated user's identity. + * @param type The type of leaderboard. + * @param filter The filter for the leaderboard entries. + * @param entryCount The number of leaderboard entries to retrieve. + * @return ResponseEntity containing the leaderboard data. + */ + @GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<LeaderboardDTO> getLeaderboard(@AuthenticationPrincipal AuthIdentity identity, + @RequestParam @Enumerator(value = LeaderboardType.class, message = "Invalid type") String type, + @RequestParam @Enumerator(value = LeaderboardFilter.class, message = "Invalid filter") String filter, + @RequestParam(defaultValue = "10", required = false) int entryCount) { + Leaderboard leaderboard = leaderboardService.getTopUsers(LeaderboardType.valueOf(type), + LeaderboardFilter.valueOf(filter), entryCount, identity.getId()); + LeaderboardDTO leaderboardDTO = modelMapper.map(leaderboard, LeaderboardDTO.class); + log.info("[LeaderboardController:getLeaderboard] type: {}, filter: {}, count: {}", type, filter, entryCount); + for (LeaderboardEntryDTO leaderboardEntryDTO : leaderboardDTO.getEntries()) { + log.info("[LeaderboardController:getLeaderboard] entry: {}, rank: {}, score: {}", + leaderboardEntryDTO.getUser().getId(), leaderboardEntryDTO.getRank(), + leaderboardEntryDTO.getScore()); + } + return ResponseEntity.ok(leaderboardDTO); + } - /** - * Retrieves the surrounding leaderboard entries for the authenticated user. - * - * @param identity The authenticated user's identity. - * @param type The type of leaderboard. - * @param filter The filter for the leaderboard entries. - * @param entryCount The number of leaderboard entries to retrieve. - * @return ResponseEntity containing the surrounding leaderboard entries. - */ - @GetMapping(value = "/surrounding", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<LeaderboardDTO> getSurrounding( - @AuthenticationPrincipal AuthIdentity identity, - @RequestParam @Enumerator(value = LeaderboardType.class, - message = "Invalid type") String type, - @RequestParam @Enumerator(value = LeaderboardFilter.class, - message = "Invalid filter") String filter, - @RequestParam(defaultValue = "10", required = false) int entryCount) { - Leaderboard leaderboard = leaderboardService.getSurrounding( - LeaderboardType.valueOf(type), LeaderboardFilter.valueOf(filter), entryCount, identity.getId()); - LeaderboardDTO leaderboardDTO = modelMapper.map(leaderboard, LeaderboardDTO.class); - log.info("[LeaderboardController:getLeaderboard] type: {}, filter: {}, count: {}", - type, filter, entryCount); - for(LeaderboardEntryDTO leaderboardEntryDTO : leaderboardDTO.getEntries()) { - log.info("[LeaderboardController:getLeaderboard] entry: {}, rank: {}, score: {}", - leaderboardEntryDTO.getUser().getId(), leaderboardEntryDTO.getRank(), leaderboardEntryDTO.getScore()); - } - return ResponseEntity.ok(leaderboardDTO); - } + /** + * Retrieves the surrounding leaderboard entries for the authenticated user. + * @param identity The authenticated user's identity. + * @param type The type of leaderboard. + * @param filter The filter for the leaderboard entries. + * @param entryCount The number of leaderboard entries to retrieve. + * @return ResponseEntity containing the surrounding leaderboard entries. + */ + @GetMapping(value = "/surrounding", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<LeaderboardDTO> getSurrounding(@AuthenticationPrincipal AuthIdentity identity, + @RequestParam @Enumerator(value = LeaderboardType.class, message = "Invalid type") String type, + @RequestParam @Enumerator(value = LeaderboardFilter.class, message = "Invalid filter") String filter, + @RequestParam(defaultValue = "10", required = false) int entryCount) { + Leaderboard leaderboard = leaderboardService.getSurrounding(LeaderboardType.valueOf(type), + LeaderboardFilter.valueOf(filter), entryCount, identity.getId()); + LeaderboardDTO leaderboardDTO = modelMapper.map(leaderboard, LeaderboardDTO.class); + log.info("[LeaderboardController:getLeaderboard] type: {}, filter: {}, count: {}", type, filter, entryCount); + for (LeaderboardEntryDTO leaderboardEntryDTO : leaderboardDTO.getEntries()) { + log.info("[LeaderboardController:getLeaderboard] entry: {}, rank: {}, score: {}", + leaderboardEntryDTO.getUser().getId(), leaderboardEntryDTO.getRank(), + leaderboardEntryDTO.getScore()); + } + return ResponseEntity.ok(leaderboardDTO); + } + + @Operation(summary = "Get sum of total points globally", + description = "Get the sum of the total points of all users globally") + @ApiResponses({ @ApiResponse(responseCode = "200", description = "Successfully retrieved total points") }) + @GetMapping(value = "/total-points", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<Long> getTotalPoints() { + long totalPoints = leaderboardService.getSumTotalEarnedPoints(); + log.info("[LeaderboardController:getTotalPoints] points: {}", totalPoints); + return ResponseEntity.ok(totalPoints); + } - @Operation(summary = "Get sum of total points globally", description = "Get the sum of the total points of all users globally") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "Successfully retrieved total points") - }) - @GetMapping(value = "/total-points", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<Long> getTotalPoints() { - long totalPoints = leaderboardService.getSumTotalEarnedPoints(); - log.info("[LeaderboardController:getTotalPoints] points: {}", totalPoints); - return ResponseEntity.ok(totalPoints); - } } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/controller/notification/NotificationController.java b/src/main/java/no/ntnu/idi/stud/savingsapp/controller/notification/NotificationController.java index 57b361ddc9bd1b41a71832013f2d72b6ef6d1ec8..c8bdf6aaf0103ebc5584585beefbbcb9ea6b970c 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/controller/notification/NotificationController.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/controller/notification/NotificationController.java @@ -39,99 +39,92 @@ import org.springframework.web.bind.annotation.RestController; @Slf4j public class NotificationController { - @Autowired - private NotificationService notificationService; + @Autowired + private NotificationService notificationService; - @Autowired - private UserService userService; + @Autowired + private UserService userService; - @Autowired - private ModelMapper modelMapper; + @Autowired + private ModelMapper modelMapper; - /** - * Retrieves a notification by its id. - * - * @param notificationId The id of the notification to retrieve. - * @return ResponseEntity containing the NotificationDTO. - */ - @Operation(summary = "Get the notification", description = "Get notification by its id ") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully got notification"), - @ApiResponse(responseCode = "500", description = "Notification is not found"), - }) - @GetMapping(value = "/{notificationId}", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<NotificationDTO> getNotification(@PathVariable long notificationId) { - Notification notification = notificationService.getNotificationById(notificationId); - NotificationDTO response = modelMapper.map(notification, NotificationDTO.class); - log.info("[NotificationController:getNotification] notification: {}", response.getId()); - return ResponseEntity.ok(response); - } + /** + * Retrieves a notification by its id. + * @param notificationId The id of the notification to retrieve. + * @return ResponseEntity containing the NotificationDTO. + */ + @Operation(summary = "Get the notification", description = "Get notification by its id ") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully got notification"), + @ApiResponse(responseCode = "500", description = "Notification is not found"), }) + @GetMapping(value = "/{notificationId}", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<NotificationDTO> getNotification(@PathVariable long notificationId) { + Notification notification = notificationService.getNotificationById(notificationId); + NotificationDTO response = modelMapper.map(notification, NotificationDTO.class); + log.info("[NotificationController:getNotification] notification: {}", response.getId()); + return ResponseEntity.ok(response); + } - /** - * Retrieves all the notifications belonging to a user. - * - * @param identity The security context of the authenticated user. - * @return ResponseEntity containing a list of NotificationResponseDTO. - */ - @Operation(summary = "Get the list of notifications", description = "Get all notifications " + - "to a user") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully got notifications") - }) - @GetMapping(value = "", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<List<NotificationDTO>> getNotificationByUser(@AuthenticationPrincipal AuthIdentity identity) { - List<Notification> notifications = notificationService.getNotificationsByUserId(identity.getId()); - List<NotificationDTO> notificationDTOs = notifications.stream().map(notification -> modelMapper.map(notification, NotificationDTO.class)).toList(); - for (NotificationDTO notificationDTO : notificationDTOs) { - log.info("[NotificationController:getNotificationByUser] notification: {}", notificationDTO.getId()); - } - return ResponseEntity.ok(notificationDTOs); - } + /** + * Retrieves all the notifications belonging to a user. + * @param identity The security context of the authenticated user. + * @return ResponseEntity containing a list of NotificationResponseDTO. + */ + @Operation(summary = "Get the list of notifications", description = "Get all notifications " + "to a user") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully got notifications") }) + @GetMapping(value = "", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<List<NotificationDTO>> getNotificationByUser(@AuthenticationPrincipal AuthIdentity identity) { + List<Notification> notifications = notificationService.getNotificationsByUserId(identity.getId()); + List<NotificationDTO> notificationDTOs = notifications.stream() + .map(notification -> modelMapper.map(notification, NotificationDTO.class)) + .toList(); + for (NotificationDTO notificationDTO : notificationDTOs) { + log.info("[NotificationController:getNotificationByUser] notification: {}", notificationDTO.getId()); + } + return ResponseEntity.ok(notificationDTOs); + } - /** - * Retrieves all the unread notifications to a user. - * - * @param identity The security context of the authenticated user. - * @return ResponseEntity containing a list of NotificationResponseDTO. - */ - @Operation(summary = "Get the list of unread notifications", description = "Get all unread notifications " + - "to a user") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully got notifications") - }) - @GetMapping(value = "/unread", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<List<NotificationDTO>> getUnreadNotificationByUser(@AuthenticationPrincipal AuthIdentity identity) { - List<Notification> notifications = notificationService.getUnreadNotificationsByUserId(identity.getId()); - List<NotificationDTO> notificationsDTOs = notifications.stream().map(notification -> modelMapper.map(notification, NotificationDTO.class)).toList(); - for(NotificationDTO notificationDTO : notificationsDTOs) { - log.info("[NotificationController:getUnreadNotificationByUser] notification: {}", notificationDTO.getId()); - } - return ResponseEntity.ok(notificationsDTOs); - } + /** + * Retrieves all the unread notifications to a user. + * @param identity The security context of the authenticated user. + * @return ResponseEntity containing a list of NotificationResponseDTO. + */ + @Operation(summary = "Get the list of unread notifications", + description = "Get all unread notifications " + "to a user") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully got notifications") }) + @GetMapping(value = "/unread", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<List<NotificationDTO>> getUnreadNotificationByUser( + @AuthenticationPrincipal AuthIdentity identity) { + List<Notification> notifications = notificationService.getUnreadNotificationsByUserId(identity.getId()); + List<NotificationDTO> notificationsDTOs = notifications.stream() + .map(notification -> modelMapper.map(notification, NotificationDTO.class)) + .toList(); + for (NotificationDTO notificationDTO : notificationsDTOs) { + log.info("[NotificationController:getUnreadNotificationByUser] notification: {}", notificationDTO.getId()); + } + return ResponseEntity.ok(notificationsDTOs); + } + + /** + * Updates a notification. + * @param identity The security context of the authenticated user. + * @param request The notification request. + * @return ResponseEntity. + */ + @Operation(summary = "Updates a notification", description = "Updates a notification based on the request") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully updated notification"), + @ApiResponse(responseCode = "500", description = "User is not found") }) + @PostMapping(value = "/update", consumes = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<?> updateNotification(@AuthenticationPrincipal AuthIdentity identity, + @RequestBody NotificationDTO request) { + Notification notification = modelMapper.map(request, Notification.class); + if (notification.getCreatedAt() == null) { + notification.setCreatedAt(Timestamp.from(Instant.now())); + } + User user = userService.findById(identity.getId()); + notification.setUser(user); + notificationService.updateNotification(notification); + log.info("[NotificationController:updateNotification] updated notification: {}", request.getId()); + return ResponseEntity.ok().build(); + } - /** - * Updates a notification. - * - * @param identity The security context of the authenticated user. - * @param request The notification request. - * @return ResponseEntity. - */ - @Operation(summary = "Updates a notification", description = "Updates a notification based on the request") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully updated notification"), - @ApiResponse(responseCode = "500", description = "User is not found") - }) - @PostMapping(value = "/update", consumes = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<?> updateNotification(@AuthenticationPrincipal AuthIdentity identity, - @RequestBody NotificationDTO request) { - Notification notification = modelMapper.map(request, Notification.class); - if (notification.getCreatedAt() == null) { - notification.setCreatedAt(Timestamp.from(Instant.now())); - } - User user = userService.findById(identity.getId()); - notification.setUser(user); - notificationService.updateNotification(notification); - log.info("[NotificationController:updateNotification] updated notification: {}", request.getId()); - return ResponseEntity.ok().build(); - } } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/controller/redirect/RedirectController.java b/src/main/java/no/ntnu/idi/stud/savingsapp/controller/redirect/RedirectController.java index 17a2e54ee719c5caca1752539f252b2b99390755..f06daf582f38c197d8bef3b48bb80702f6f4c69b 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/controller/redirect/RedirectController.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/controller/redirect/RedirectController.java @@ -10,7 +10,8 @@ import org.springframework.web.bind.annotation.*; import java.io.IOException; /** - * Controller for managing HTTP redirects, especially useful for handling callback responses from authentication services. + * Controller for managing HTTP redirects, especially useful for handling callback + * responses from authentication services. */ @RestController @RequestMapping @@ -18,31 +19,34 @@ import java.io.IOException; @Tag(name = "Redirect") public class RedirectController { - /** - * Handles the callback from an OAuth service or similar by redirecting to the appropriate local URL - * with the required parameters. - * - * @param state The state parameter received from the OAuth service, used to maintain state between the request and callback. - * @param request The HTTP request containing all the necessary parameters from the callback. - * @param response The HTTP response to manage redirection. - * - * @throws RuntimeException if an IOException occurs during URL redirection. - */ - @GetMapping("/redirect") - @ResponseBody - private void consumeCallback(@RequestParam(value="state") String state, - HttpServletRequest request, HttpServletResponse response) { - if (request.getParameterMap().containsKey("code")) { - String code = request.getParameterMap().get("code")[0]; - response.setHeader("Location", SparestiApplication.getFrontendURL() + "/redirect?code=" + code + "&state=" + state); - response.setStatus(302); - return; - } - // Default redirection if "code" parameter is missing - try { - response.sendRedirect(SparestiApplication.getFrontendURL() + "/login"); - } catch (IOException e) { - throw new RuntimeException(e); - } - } + /** + * Handles the callback from an OAuth service or similar by redirecting to the + * appropriate local URL with the required parameters. + * @param state The state parameter received from the OAuth service, used to maintain + * state between the request and callback. + * @param request The HTTP request containing all the necessary parameters from the + * callback. + * @param response The HTTP response to manage redirection. + * @throws RuntimeException if an IOException occurs during URL redirection. + */ + @GetMapping("/redirect") + @ResponseBody + private void consumeCallback(@RequestParam(value = "state") String state, HttpServletRequest request, + HttpServletResponse response) { + if (request.getParameterMap().containsKey("code")) { + String code = request.getParameterMap().get("code")[0]; + response.setHeader("Location", + SparestiApplication.getFrontendURL() + "/redirect?code=" + code + "&state=" + state); + response.setStatus(302); + return; + } + // Default redirection if "code" parameter is missing + try { + response.sendRedirect(SparestiApplication.getFrontendURL() + "/login"); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/controller/user/UserController.java b/src/main/java/no/ntnu/idi/stud/savingsapp/controller/user/UserController.java index 46b709d10cdc8bafcd66f651d7854910477cccb5..a45ae8c7548d5ee22db0e1e710cfbcf45c865c7b 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/controller/user/UserController.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/controller/user/UserController.java @@ -33,6 +33,7 @@ import org.springframework.web.bind.annotation.*; import java.util.List; import java.util.ArrayList; + /** * Controller handling user related requests. */ @@ -45,270 +46,252 @@ import java.util.ArrayList; @Slf4j public class UserController { - @Autowired - private UserService userService; + @Autowired + private UserService userService; - @Autowired - private ModelMapper modelMapper; + @Autowired + private ModelMapper modelMapper; - /** - * Retrieves the authenticated user's data. - * - * @param identity The security context of the authenticated user. - * @return ResponseEntity containing the UserDTO of the authenticated user. - * @apiNote This endpoint is used to fetch all user information for the authenticated user. - * It uses the user's ID stored in the authentication principal to fetch the data. - */ - @Operation(summary = "Get the authenticated user", description = "Get all user information for " + - "the authenticated user") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully got user") - }) - @GetMapping(value = "/me", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<UserDTO> getUser(@AuthenticationPrincipal AuthIdentity identity) { - User user = userService.findById(identity.getId()); - UserDTO userDTO = modelMapper.map(user, UserDTO.class); - log.info("[UserController:getUser] user: {}", userDTO.getId()); - return ResponseEntity.ok(userDTO); - } + /** + * Retrieves the authenticated user's data. + * @param identity The security context of the authenticated user. + * @return ResponseEntity containing the UserDTO of the authenticated user. + * @apiNote This endpoint is used to fetch all user information for the authenticated + * user. It uses the user's ID stored in the authentication principal to fetch the + * data. + */ + @Operation(summary = "Get the authenticated user", + description = "Get all user information for " + "the authenticated user") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully got user") }) + @GetMapping(value = "/me", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<UserDTO> getUser(@AuthenticationPrincipal AuthIdentity identity) { + User user = userService.findById(identity.getId()); + UserDTO userDTO = modelMapper.map(user, UserDTO.class); + log.info("[UserController:getUser] user: {}", userDTO.getId()); + return ResponseEntity.ok(userDTO); + } - /** - * Retrieves the profile of a specific user by their unique identifier. - * - * @param userId The unique identifier of the user whose profile is to be retrieved. - * @return ResponseEntity containing the ProfileDTO of the requested user. - * @apiNote This endpoint fetches the profile of any user given their user ID. - * It is intended for public access where any authenticated user can view others' profiles. - */ - @Operation(summary = "Get a profile", description = "Get the profile of a user") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully got profile") - }) - @GetMapping(value = "/{userId}/profile", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<ProfileDTO> getProfile(@PathVariable long userId) { - User user = userService.findById(userId); - ProfileDTO profileDTO = modelMapper.map(user, ProfileDTO.class); - log.info("[UserController:getProfile] profile: {}", profileDTO.getId()); - return ResponseEntity.ok(profileDTO); - } + /** + * Retrieves the profile of a specific user by their unique identifier. + * @param userId The unique identifier of the user whose profile is to be retrieved. + * @return ResponseEntity containing the ProfileDTO of the requested user. + * @apiNote This endpoint fetches the profile of any user given their user ID. It is + * intended for public access where any authenticated user can view others' profiles. + */ + @Operation(summary = "Get a profile", description = "Get the profile of a user") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully got profile") }) + @GetMapping(value = "/{userId}/profile", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<ProfileDTO> getProfile(@PathVariable long userId) { + User user = userService.findById(userId); + ProfileDTO profileDTO = modelMapper.map(user, ProfileDTO.class); + log.info("[UserController:getProfile] profile: {}", profileDTO.getId()); + return ResponseEntity.ok(profileDTO); + } - /** - * Updates the profile of the authenticated user based on the provided data. - * - * @param identity The security context of the authenticated user. - * @param updateDTO The data transfer object containing the fields that need to be updated. - * @return ResponseEntity containing the updated UserDTO. - * @apiNote This endpoint allows the authenticated user to update their own profile. - * It only updates fields that are provided in the request body. - */ - @Operation(summary = "Update a profile", description = "Update the profile of the authenticated user") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully updated profile") - }) - @PatchMapping(produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<UserDTO> update(@AuthenticationPrincipal AuthIdentity identity, - @RequestBody @Valid UserUpdateDTO updateDTO) { - User user = userService.findById(identity.getId()); - if (updateDTO.getFirstName() != null) { - user.setFirstName(updateDTO.getFirstName()); - } - if (updateDTO.getLastName() != null) { - user.setLastName(updateDTO.getLastName()); - } - if (updateDTO.getEmail() != null) { - user.setEmail(updateDTO.getEmail()); - } - if (updateDTO.getEmail() != null) { - user.setEmail(updateDTO.getEmail()); - } - if (updateDTO.getProfileImage() != null) { - user.setProfileImage(updateDTO.getProfileImage()); - } - if(updateDTO.getBannerImage() != null) { - user.setBannerImage(updateDTO.getBannerImage()); - } - if(updateDTO.getCheckingAccountBBAN() != null) { - user.setCheckingAccountBBAN(updateDTO.getCheckingAccountBBAN()); - } - if (updateDTO.getSavingsAccountBBAN() != null) { - user.setSavingsAccountBBAN(updateDTO.getSavingsAccountBBAN()); - } - if (updateDTO.getConfiguration() != null) { - if (updateDTO.getConfiguration().getCommitment() != null) { - user.getConfiguration().setCommitment(Commitment.valueOf(updateDTO.getConfiguration().getCommitment())); - } - if (updateDTO.getConfiguration().getExperience() != null) { - user.getConfiguration().setExperience(Experience.valueOf(updateDTO.getConfiguration().getExperience())); - } - if (updateDTO.getConfiguration().getChallengeTypes() != null) { - for (String challengeType : updateDTO.getConfiguration().getChallengeTypes()) { - user.getConfiguration().getChallengeTypes().add(ChallengeType.valueOf(challengeType)); - } - } - } - User updatedUser = userService.update(user); - UserDTO userDTO = modelMapper.map(updatedUser, UserDTO.class); - log.info("[UserController:update] updated user id: {}", identity.getId()); - return ResponseEntity.ok(userDTO); - } + /** + * Updates the profile of the authenticated user based on the provided data. + * @param identity The security context of the authenticated user. + * @param updateDTO The data transfer object containing the fields that need to be + * updated. + * @return ResponseEntity containing the updated UserDTO. + * @apiNote This endpoint allows the authenticated user to update their own profile. + * It only updates fields that are provided in the request body. + */ + @Operation(summary = "Update a profile", description = "Update the profile of the authenticated user") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully updated profile") }) + @PatchMapping(produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<UserDTO> update(@AuthenticationPrincipal AuthIdentity identity, + @RequestBody @Valid UserUpdateDTO updateDTO) { + User user = userService.findById(identity.getId()); + if (updateDTO.getFirstName() != null) { + user.setFirstName(updateDTO.getFirstName()); + } + if (updateDTO.getLastName() != null) { + user.setLastName(updateDTO.getLastName()); + } + if (updateDTO.getEmail() != null) { + user.setEmail(updateDTO.getEmail()); + } + if (updateDTO.getEmail() != null) { + user.setEmail(updateDTO.getEmail()); + } + if (updateDTO.getProfileImage() != null) { + user.setProfileImage(updateDTO.getProfileImage()); + } + if (updateDTO.getBannerImage() != null) { + user.setBannerImage(updateDTO.getBannerImage()); + } + if (updateDTO.getCheckingAccountBBAN() != null) { + user.setCheckingAccountBBAN(updateDTO.getCheckingAccountBBAN()); + } + if (updateDTO.getSavingsAccountBBAN() != null) { + user.setSavingsAccountBBAN(updateDTO.getSavingsAccountBBAN()); + } + if (updateDTO.getConfiguration() != null) { + if (updateDTO.getConfiguration().getCommitment() != null) { + user.getConfiguration().setCommitment(Commitment.valueOf(updateDTO.getConfiguration().getCommitment())); + } + if (updateDTO.getConfiguration().getExperience() != null) { + user.getConfiguration().setExperience(Experience.valueOf(updateDTO.getConfiguration().getExperience())); + } + if (updateDTO.getConfiguration().getChallengeTypes() != null) { + for (String challengeType : updateDTO.getConfiguration().getChallengeTypes()) { + user.getConfiguration().getChallengeTypes().add(ChallengeType.valueOf(challengeType)); + } + } + } + User updatedUser = userService.update(user); + UserDTO userDTO = modelMapper.map(updatedUser, UserDTO.class); + log.info("[UserController:update] updated user id: {}", identity.getId()); + return ResponseEntity.ok(userDTO); + } - @Operation(summary = "Delete the authenticated user", description = "Delete the authenticated user") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully deleted user") - }) - @DeleteMapping(value = "/me", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<Void> deleteUser(@AuthenticationPrincipal AuthIdentity identity) { - userService.delete(identity.getId()); - log.info("[UserController:deleteUser] user: {}", identity.getId()); - return ResponseEntity.ok().build(); - } + @Operation(summary = "Delete the authenticated user", description = "Delete the authenticated user") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully deleted user") }) + @DeleteMapping(value = "/me", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<Void> deleteUser(@AuthenticationPrincipal AuthIdentity identity) { + userService.delete(identity.getId()); + log.info("[UserController:deleteUser] user: {}", identity.getId()); + return ResponseEntity.ok().build(); + } - @Operation(summary = "Update a password", description = "Update the password of the authenticated user") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Successfully updated password") - }) - @PatchMapping(value = "/password", consumes = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity<UserDTO> updatePassword(@AuthenticationPrincipal AuthIdentity identity, - @RequestBody @Valid PasswordUpdateDTO updateDTO) { - User user = userService.updatePassword(identity.getId(), updateDTO.getOldPassword(), updateDTO.getNewPassword()); - UserDTO userDTO = modelMapper.map(user, UserDTO.class); - log.info("[UserController:updatedPassword] user id: {}", identity.getId()); - return ResponseEntity.ok(userDTO); - } + @Operation(summary = "Update a password", description = "Update the password of the authenticated user") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Successfully updated password") }) + @PatchMapping(value = "/password", consumes = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity<UserDTO> updatePassword(@AuthenticationPrincipal AuthIdentity identity, + @RequestBody @Valid PasswordUpdateDTO updateDTO) { + User user = userService.updatePassword(identity.getId(), updateDTO.getOldPassword(), + updateDTO.getNewPassword()); + UserDTO userDTO = modelMapper.map(user, UserDTO.class); + log.info("[UserController:updatedPassword] user id: {}", identity.getId()); + return ResponseEntity.ok(userDTO); + } - /** - * Initiates a password reset process by sending a reset email to the user with the provided email. - * This endpoint is called when a user requests a password reset. It triggers an email with reset instructions. - * - * @param email The email address of the user requesting a password reset, which must be a valid email format. - * @throws IllegalArgumentException if the email address does not meet the email format validation. - */ - @Operation(summary = "Initiate a password reset", description = "Send a password reset mail " + - "to the user with the specified email") - @ApiResponses(value = { - @ApiResponse(responseCode = "202", description = "Successfully initiated a password reset") - }) - @SecurityRequirements - @PostMapping(value = "/reset-password", consumes = MediaType.TEXT_PLAIN_VALUE) - @ResponseStatus(value = HttpStatus.ACCEPTED) - public void resetPassword(@RequestBody @Email(message = "Invalid email") String email) { - userService.initiatePasswordReset(email); - log.info("[UserController:resetPassword] initiated password reset, email: {}", email); - } + /** + * Initiates a password reset process by sending a reset email to the user with the + * provided email. This endpoint is called when a user requests a password reset. It + * triggers an email with reset instructions. + * @param email The email address of the user requesting a password reset, which must + * be a valid email format. + * @throws IllegalArgumentException if the email address does not meet the email + * format validation. + */ + @Operation(summary = "Initiate a password reset", + description = "Send a password reset mail " + "to the user with the specified email") + @ApiResponses( + value = { @ApiResponse(responseCode = "202", description = "Successfully initiated a password reset") }) + @SecurityRequirements + @PostMapping(value = "/reset-password", consumes = MediaType.TEXT_PLAIN_VALUE) + @ResponseStatus(value = HttpStatus.ACCEPTED) + public void resetPassword(@RequestBody @Email(message = "Invalid email") String email) { + userService.initiatePasswordReset(email); + log.info("[UserController:resetPassword] initiated password reset, email: {}", email); + } - /** - * Confirms a password reset using a provided token and a new password. - * This endpoint is called to finalize the password reset process. It uses the token sent to the user's email - * and a new password specified by the user to complete the password reset. - * - * @param resetDTO The PasswordResetDTO containing the reset token and the new password which must be valid. - * @throws jakarta.validation.ValidationException if the resetDTO does not pass validation checks. - */ - @Operation(summary = "Confirm a password reset", description = "Confirms a password reset " + - "using a token and a new password") - @ApiResponses(value = { - @ApiResponse(responseCode = "204", description = "Password was reset successfully"), - @ApiResponse(responseCode = "403", description = "Invalid token") - }) - @SecurityRequirements - @PostMapping(value = "/confirm-password") - @ResponseStatus(value = HttpStatus.NO_CONTENT) - public void confirmPasswordReset(@RequestBody @Valid PasswordResetDTO resetDTO) { - userService.confirmPasswordReset(resetDTO.getToken(), resetDTO.getPassword()); - log.info("[UserController:confirmPasswordReset] initiated password reset, token: {}", resetDTO.getToken()); - } + /** + * Confirms a password reset using a provided token and a new password. This endpoint + * is called to finalize the password reset process. It uses the token sent to the + * user's email and a new password specified by the user to complete the password + * reset. + * @param resetDTO The PasswordResetDTO containing the reset token and the new + * password which must be valid. + * @throws jakarta.validation.ValidationException if the resetDTO does not pass + * validation checks. + */ + @Operation(summary = "Confirm a password reset", + description = "Confirms a password reset " + "using a token and a new password") + @ApiResponses(value = { @ApiResponse(responseCode = "204", description = "Password was reset successfully"), + @ApiResponse(responseCode = "403", description = "Invalid token") }) + @SecurityRequirements + @PostMapping(value = "/confirm-password") + @ResponseStatus(value = HttpStatus.NO_CONTENT) + public void confirmPasswordReset(@RequestBody @Valid PasswordResetDTO resetDTO) { + userService.confirmPasswordReset(resetDTO.getToken(), resetDTO.getPassword()); + log.info("[UserController:confirmPasswordReset] initiated password reset, token: {}", resetDTO.getToken()); + } - @Operation(summary = "Search for users by name and filter", description = "Returns a list of users whose names contain the specified search term and match the filter.") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "Successfully retrieved list of users") - }) - @GetMapping("/search/{searchTerm}/{filter}") - public ResponseEntity<List<UserDTO>> getUsersByNameAndFilter( - @AuthenticationPrincipal AuthIdentity identity, - @PathVariable String searchTerm, - @PathVariable @Enumerator(value = SearchFilter.class, - message = "Invalid filter") String filter) { - log.info("[UserController:getUsersByNameAndFilter] searchTerm: {}, filter: {}", searchTerm, filter); - List<User> users = userService.getUsersByNameAndFilter(identity.getId(), searchTerm, SearchFilter.valueOf(filter)); - List<UserDTO> userDTOs = new ArrayList<>(); - for(User user : users) { - UserDTO userDTO = modelMapper.map(user, UserDTO.class); - userDTOs.add(userDTO); - log.info("[UserController:getUsersByNameAndFilter] user: {}", userDTO.getId()); - } - return ResponseEntity.ok(userDTOs); - } + @Operation(summary = "Search for users by name and filter", + description = "Returns a list of users whose names contain the specified search term and match the filter.") + @ApiResponses({ @ApiResponse(responseCode = "200", description = "Successfully retrieved list of users") }) + @GetMapping("/search/{searchTerm}/{filter}") + public ResponseEntity<List<UserDTO>> getUsersByNameAndFilter(@AuthenticationPrincipal AuthIdentity identity, + @PathVariable String searchTerm, + @PathVariable @Enumerator(value = SearchFilter.class, message = "Invalid filter") String filter) { + log.info("[UserController:getUsersByNameAndFilter] searchTerm: {}, filter: {}", searchTerm, filter); + List<User> users = userService.getUsersByNameAndFilter(identity.getId(), searchTerm, + SearchFilter.valueOf(filter)); + List<UserDTO> userDTOs = new ArrayList<>(); + for (User user : users) { + UserDTO userDTO = modelMapper.map(user, UserDTO.class); + userDTOs.add(userDTO); + log.info("[UserController:getUsersByNameAndFilter] user: {}", userDTO.getId()); + } + return ResponseEntity.ok(userDTOs); + } - /** - * Sends feedback from an email. - */ - @Operation(summary = "Send feedback", description = "Send feedback from an email.") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Success") - }) - @PostMapping("/send-feedback") - public ResponseEntity<Void> sendFeedback(@Validated @RequestBody FeedbackRequestDTO feedbackRequestDTO) { - userService.sendFeedback(feedbackRequestDTO.getEmail(), feedbackRequestDTO.getMessage()); - log.info("[UserController:sendFeedback] feedback: {}", feedbackRequestDTO.getMessage()); - return ResponseEntity.ok().build(); - } + /** + * Sends feedback from an email. + */ + @Operation(summary = "Send feedback", description = "Send feedback from an email.") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Success") }) + @PostMapping("/send-feedback") + public ResponseEntity<Void> sendFeedback(@Validated @RequestBody FeedbackRequestDTO feedbackRequestDTO) { + userService.sendFeedback(feedbackRequestDTO.getEmail(), feedbackRequestDTO.getMessage()); + log.info("[UserController:sendFeedback] feedback: {}", feedbackRequestDTO.getMessage()); + return ResponseEntity.ok().build(); + } - /** - * Get all feedback. - * - * @param identity The authenticated user's identity. - * @return A list containing all feedback. - */ - @Operation(summary = "Send feedback", description = "Send feedback from a user.") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Success") - }) - @GetMapping("/get-feedback") - public ResponseEntity<List<FeedbackResponseDTO>> getFeedback(@AuthenticationPrincipal AuthIdentity identity) { - if (!identity.getRole().equalsIgnoreCase("ADMIN")) { - log.error("[UserController:getFeedback] Permission denied, user role: {}", identity.getRole()); - throw new PermissionDeniedException(); - } - List<Feedback> feedbacks = userService.getFeedback(); - List<FeedbackResponseDTO> feedbackResponseDTOS = feedbacks.stream().map(quiz -> modelMapper.map(quiz, FeedbackResponseDTO.class)).toList(); - for(FeedbackResponseDTO feedbackResponseDTO : feedbackResponseDTOS) { - log.info("[UserController:getFeedback] feedback: {}", feedbackResponseDTO.getId()); - } - return ResponseEntity.ok(feedbackResponseDTOS); - } - - @Operation(summary = "Get X amount of random users", description = "Get X amount of random users that fit the filter") - @ApiResponses({ - @ApiResponse(responseCode = "200", description = "Successfully retrieved list of users"), - }) - @GetMapping("/search/random/{amount}/{filter}") - public ResponseEntity<List<UserDTO>> getRandomUsers( - @AuthenticationPrincipal AuthIdentity identity, - @PathVariable int amount, - @PathVariable @Enumerator(value = SearchFilter.class, - message = "Invalid filter") String filter) { - List<User> users = userService.getRandomUsers(identity.getId(), amount, SearchFilter.valueOf(filter)); - List<UserDTO> userDTOs = new ArrayList<>(); - for(User user : users) { - UserDTO userDTO = modelMapper.map(user, UserDTO.class); - userDTOs.add(userDTO); - log.info("[UserController:getRandomUsers] user: {}", userDTO.getId()); - } - return ResponseEntity.ok(userDTOs); - } + /** + * Get all feedback. + * @param identity The authenticated user's identity. + * @return A list containing all feedback. + */ + @Operation(summary = "Send feedback", description = "Send feedback from a user.") + @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Success") }) + @GetMapping("/get-feedback") + public ResponseEntity<List<FeedbackResponseDTO>> getFeedback(@AuthenticationPrincipal AuthIdentity identity) { + if (!identity.getRole().equalsIgnoreCase("ADMIN")) { + log.error("[UserController:getFeedback] Permission denied, user role: {}", identity.getRole()); + throw new PermissionDeniedException(); + } + List<Feedback> feedbacks = userService.getFeedback(); + List<FeedbackResponseDTO> feedbackResponseDTOS = feedbacks.stream() + .map(quiz -> modelMapper.map(quiz, FeedbackResponseDTO.class)) + .toList(); + for (FeedbackResponseDTO feedbackResponseDTO : feedbackResponseDTOS) { + log.info("[UserController:getFeedback] feedback: {}", feedbackResponseDTO.getId()); + } + return ResponseEntity.ok(feedbackResponseDTOS); + } - @Operation(summary = "Update User Subscription Level", description = "Updates the subscription level of the current user") - @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Subscription level updated successfully") - }) - @PutMapping("/subscription/{subscriptionLevel}") - public ResponseEntity<?> updateSubscriptionLevel( - @AuthenticationPrincipal AuthIdentity identity, - @PathVariable @Enumerator(value = SubscriptionLevel.class, message = "Invalid subscription level") String subscriptionLevel) { - userService.updateSubscriptionLevel(identity.getId(), SubscriptionLevel.valueOf(subscriptionLevel)); - log.info("[UserController:updateSubscriptionLevel] subscription level: {}", subscriptionLevel); - return ResponseEntity.ok().build(); - } -} + @Operation(summary = "Get X amount of random users", + description = "Get X amount of random users that fit the filter") + @ApiResponses({ @ApiResponse(responseCode = "200", description = "Successfully retrieved list of users"), }) + @GetMapping("/search/random/{amount}/{filter}") + public ResponseEntity<List<UserDTO>> getRandomUsers(@AuthenticationPrincipal AuthIdentity identity, + @PathVariable int amount, + @PathVariable @Enumerator(value = SearchFilter.class, message = "Invalid filter") String filter) { + List<User> users = userService.getRandomUsers(identity.getId(), amount, SearchFilter.valueOf(filter)); + List<UserDTO> userDTOs = new ArrayList<>(); + for (User user : users) { + UserDTO userDTO = modelMapper.map(user, UserDTO.class); + userDTOs.add(userDTO); + log.info("[UserController:getRandomUsers] user: {}", userDTO.getId()); + } + return ResponseEntity.ok(userDTOs); + } + @Operation(summary = "Update User Subscription Level", + description = "Updates the subscription level of the current user") + @ApiResponses( + value = { @ApiResponse(responseCode = "200", description = "Subscription level updated successfully") }) + @PutMapping("/subscription/{subscriptionLevel}") + public ResponseEntity<?> updateSubscriptionLevel(@AuthenticationPrincipal AuthIdentity identity, + @PathVariable @Enumerator(value = SubscriptionLevel.class, + message = "Invalid subscription level") String subscriptionLevel) { + userService.updateSubscriptionLevel(identity.getId(), SubscriptionLevel.valueOf(subscriptionLevel)); + log.info("[UserController:updateSubscriptionLevel] subscription level: {}", subscriptionLevel); + return ResponseEntity.ok().build(); + } +} diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/auth/AuthenticationResponse.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/auth/AuthenticationResponse.java index 15522cee0361c95e8d2b095e9eda514f886bb358..4c2bee73810986dbfe80ca94ff3de98b2383aa04 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/auth/AuthenticationResponse.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/auth/AuthenticationResponse.java @@ -10,11 +10,18 @@ import lombok.Data; @AllArgsConstructor public class AuthenticationResponse { - private String firstName; - private String lastName; - private Long userId; - private Long profileImage; - private String role; - private String subscriptionLevel; - private String token; + private String firstName; + + private String lastName; + + private Long userId; + + private Long profileImage; + + private String role; + + private String subscriptionLevel; + + private String token; + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/auth/BankIDRequest.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/auth/BankIDRequest.java index 4029af7a149fb36f170debb75535df997894a66b..e64acf85444a0df9f14c39ea55c54b4c47ec9a1a 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/auth/BankIDRequest.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/auth/BankIDRequest.java @@ -5,7 +5,8 @@ import lombok.Data; @Data public final class BankIDRequest { - private String code; - private String state; + private String code; + + private String state; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/auth/LoginRequest.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/auth/LoginRequest.java index 7588b45f7e131044cdb99c41745bf39bd307e910..de4893dac0acd3d5566c99d477dfb5079dfa7e66 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/auth/LoginRequest.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/auth/LoginRequest.java @@ -10,9 +10,10 @@ import no.ntnu.idi.stud.savingsapp.validation.Password; @Data public final class LoginRequest { - @Email(message = "Invalid email") - private String email; + @Email(message = "Invalid email") + private String email; + + @Password + private String password; - @Password - private String password; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/auth/SignUpRequest.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/auth/SignUpRequest.java index f1dc850dd88b1984545c957dea02de8989127ea8..333f1f2fc067e4590f55bfba24abb9bbf24a89f9 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/auth/SignUpRequest.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/auth/SignUpRequest.java @@ -14,24 +14,24 @@ import no.ntnu.idi.stud.savingsapp.validation.Password; @Data public final class SignUpRequest { - @Name - private String firstName; + @Name + private String firstName; - @Name - private String lastName; + @Name + private String lastName; - @Email(message = "Invalid email") - private String email; + @Email(message = "Invalid email") + private String email; - @Password - private String password; + @Password + private String password; - private Long checkingAccountBBAN; + private Long checkingAccountBBAN; - private Long savingsAccountBBAN; + private Long savingsAccountBBAN; - @Valid - @NotNull(message = "Configuration is required") - private ConfigurationDTO configuration; + @Valid + @NotNull(message = "Configuration is required") + private ConfigurationDTO configuration; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/badge/BadgeDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/badge/BadgeDTO.java index ca75f5fe53d6fbf59e903aac8620178721e74e18..24726547ec14b2040cb10d07cd89dc7271a02337 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/badge/BadgeDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/badge/BadgeDTO.java @@ -5,9 +5,12 @@ import lombok.Data; @Data public class BadgeDTO { - private Long id; - private String badgeName; - private int criteria; - private Long imageId; + private Long id; + + private String badgeName; + + private int criteria; + + private Long imageId; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/budget/BudgetRequestDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/budget/BudgetRequestDTO.java index 16550921241f11a6442bc9ba36b07d43659c43d9..b1f65ae8e5d5863570f5e870c3a954113489df90 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/budget/BudgetRequestDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/budget/BudgetRequestDTO.java @@ -6,8 +6,10 @@ import lombok.Data; @Data public class BudgetRequestDTO { - private String budgetName; - private BigDecimal budgetAmount; - private BigDecimal expenseAmount; + private String budgetName; + + private BigDecimal budgetAmount; + + private BigDecimal expenseAmount; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/budget/BudgetResponseDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/budget/BudgetResponseDTO.java index e889ce72b33d3e094c240fd30116700412eb0168..3b31fc1b1dd2171b3d95c33fb4d5116b7b66aae7 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/budget/BudgetResponseDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/budget/BudgetResponseDTO.java @@ -7,10 +7,14 @@ import lombok.Data; @Data public class BudgetResponseDTO { - private Long id; - private String budgetName; - private BigDecimal budgetAmount; - private BigDecimal expenseAmount; - private Timestamp createdAt; + private Long id; + + private String budgetName; + + private BigDecimal budgetAmount; + + private BigDecimal expenseAmount; + + private Timestamp createdAt; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/budget/ExpenseRequestDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/budget/ExpenseRequestDTO.java index f9589a648db95573de45a37273177ada060c7696..4ee9235a4ee31153360bb632dbeb1a1a679df4a0 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/budget/ExpenseRequestDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/budget/ExpenseRequestDTO.java @@ -6,8 +6,10 @@ import lombok.Data; @Data public class ExpenseRequestDTO { - private Long expenseId; - private String description; - private BigDecimal amount; + private Long expenseId; + + private String description; + + private BigDecimal amount; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/budget/ExpenseResponseDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/budget/ExpenseResponseDTO.java index 0f2b0be15bc50e1ce667ac5e8b6a78ce4f32b8ed..4f3c0c6589244c3a95afbe6a7f007c11678709f9 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/budget/ExpenseResponseDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/budget/ExpenseResponseDTO.java @@ -5,9 +5,12 @@ import lombok.Data; @Data public class ExpenseResponseDTO { - private Long expenseId; - private Long budgetId; - private String description; - private String amount; + private Long expenseId; + + private Long budgetId; + + private String description; + + private String amount; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/configuration/ConfigurationDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/configuration/ConfigurationDTO.java index bd22770b99d1c064060a727567890626aa8efbf2..6d1621d982d5fb47eaf9aad602fb0d65ccf489a5 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/configuration/ConfigurationDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/configuration/ConfigurationDTO.java @@ -11,8 +11,10 @@ import java.util.List; @NoArgsConstructor public class ConfigurationDTO { - private String commitment; - private String experience; - private List<@Enumerator(value = ChallengeType.class) String> challengeTypes; + private String commitment; + + private String experience; + + private List<@Enumerator(value = ChallengeType.class) String> challengeTypes; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/goal/ChallengeDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/goal/ChallengeDTO.java index dafca4416483bc2a8b1ecb86cf37af479f2704b9..7224b6faf6519f5600132660e9a74b14e225188e 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/goal/ChallengeDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/goal/ChallengeDTO.java @@ -9,14 +9,22 @@ import java.util.List; @Data public final class ChallengeDTO { - private long id; - private BigDecimal amount; - private int points; - private int checkDays; - private int totalDays; - private Timestamp startDate; - private Timestamp endDate; - private ChallengeTemplateDTO challengeTemplate; - private List<ProgressDTO> progressList; + private long id; + + private BigDecimal amount; + + private int points; + + private int checkDays; + + private int totalDays; + + private Timestamp startDate; + + private Timestamp endDate; + + private ChallengeTemplateDTO challengeTemplate; + + private List<ProgressDTO> progressList; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/goal/ChallengeTemplateDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/goal/ChallengeTemplateDTO.java index 463a98b2c06d49ef1b54741727907f18d0008593..b450dfa102298d6719ce319812dbad441f1e6d59 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/goal/ChallengeTemplateDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/goal/ChallengeTemplateDTO.java @@ -8,10 +8,14 @@ import java.math.BigDecimal; @Data public final class ChallengeTemplateDTO { - private long id; - private String templateName; - private String text; - private BigDecimal amount; - private ChallengeType type; + private long id; + + private String templateName; + + private String text; + + private BigDecimal amount; + + private ChallengeType type; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/goal/CreateGoalDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/goal/CreateGoalDTO.java index 481a4829629f545adb56b541c67c9df321e5d0d4..d49aa8487b654f45d6ca78b5e37439a59e3d41db 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/goal/CreateGoalDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/goal/CreateGoalDTO.java @@ -9,17 +9,17 @@ import java.util.List; @Data public final class CreateGoalDTO { - @NonNull - private String name; + @NonNull + private String name; - @NonNull - private String description; + @NonNull + private String description; - private BigDecimal targetAmount; + private BigDecimal targetAmount; - @NonNull - private String targetDate; + @NonNull + private String targetDate; - private List<GroupUserDTO> distribution; + private List<GroupUserDTO> distribution; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/goal/GoalDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/goal/GoalDTO.java index 6182ce7c2e78abbd83dd2ab6aeeed1580c7e8f1d..4cdc65390d47c84392f976b345913faa039a7af0 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/goal/GoalDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/goal/GoalDTO.java @@ -12,13 +12,20 @@ import java.util.List; @NoArgsConstructor public final class GoalDTO { - private long id; - private String name; - private String description; - private BigDecimal targetAmount; - private Timestamp targetDate; - private Timestamp createdAt; - private List<ChallengeDTO> challenges; - private UserDTO user; + private long id; + + private String name; + + private String description; + + private BigDecimal targetAmount; + + private Timestamp targetDate; + + private Timestamp createdAt; + + private List<ChallengeDTO> challenges; + + private UserDTO user; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/goal/GroupUserDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/goal/GroupUserDTO.java index d88a88d88a6b14de472a858050c8d1deb9dd3b69..c90c4d6a774b92905fab6f96f9e3ac6653c847f2 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/goal/GroupUserDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/goal/GroupUserDTO.java @@ -8,6 +8,8 @@ import java.math.BigDecimal; @Data public final class GroupUserDTO { - private Long userId; - private BigDecimal amount; + private Long userId; + + private BigDecimal amount; + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/goal/MarkChallengeDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/goal/MarkChallengeDTO.java index c523bc1a9a1ba161e7658cfe8c2190a097e98f84..f870d8535ebe69e4ab37c033e15b6bd0f1937cb0 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/goal/MarkChallengeDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/goal/MarkChallengeDTO.java @@ -7,8 +7,10 @@ import java.math.BigDecimal; @Data public final class MarkChallengeDTO { - private long id; - private int day; - private BigDecimal amount; + private long id; + + private int day; + + private BigDecimal amount; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/goal/ProgressDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/goal/ProgressDTO.java index 271e826273a1a4ed2d4a419637352e7130e6214b..d8173f7585733efa3cbf6d81d5c88e13804fa46f 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/goal/ProgressDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/goal/ProgressDTO.java @@ -8,9 +8,12 @@ import java.sql.Timestamp; @Data public final class ProgressDTO { - private long id; - private int day; - private BigDecimal amount; - private Timestamp completedAt; + private long id; + + private int day; + + private BigDecimal amount; + + private Timestamp completedAt; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/leaderboard/LeaderboardDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/leaderboard/LeaderboardDTO.java index e7dac095e78f2ba1d4c965fa42499ad39a484399..f8a24850ed195a204b268cff4769f3f8047c7ac2 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/leaderboard/LeaderboardDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/leaderboard/LeaderboardDTO.java @@ -7,8 +7,10 @@ import java.util.List; @Data public final class LeaderboardDTO { - private String type; - private String filter; - private List<LeaderboardEntryDTO> entries; + private String type; + + private String filter; + + private List<LeaderboardEntryDTO> entries; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/leaderboard/LeaderboardEntryDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/leaderboard/LeaderboardEntryDTO.java index a073c12f1a61451faa4cb7043e8d03b3f517357d..2c63a32ffb4fc9b2dca9aaa057fad8dd63c4da98 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/leaderboard/LeaderboardEntryDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/leaderboard/LeaderboardEntryDTO.java @@ -6,8 +6,10 @@ import no.ntnu.idi.stud.savingsapp.dto.user.UserDTO; @Data public final class LeaderboardEntryDTO { - private UserDTO user; - private int score; - private long rank; + private UserDTO user; + + private int score; + + private long rank; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/notification/NotificationDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/notification/NotificationDTO.java index f311716202e6f7aa0539d978e3c42e8dc631388e..2a287a0e04c586f337dd633953fd4f13555e43f0 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/notification/NotificationDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/notification/NotificationDTO.java @@ -7,10 +7,14 @@ import no.ntnu.idi.stud.savingsapp.model.notification.NotificationType; @Data public class NotificationDTO { - private long id; - private String message; - private boolean unread; - private NotificationType notificationType; - private Timestamp createdAt; + private long id; + + private String message; + + private boolean unread; + + private NotificationType notificationType; + + private Timestamp createdAt; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/question/AnswerDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/question/AnswerDTO.java index a4f50cfdc752bebc06fc3f4fd1322887dcebe61c..a5d78eedbb286e7b4c8d81d64ae074dcb2628f5e 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/question/AnswerDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/question/AnswerDTO.java @@ -5,6 +5,6 @@ import lombok.Data; @Data public class AnswerDTO { - String answer_text; + String answer_text; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/question/QuestionDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/question/QuestionDTO.java index f0245bed3d44a85a80ced96b8d960c2f97359ad2..8857a72fbe4b02a86965d9da26cbaed79f41bd19 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/question/QuestionDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/question/QuestionDTO.java @@ -7,7 +7,8 @@ import lombok.Data; @Data public class QuestionDTO { - String questionText; - List<AnswerDTO> answers; + String questionText; + + List<AnswerDTO> answers; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/store/InventoryDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/store/InventoryDTO.java index efccdaa988851a66accd406ff2812978c11549f7..16eb2bf34f90ea110ed1ce9d9aa04720cd0d78ec 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/store/InventoryDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/store/InventoryDTO.java @@ -7,9 +7,12 @@ import lombok.Data; @Data public final class InventoryDTO { - private long id; - private String itemName; - private long imageId; - private Timestamp boughtAt; + private long id; + + private String itemName; + + private long imageId; + + private Timestamp boughtAt; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/store/ItemDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/store/ItemDTO.java index 39003ab3bd137ae728486b2698681606feb380ab..6041cc8103560b2503560b25645fb66ea16b7e81 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/store/ItemDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/store/ItemDTO.java @@ -5,10 +5,14 @@ import lombok.Data; @Data public class ItemDTO { - private long id; - private String itemName; - private int price; - private long imageId; - private boolean alreadyBought; + private long id; + + private String itemName; + + private int price; + + private long imageId; + + private boolean alreadyBought; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/BankAccountResponseDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/BankAccountResponseDTO.java index 4b7091bbdd3bc14d4ceb4820b8d8e0c72465e6a1..ee74d500e2038170d467ef6bd304270af98775ac 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/BankAccountResponseDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/BankAccountResponseDTO.java @@ -5,6 +5,9 @@ import lombok.Data; @Data public final class BankAccountResponseDTO { - private Long bban; - private BigDecimal balance; + + private Long bban; + + private BigDecimal balance; + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/FeedbackRequestDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/FeedbackRequestDTO.java index 8119e9f4a35758af0c4ca04bffa92f3b03fff60d..993556d418aaa55d516d7374f04f78f666173c94 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/FeedbackRequestDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/FeedbackRequestDTO.java @@ -5,7 +5,8 @@ import lombok.Data; @Data public class FeedbackRequestDTO { - private String email; - private String message; + private String email; + + private String message; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/FeedbackResponseDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/FeedbackResponseDTO.java index 7863216000a839fe8e77ee3d80c3b420a55d5374..339c795e1c5581514406849453babb3cf0ecf32c 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/FeedbackResponseDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/FeedbackResponseDTO.java @@ -6,9 +6,12 @@ import lombok.Data; @Data public class FeedbackResponseDTO { - private String id; - private String email; - private String message; - private Timestamp createdAt; + private String id; + + private String email; + + private String message; + + private Timestamp createdAt; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/PasswordResetDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/PasswordResetDTO.java index 117f9b4066c2495bb8ade8508c36a7ff14bd69ed..feb356b91affa1da3fa0d9f5292afb1a8ada299f 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/PasswordResetDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/PasswordResetDTO.java @@ -7,10 +7,10 @@ import no.ntnu.idi.stud.savingsapp.validation.Password; @Data public final class PasswordResetDTO { - @NotNull(message = "Token is required") - private String token; + @NotNull(message = "Token is required") + private String token; - @Password - private String password; + @Password + private String password; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/PasswordUpdateDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/PasswordUpdateDTO.java index c7a36c89ceb69eb2c355024b03b03062d97bb049..983d7e4ab63ccb5ca9bf56addcd19afc39dd1945 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/PasswordUpdateDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/PasswordUpdateDTO.java @@ -6,10 +6,10 @@ import no.ntnu.idi.stud.savingsapp.validation.Password; @Data public final class PasswordUpdateDTO { - @Password - private String oldPassword; + @Password + private String oldPassword; - @Password - private String newPassword; + @Password + private String newPassword; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/PointDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/PointDTO.java index 7fe8ea6b4d617ff18ef94a49a5b71c0ba88475bc..e7b1c4567065a3293f8046f30be0e6cf41cb17c3 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/PointDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/PointDTO.java @@ -4,6 +4,9 @@ import lombok.Data; @Data public class PointDTO { - private int currentPoints; - private int totalEarnedPoints; + + private int currentPoints; + + private int totalEarnedPoints; + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/ProfileDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/ProfileDTO.java index 5fc4d7fbee0c3a9bc7868809d133f507e4ec6d9e..f2ddf7aa36601d7e0d70664d841da6ab033ff63f 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/ProfileDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/ProfileDTO.java @@ -7,12 +7,20 @@ import java.sql.Timestamp; @Data public class ProfileDTO { - private long id; - private String firstName; - private String lastName; - private Long profileImage; - private Long bannerImage; - private Timestamp createdAt; - private PointDTO point; - private StreakDTO streak; + private long id; + + private String firstName; + + private String lastName; + + private Long profileImage; + + private Long bannerImage; + + private Timestamp createdAt; + + private PointDTO point; + + private StreakDTO streak; + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/StreakDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/StreakDTO.java index 33619f3048e17cb262ee385737a500c57264fcc2..d856b9a57b808cb5866a809a79a8dd253daa669f 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/StreakDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/StreakDTO.java @@ -6,10 +6,16 @@ import lombok.Data; @Data public final class StreakDTO { - private int currentStreak; - private Timestamp currentStreakCreatedAt; - private Timestamp currentStreakUpdatedAt; - private int highestStreak; - private Timestamp highestStreakCreatedAt; - private Timestamp highestStreakEndedAt; + private int currentStreak; + + private Timestamp currentStreakCreatedAt; + + private Timestamp currentStreakUpdatedAt; + + private int highestStreak; + + private Timestamp highestStreakCreatedAt; + + private Timestamp highestStreakEndedAt; + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/UserDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/UserDTO.java index 7692a61684a4df99de2dff1ec59455ad63f8fd97..c358e487ab21517448730f3a821217f1c5e8910c 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/UserDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/UserDTO.java @@ -7,17 +7,30 @@ import java.sql.Timestamp; @Data public class UserDTO { - private long id; - private String firstName; - private String lastName; - private Long profileImage; - private Long bannerImage; - private String email; - private Timestamp createdAt; - private String role; - private String subscriptionLevel; - private Long checkingAccountBBAN; - private Long savingsAccountBBAN; - private PointDTO point; - private StreakDTO streak; + private long id; + + private String firstName; + + private String lastName; + + private Long profileImage; + + private Long bannerImage; + + private String email; + + private Timestamp createdAt; + + private String role; + + private String subscriptionLevel; + + private Long checkingAccountBBAN; + + private Long savingsAccountBBAN; + + private PointDTO point; + + private StreakDTO streak; + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/UserUpdateDTO.java b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/UserUpdateDTO.java index 06ade69561c28e1ffae9341551d6627d16a1908b..a20561a9c389e0d9fb60cf1073368a2d0073452a 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/UserUpdateDTO.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/dto/user/UserUpdateDTO.java @@ -9,23 +9,24 @@ import no.ntnu.idi.stud.savingsapp.validation.Name; @Data public final class UserUpdateDTO { - @Name(nullable = true) - private String firstName; + @Name(nullable = true) + private String firstName; - @Name(nullable = true) - private String lastName; + @Name(nullable = true) + private String lastName; - @Email(message = "Invalid email") - private String email; + @Email(message = "Invalid email") + private String email; - private Long profileImage; + private Long profileImage; - private Long bannerImage; + private Long bannerImage; - private Long savingsAccountBBAN; + private Long savingsAccountBBAN; - private Long checkingAccountBBAN; + private Long checkingAccountBBAN; + + @Valid + private ConfigurationDTO configuration; - @Valid - private ConfigurationDTO configuration; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/ExceptionResponse.java b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/ExceptionResponse.java index 157d8f5e968d0b6ba3d5d3ab12e0bd53271805a7..3ebe40339dbbe4d1cc39e27614753040eb904ba4 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/ExceptionResponse.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/ExceptionResponse.java @@ -12,18 +12,19 @@ import org.springframework.http.ResponseEntity; @AllArgsConstructor public class ExceptionResponse { - private int status; - private String message; + private int status; + + private String message; + + /** + * Creates a ResponseEntity containing the exception response. + * @param status The HTTP status code. + * @param message The message describing the exception. + * @return A ResponseEntity containing the exception response. + */ + protected static ResponseEntity<ExceptionResponse> toResponseEntity(HttpStatus status, String message) { + ExceptionResponse response = new ExceptionResponse(status.value(), message); + return ResponseEntity.status(status).body(response); + } - /** - * Creates a ResponseEntity containing the exception response. - * - * @param status The HTTP status code. - * @param message The message describing the exception. - * @return A ResponseEntity containing the exception response. - */ - protected static ResponseEntity<ExceptionResponse> toResponseEntity(HttpStatus status, String message) { - ExceptionResponse response = new ExceptionResponse(status.value(), message); - return ResponseEntity.status(status).body(response); - } } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/GlobalExceptionHandler.java b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/GlobalExceptionHandler.java index 7623dff72009e42c52a4cd4a84c8a2d93be84eb1..62a09f53b1c58d7386eeb2e6f7727aa5bfbdff56 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/GlobalExceptionHandler.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/GlobalExceptionHandler.java @@ -33,114 +33,110 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExcep @ControllerAdvice public class GlobalExceptionHandler extends ResponseEntityExceptionHandler { - /** - * Handles validation errors for method arguments. - * - * @param e The MethodArgumentNotValidException containing validation errors. - * @param headers The headers for the response. - * @param status The HTTP status code. - * @param request The current web request. - * @return A ResponseEntity containing the error response. - */ - @Override - protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException e, HttpHeaders headers, HttpStatusCode status, WebRequest request) { - String error = e.getMessage(); - FieldError fieldError = e.getFieldError(); - if (fieldError != null) { - error = fieldError.getDefaultMessage(); - } - ExceptionResponse response = new ExceptionResponse(HttpStatus.BAD_REQUEST.value(), error); - return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response); - } + /** + * Handles validation errors for method arguments. + * @param e The MethodArgumentNotValidException containing validation errors. + * @param headers The headers for the response. + * @param status The HTTP status code. + * @param request The current web request. + * @return A ResponseEntity containing the error response. + */ + @Override + protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException e, + HttpHeaders headers, HttpStatusCode status, WebRequest request) { + String error = e.getMessage(); + FieldError fieldError = e.getFieldError(); + if (fieldError != null) { + error = fieldError.getDefaultMessage(); + } + ExceptionResponse response = new ExceptionResponse(HttpStatus.BAD_REQUEST.value(), error); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(response); + } - /** - * Handles exceptions by returning an {@link HttpStatus#BAD_REQUEST} response. - * - * @param e The exception. - * @return A ResponseEntity containing the error response. - */ - @ExceptionHandler({ConstraintViolationException.class, InvalidChallengeDayException.class}) - public ResponseEntity<ExceptionResponse> handleBadRequest(Exception e) { - String error = e.getMessage(); - if (e instanceof ConstraintViolationException constraintViolationException) { - for (ConstraintViolation<?> violation : constraintViolationException.getConstraintViolations()) { - error = violation.getMessage(); - break; - } - } - return ExceptionResponse.toResponseEntity(HttpStatus.BAD_REQUEST, error); - } + /** + * Handles exceptions by returning an {@link HttpStatus#BAD_REQUEST} response. + * @param e The exception. + * @return A ResponseEntity containing the error response. + */ + @ExceptionHandler({ ConstraintViolationException.class, InvalidChallengeDayException.class }) + public ResponseEntity<ExceptionResponse> handleBadRequest(Exception e) { + String error = e.getMessage(); + if (e instanceof ConstraintViolationException constraintViolationException) { + for (ConstraintViolation<?> violation : constraintViolationException.getConstraintViolations()) { + error = violation.getMessage(); + break; + } + } + return ExceptionResponse.toResponseEntity(HttpStatus.BAD_REQUEST, error); + } - /** - * Handles exceptions by returning an {@link HttpStatus#UNAUTHORIZED} response. - * - * @param e The exception. - * @return A ResponseEntity containing the error response. - */ - @ExceptionHandler({InvalidCredentialsException.class, AccessDeniedException.class, - AuthenticationException.class, CredentialsExpiredException.class}) - public ResponseEntity<ExceptionResponse> handleUnauthorized(Exception e) { - return ExceptionResponse.toResponseEntity(HttpStatus.UNAUTHORIZED, e.getMessage()); - } + /** + * Handles exceptions by returning an {@link HttpStatus#UNAUTHORIZED} response. + * @param e The exception. + * @return A ResponseEntity containing the error response. + */ + @ExceptionHandler({ InvalidCredentialsException.class, AccessDeniedException.class, AuthenticationException.class, + CredentialsExpiredException.class }) + public ResponseEntity<ExceptionResponse> handleUnauthorized(Exception e) { + return ExceptionResponse.toResponseEntity(HttpStatus.UNAUTHORIZED, e.getMessage()); + } - /** - * Handles exceptions by returning an {@link HttpStatus#FORBIDDEN} response. - * - * @param e The exception. - * @return A ResponseEntity containing the error response. - */ - @ExceptionHandler({PermissionDeniedException.class, InvalidPasswordResetTokenException.class}) - public ResponseEntity<ExceptionResponse> handleForbidden(Exception e) { - return ExceptionResponse.toResponseEntity(HttpStatus.FORBIDDEN, e.getMessage()); - } + /** + * Handles exceptions by returning an {@link HttpStatus#FORBIDDEN} response. + * @param e The exception. + * @return A ResponseEntity containing the error response. + */ + @ExceptionHandler({ PermissionDeniedException.class, InvalidPasswordResetTokenException.class }) + public ResponseEntity<ExceptionResponse> handleForbidden(Exception e) { + return ExceptionResponse.toResponseEntity(HttpStatus.FORBIDDEN, e.getMessage()); + } - /** - * Handles exceptions by returning an {@link HttpStatus#CONFLICT} response. - * - * @param e The exception. - * @return A ResponseEntity containing the error response. - */ - @ExceptionHandler({EmailAlreadyExistsException.class}) - public ResponseEntity<ExceptionResponse> handleConflict(Exception e) { - return ExceptionResponse.toResponseEntity(HttpStatus.CONFLICT, e.getMessage()); - } + /** + * Handles exceptions by returning an {@link HttpStatus#CONFLICT} response. + * @param e The exception. + * @return A ResponseEntity containing the error response. + */ + @ExceptionHandler({ EmailAlreadyExistsException.class }) + public ResponseEntity<ExceptionResponse> handleConflict(Exception e) { + return ExceptionResponse.toResponseEntity(HttpStatus.CONFLICT, e.getMessage()); + } - /** - * Handles exceptions by returning an {@link HttpStatus#NOT_FOUND} response. - * - * @param e The exception. - * @return A ResponseEntity containing the error response. - */ - @ExceptionHandler({UserNotFoundException.class, ImageNotFoundException.class, - GoalNotFoundException.class, ChallengeNotFoundException.class}) - public ResponseEntity<ExceptionResponse> handleNotFound(Exception e) { - return ExceptionResponse.toResponseEntity(HttpStatus.NOT_FOUND, e.getMessage()); - } + /** + * Handles exceptions by returning an {@link HttpStatus#NOT_FOUND} response. + * @param e The exception. + * @return A ResponseEntity containing the error response. + */ + @ExceptionHandler({ UserNotFoundException.class, ImageNotFoundException.class, GoalNotFoundException.class, + ChallengeNotFoundException.class }) + public ResponseEntity<ExceptionResponse> handleNotFound(Exception e) { + return ExceptionResponse.toResponseEntity(HttpStatus.NOT_FOUND, e.getMessage()); + } - /** - * Handles remaining exceptions by returning an {@link HttpStatus#INTERNAL_SERVER_ERROR} response. - * - * @param e The exception. - * @return A ResponseEntity containing the error response. - */ - @ExceptionHandler(Exception.class) - public ResponseEntity<ExceptionResponse> handleRemainingExceptions(Exception e) { - return ExceptionResponse.toResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage()); - } + /** + * Handles remaining exceptions by returning an + * {@link HttpStatus#INTERNAL_SERVER_ERROR} response. + * @param e The exception. + * @return A ResponseEntity containing the error response. + */ + @ExceptionHandler(Exception.class) + public ResponseEntity<ExceptionResponse> handleRemainingExceptions(Exception e) { + return ExceptionResponse.toResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage()); + } + + /** + * Customizes the default exception handler. + * @param e The exception. + * @param body The body of the response. + * @param headers The headers for the response. + * @param statusCode The HTTP status code. + * @param request The current web request. + * @return A ResponseEntity containing the error response. + */ + @Override + protected ResponseEntity<Object> handleExceptionInternal(Exception e, Object body, HttpHeaders headers, + HttpStatusCode statusCode, WebRequest request) { + ExceptionResponse response = new ExceptionResponse(statusCode.value(), e.getMessage()); + return super.handleExceptionInternal(e, response, headers, statusCode, request); + } - /** - * Customizes the default exception handler. - * - * @param e The exception. - * @param body The body of the response. - * @param headers The headers for the response. - * @param statusCode The HTTP status code. - * @param request The current web request. - * @return A ResponseEntity containing the error response. - */ - @Override - protected ResponseEntity<Object> handleExceptionInternal(Exception e, Object body, HttpHeaders headers, HttpStatusCode statusCode, WebRequest request) { - ExceptionResponse response = new ExceptionResponse(statusCode.value(), e.getMessage()); - return super.handleExceptionInternal(e, response, headers, statusCode, request); - } } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/auth/InvalidCredentialsException.java b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/auth/InvalidCredentialsException.java index 0b6e1334721d462633b108a6d3435167b5a74ad2..c6ff7723d92e242a71ff1bdb2c6eaaf463cb9d0a 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/auth/InvalidCredentialsException.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/auth/InvalidCredentialsException.java @@ -5,17 +5,18 @@ package no.ntnu.idi.stud.savingsapp.exception.auth; */ public class InvalidCredentialsException extends RuntimeException { - /** - * Constructs an InvalidCredentialsException with the default message. - */ - public InvalidCredentialsException() { - super("Invalid credentials"); - } + /** + * Constructs an InvalidCredentialsException with the default message. + */ + public InvalidCredentialsException() { + super("Invalid credentials"); + } + + /** + * Constructs an InvalidCredentialsException with a custom message. + */ + public InvalidCredentialsException(String string) { + super(string); + } - /** - * Constructs an InvalidCredentialsException with a custom message. - */ - public InvalidCredentialsException(String string) { - super(string); - } } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/badge/BadgeNotFoundException.java b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/badge/BadgeNotFoundException.java index ad0124e8d6ac15481c2e6bc73c6578312f79bce1..7d9d02c841b715395d140fb87cfcc08e0a62096d 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/badge/BadgeNotFoundException.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/badge/BadgeNotFoundException.java @@ -5,11 +5,11 @@ package no.ntnu.idi.stud.savingsapp.exception.badge; */ public class BadgeNotFoundException extends RuntimeException { - /** - * Constructs an BadgeNotFoundException with default message. - */ - public BadgeNotFoundException() { - super("Badge is not found"); - } + /** + * Constructs an BadgeNotFoundException with default message. + */ + public BadgeNotFoundException() { + super("Badge is not found"); + } } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/budget/BudgetNotFoundException.java b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/budget/BudgetNotFoundException.java index 021cbd453f0d2146a06872ff7def99dc285c37e5..dccf80ecc8ca993471b9d0ef5d26dacce91474fd 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/budget/BudgetNotFoundException.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/budget/BudgetNotFoundException.java @@ -5,10 +5,11 @@ package no.ntnu.idi.stud.savingsapp.exception.budget; */ public class BudgetNotFoundException extends RuntimeException { - /** - * Constructs an BudgetNotFoundException with default message. - */ - public BudgetNotFoundException() { - super("Budget is not found"); - } + /** + * Constructs an BudgetNotFoundException with default message. + */ + public BudgetNotFoundException() { + super("Budget is not found"); + } + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/budget/ExpenseNotFoundException.java b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/budget/ExpenseNotFoundException.java index f7145e067e599e4d146baf44f9e953ce966fe054..f8fd4761a018462be773badbb4a476fbd75d05b1 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/budget/ExpenseNotFoundException.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/budget/ExpenseNotFoundException.java @@ -5,10 +5,11 @@ package no.ntnu.idi.stud.savingsapp.exception.budget; */ public class ExpenseNotFoundException extends RuntimeException { - /** - * Constructs an ExpenseNotFoundException with default message. - */ - public ExpenseNotFoundException() { - super("Expense is not found"); - } + /** + * Constructs an ExpenseNotFoundException with default message. + */ + public ExpenseNotFoundException() { + super("Expense is not found"); + } + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/goal/ChallengeNotFoundException.java b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/goal/ChallengeNotFoundException.java index 5439a2fec7b3b368902d97c87e2b0a281ade181c..04427c5bce4e06951f11dfd6c18dd9c9df2192ea 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/goal/ChallengeNotFoundException.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/goal/ChallengeNotFoundException.java @@ -5,15 +5,19 @@ package no.ntnu.idi.stud.savingsapp.exception.goal; */ public final class ChallengeNotFoundException extends RuntimeException { - /** - * Constructs a ChallengeNotFoundException with default message. - */ - public ChallengeNotFoundException() { super("Challenge not found");} + /** + * Constructs a ChallengeNotFoundException with default message. + */ + public ChallengeNotFoundException() { + super("Challenge not found"); + } + + /** + * Constructs a ChallengeNotFoundException with custom message. + * @param string the custom exception message + */ + public ChallengeNotFoundException(String string) { + super(string); + } - /** - * Constructs a ChallengeNotFoundException with custom message. - * - * @param string the custom exception message - */ - public ChallengeNotFoundException(String string) {super(string);} } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/goal/GoalNotFoundException.java b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/goal/GoalNotFoundException.java index 23b3798793140e9173a257510ad6ab90a176439a..14e1058adf8bfd34b09e970963452a5502c8763b 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/goal/GoalNotFoundException.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/goal/GoalNotFoundException.java @@ -5,15 +5,19 @@ package no.ntnu.idi.stud.savingsapp.exception.goal; */ public final class GoalNotFoundException extends RuntimeException { - /** - * Constructs a GoalNotFoundException with default message. - */ - public GoalNotFoundException() { super("Goal not found");} + /** + * Constructs a GoalNotFoundException with default message. + */ + public GoalNotFoundException() { + super("Goal not found"); + } + + /** + * Constructs a GoalNotFoundException with custom message. + * @param string the custom exception message + */ + public GoalNotFoundException(String string) { + super(string); + } - /** - * Constructs a GoalNotFoundException with custom message. - * - * @param string the custom exception message - */ - public GoalNotFoundException(String string) {super(string);} } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/goal/GroupNotFoundException.java b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/goal/GroupNotFoundException.java index efb1667f3e8d119ba7fe50afc04d00a99812b05c..c408381a483a9dfa67ac4b96b2fa663078b6a08b 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/goal/GroupNotFoundException.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/goal/GroupNotFoundException.java @@ -1,16 +1,20 @@ package no.ntnu.idi.stud.savingsapp.exception.goal; -public final class GroupNotFoundException extends RuntimeException{ +public final class GroupNotFoundException extends RuntimeException { - /** - * Constructs a GroupNotFoundException with default message. - */ - public GroupNotFoundException() { super("Group not found");} + /** + * Constructs a GroupNotFoundException with default message. + */ + public GroupNotFoundException() { + super("Group not found"); + } + + /** + * Constructs a GroupNotFoundException with custom message. + * @param string the custom exception message + */ + public GroupNotFoundException(String string) { + super(string); + } - /** - * Constructs a GroupNotFoundException with custom message. - * - * @param string the custom exception message - */ - public GroupNotFoundException(String string) {super(string);} } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/goal/InvalidChallengeDayException.java b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/goal/InvalidChallengeDayException.java index 29a060133f200c76d0fe3528afa76104ab14102f..a48be672b48f99bf5325899dd83186e61bc0d708 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/goal/InvalidChallengeDayException.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/goal/InvalidChallengeDayException.java @@ -3,17 +3,21 @@ package no.ntnu.idi.stud.savingsapp.exception.goal; /** * Exception thrown when attempting to choose an invalid challenge day. */ -public final class InvalidChallengeDayException extends RuntimeException{ +public final class InvalidChallengeDayException extends RuntimeException { - /** - * Constructs a InvalidChallengeDayException with default message. - */ - public InvalidChallengeDayException() { super("Invalid challenge day");} + /** + * Constructs a InvalidChallengeDayException with default message. + */ + public InvalidChallengeDayException() { + super("Invalid challenge day"); + } + + /** + * Constructs a InvalidChallengeDayException with custom message. + * @param string the custom exception message + */ + public InvalidChallengeDayException(String string) { + super(string); + } - /** - * Constructs a InvalidChallengeDayException with custom message. - * - * @param string the custom exception message - */ - public InvalidChallengeDayException(String string) {super(string);} } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/image/ImageNotFoundException.java b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/image/ImageNotFoundException.java index 5deadf1bd45c243ff6f7f8d5fc4daf283b9aa4bc..b9275bf725d573c03e08dc797647f12c0d56b553 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/image/ImageNotFoundException.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/image/ImageNotFoundException.java @@ -1,14 +1,16 @@ package no.ntnu.idi.stud.savingsapp.exception.image; /** - * Exception thrown when attempting to retrieve an image that does not exist in the system. + * Exception thrown when attempting to retrieve an image that does not exist in the + * system. */ public final class ImageNotFoundException extends RuntimeException { - /** - * Constructs a ImageNotFoundException with the default message. - */ - public ImageNotFoundException() { - super("Image not found"); - } + /** + * Constructs a ImageNotFoundException with the default message. + */ + public ImageNotFoundException() { + super("Image not found"); + } + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/notification/NotificationNotFoundException.java b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/notification/NotificationNotFoundException.java index f08cd22e528c5e8d3f5dce733728505c15a2cf4a..aa078de0e8a50b551bde8041496cb142aa7a15b0 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/notification/NotificationNotFoundException.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/notification/NotificationNotFoundException.java @@ -4,10 +4,12 @@ package no.ntnu.idi.stud.savingsapp.exception.notification; * Exception thrown when attempting to retrieve a Notification that does not exist. */ public class NotificationNotFoundException extends RuntimeException { - /** - * Constructs a NotificationNotFoundException with the default message. - */ - public NotificationNotFoundException() { - super("Notification is not found"); - } + + /** + * Constructs a NotificationNotFoundException with the default message. + */ + public NotificationNotFoundException() { + super("Notification is not found"); + } + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/question/QuestionTypeNotFoundException.java b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/question/QuestionTypeNotFoundException.java index 96e58378196effdb9dce2c71c1240cc56644e082..29156e037643b79039b906a13a1c362cde0e274a 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/question/QuestionTypeNotFoundException.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/question/QuestionTypeNotFoundException.java @@ -1,13 +1,16 @@ package no.ntnu.idi.stud.savingsapp.exception.question; /** - * Exception thrown when attempting to retrieve a question of a specific type that does not exist in the system. + * Exception thrown when attempting to retrieve a question of a specific type that does + * not exist in the system. */ public class QuestionTypeNotFoundException extends RuntimeException { - /** - * Constructs a QuestionTypeNotFoundException with the default message. - */ - public QuestionTypeNotFoundException(String type) { - super("Question for type '" + type + "' not found"); - } + + /** + * Constructs a QuestionTypeNotFoundException with the default message. + */ + public QuestionTypeNotFoundException(String type) { + super("Question for type '" + type + "' not found"); + } + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/user/EmailAlreadyExistsException.java b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/user/EmailAlreadyExistsException.java index 937d633164f552a761caf15ca6d66783c3406fd1..3986dd9650d9fa8ee061e68953f00cb952090874 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/user/EmailAlreadyExistsException.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/user/EmailAlreadyExistsException.java @@ -5,10 +5,11 @@ package no.ntnu.idi.stud.savingsapp.exception.user; */ public final class EmailAlreadyExistsException extends RuntimeException { - /** - * Constructs a UserAlreadyExistsException with the default message. - */ - public EmailAlreadyExistsException() { - super("Email already exists"); - } + /** + * Constructs a UserAlreadyExistsException with the default message. + */ + public EmailAlreadyExistsException() { + super("Email already exists"); + } + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/user/InvalidPasswordResetTokenException.java b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/user/InvalidPasswordResetTokenException.java index eda2f645163916fa24164bb0dad58a55eab46f6a..792a0c931f1617d66e25ae988c54c73053a9a50c 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/user/InvalidPasswordResetTokenException.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/user/InvalidPasswordResetTokenException.java @@ -5,10 +5,11 @@ package no.ntnu.idi.stud.savingsapp.exception.user; */ public final class InvalidPasswordResetTokenException extends RuntimeException { - /** - * Constructs a InvalidPasswordResetTokenException with the default message. - */ - public InvalidPasswordResetTokenException() { - super("Invalid token"); - } + /** + * Constructs a InvalidPasswordResetTokenException with the default message. + */ + public InvalidPasswordResetTokenException() { + super("Invalid token"); + } + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/user/PermissionDeniedException.java b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/user/PermissionDeniedException.java index 9d7d38922c3fede1064d2646cc170d357f86c8d5..cad40a6687f2ef7acfe169775446bad3f9f7ac0b 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/user/PermissionDeniedException.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/user/PermissionDeniedException.java @@ -5,10 +5,11 @@ package no.ntnu.idi.stud.savingsapp.exception.user; */ public final class PermissionDeniedException extends RuntimeException { - /** - * Constructs a PermissionDeniedException with the default message. - */ - public PermissionDeniedException() { - super("Permission denied"); - } + /** + * Constructs a PermissionDeniedException with the default message. + */ + public PermissionDeniedException() { + super("Permission denied"); + } + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/user/UserException.java b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/user/UserException.java index b4a804882c19fd48312c173fd6695106a3b2b392..93ab3e8ba5bf7fac257cf393ade75112dfbf48a0 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/user/UserException.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/user/UserException.java @@ -5,10 +5,11 @@ package no.ntnu.idi.stud.savingsapp.exception.user; */ public final class UserException extends RuntimeException { - /** - * Constructs a UserException with the default message. - */ - public UserException(String string) { - super(string); - } + /** + * Constructs a UserException with the default message. + */ + public UserException(String string) { + super(string); + } + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/user/UserNotFoundException.java b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/user/UserNotFoundException.java index b6e2a7ee19e6decde4471ece72d76d767c590adb..45cf350bb11f959831eef61e35e3f0a6f73be019 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/exception/user/UserNotFoundException.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/exception/user/UserNotFoundException.java @@ -5,17 +5,18 @@ package no.ntnu.idi.stud.savingsapp.exception.user; */ public final class UserNotFoundException extends RuntimeException { - /** - * Constructs a UserNotFoundException with the default message. - */ - public UserNotFoundException() { - super("User not found"); - } + /** + * Constructs a UserNotFoundException with the default message. + */ + public UserNotFoundException() { + super("User not found"); + } + + /** + * Constructs a UserNotFoundException with the default message. + */ + public UserNotFoundException(String string) { + super(string); + } - /** - * Constructs a UserNotFoundException with the default message. - */ - public UserNotFoundException(String string) { - super(string); - } } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/budget/Budget.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/budget/Budget.java index 56ea3bd26b7f6456c4a64785b99c0758a17723ce..20a64ca750a00643d33e89e7d36686fe065c8c1d 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/budget/Budget.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/budget/Budget.java @@ -1,6 +1,5 @@ package no.ntnu.idi.stud.savingsapp.model.budget; - import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; @@ -30,29 +29,30 @@ import org.hibernate.annotations.OnDeleteAction; @Table(name = "`budget`") public class Budget { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "budget_id") - private Long id; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "budget_id") + private Long id; + + @ManyToOne + @OnDelete(action = OnDeleteAction.CASCADE) + @JoinColumn(name = "user_id") + private User user; - @ManyToOne - @OnDelete(action = OnDeleteAction.CASCADE) - @JoinColumn(name = "user_id") - private User user; + @NonNull + @Column(name = "created_at", nullable = false) + private Timestamp createdAt; - @NonNull - @Column(name = "created_at", nullable = false) - private Timestamp createdAt; + @NonNull + @Column(name = "budget_name", nullable = false) + private String budgetName; - @NonNull - @Column(name = "budget_name", nullable = false) - private String budgetName; + @NonNull + @Column(name = "budget_amount", nullable = false) + private BigDecimal budgetAmount; - @NonNull - @Column(name = "budget_amount", nullable = false) - private BigDecimal budgetAmount; + @NonNull + @Column(name = "expense_amount", nullable = false) + private BigDecimal expenseAmount; - @NonNull - @Column(name = "expense_amount", nullable = false) - private BigDecimal expenseAmount; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/budget/Expense.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/budget/Expense.java index 94705ed6b8ad028e427710d5b8ab19df26433ea3..653fd3fcc650a709283eb5830ec827cd37593dd1 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/budget/Expense.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/budget/Expense.java @@ -26,21 +26,22 @@ import org.hibernate.annotations.OnDeleteAction; @Table(name = "`expense`") public class Expense { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "expense_id") - private Long id; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "expense_id") + private Long id; - @ManyToOne - @OnDelete(action = OnDeleteAction.CASCADE) - @JoinColumn(name = "budget_id") - private Budget budget; + @ManyToOne + @OnDelete(action = OnDeleteAction.CASCADE) + @JoinColumn(name = "budget_id") + private Budget budget; - @NonNull - @Column(name = "description", nullable = false) - private String description; + @NonNull + @Column(name = "description", nullable = false) + private String description; + + @NonNull + @Column(name = "amount", nullable = false) + private BigDecimal amount; - @NonNull - @Column(name = "amount", nullable = false) - private BigDecimal amount; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/configuration/ChallengeType.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/configuration/ChallengeType.java index 58376e175f3a059e90b0e0e1a26a0bb06eb88603..2c6545698ad6c711443834b5e1402b5086d85957 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/configuration/ChallengeType.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/configuration/ChallengeType.java @@ -5,20 +5,8 @@ package no.ntnu.idi.stud.savingsapp.model.configuration; */ public enum ChallengeType { - NO_COFFEE, - NO_CAR, - SHORTER_SHOWER, - SPEND_LESS_ON_FOOD, - BUY_USED_CLOTHES, - LESS_SHOPPING, - DROP_SUBSCRIPTION, - SELL_SOMETHING, - BUY_USED, - EAT_PACKED_LUNCH, - STOP_SHOPPING, - ZERO_SPENDING, - RENT_YOUR_STUFF, - MEATLESS, - SCREEN_TIME_LIMIT, - UNPLUGGED_ENTERTAINMENT, + NO_COFFEE, NO_CAR, SHORTER_SHOWER, SPEND_LESS_ON_FOOD, BUY_USED_CLOTHES, LESS_SHOPPING, DROP_SUBSCRIPTION, + SELL_SOMETHING, BUY_USED, EAT_PACKED_LUNCH, STOP_SHOPPING, ZERO_SPENDING, RENT_YOUR_STUFF, MEATLESS, + SCREEN_TIME_LIMIT, UNPLUGGED_ENTERTAINMENT, + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/configuration/Commitment.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/configuration/Commitment.java index e582b44aa3c19fa3b16fd88847226e1fcadcc8ec..4d63da22dc8f88653e4d96e109bde956c2a36bec 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/configuration/Commitment.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/configuration/Commitment.java @@ -7,21 +7,20 @@ import java.util.Random; */ public enum Commitment { - LITTLE(0.33), - SOME(0.66), - MUCH(1); + LITTLE(0.33), SOME(0.66), MUCH(1); - private static final Random random = new Random(); + private static final Random random = new Random(); - private final double percentage; + private final double percentage; - Commitment(double percentage) { - this.percentage = percentage; - } + Commitment(double percentage) { + this.percentage = percentage; + } + + public int getCheckDays(int totalDays) { + double p = random.nextDouble(percentage - 0.2) + 0.2; + System.out.println("p: " + p); + return (int) (p * totalDays); + } - public int getCheckDays(int totalDays) { - double p = random.nextDouble(percentage - 0.2) + 0.2; - System.out.println("p: " + p); - return (int) (p * totalDays); - } } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/configuration/Configuration.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/configuration/Configuration.java index ffc4e6bc74ce50495fdf646db928e4360fa97ccc..9ca41a165a28839451105d74d3398b37bd085ba8 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/configuration/Configuration.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/configuration/Configuration.java @@ -19,24 +19,25 @@ import no.ntnu.idi.stud.savingsapp.model.user.User; @Table(name = "configuration") public class Configuration { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "configuration_id") - private Long id; - - @NonNull - @Enumerated(EnumType.STRING) - @Column(name = "commitment", nullable = false) - private Commitment commitment; - - @NonNull - @Enumerated(EnumType.STRING) - @Column(name = "experience", nullable = false) - private Experience experience; - - @ElementCollection(targetClass = ChallengeType.class) - @JoinTable(name = "configuration_challenges", joinColumns = @JoinColumn(name = "configuration_id")) - @Column(name = "challenge_type", nullable = false) - @Enumerated(EnumType.STRING) - private List<ChallengeType> challengeTypes; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "configuration_id") + private Long id; + + @NonNull + @Enumerated(EnumType.STRING) + @Column(name = "commitment", nullable = false) + private Commitment commitment; + + @NonNull + @Enumerated(EnumType.STRING) + @Column(name = "experience", nullable = false) + private Experience experience; + + @ElementCollection(targetClass = ChallengeType.class) + @JoinTable(name = "configuration_challenges", joinColumns = @JoinColumn(name = "configuration_id")) + @Column(name = "challenge_type", nullable = false) + @Enumerated(EnumType.STRING) + private List<ChallengeType> challengeTypes; + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/configuration/Experience.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/configuration/Experience.java index fa7a9189d85ff7415b6d2032d16c36195d1e7674..d582114786b5b00ec19a6d5b4d5567654dcbaabc 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/configuration/Experience.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/configuration/Experience.java @@ -5,7 +5,6 @@ package no.ntnu.idi.stud.savingsapp.model.configuration; */ public enum Experience { - NONE, - SOME, - EXPERT + NONE, SOME, EXPERT + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/goal/Challenge.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/goal/Challenge.java index 1b0ef349ae3bbe219159de8fee7b001e0d9f6b16..d3e815745b9dd90b22c587f5c6fe9e0adf836c36 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/goal/Challenge.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/goal/Challenge.java @@ -20,36 +20,37 @@ import lombok.NonNull; @Table(name = "challenge") public class Challenge { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "challenge_id") - private Long id; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "challenge_id") + private Long id; - @Column(name = "potential_amount", nullable = false) - private BigDecimal potentialAmount; + @Column(name = "potential_amount", nullable = false) + private BigDecimal potentialAmount; - @Column(name = "points", nullable = false) - private int points; + @Column(name = "points", nullable = false) + private int points; - @Column(name = "check_days", nullable = false) - private int checkDays; + @Column(name = "check_days", nullable = false) + private int checkDays; - @Column(name = "total_days", nullable = false) - private int totalDays; + @Column(name = "total_days", nullable = false) + private int totalDays; - @NonNull - @Column(name = "start_date", nullable = false) - private Timestamp startDate; + @NonNull + @Column(name = "start_date", nullable = false) + private Timestamp startDate; - @NonNull - @Column(name = "end_date", nullable = false) - private Timestamp endDate; + @NonNull + @Column(name = "end_date", nullable = false) + private Timestamp endDate; - @ManyToOne(cascade = CascadeType.ALL) - @JoinColumn (name = "challenge_template_id") - private ChallengeTemplate template; + @ManyToOne(cascade = CascadeType.ALL) + @JoinColumn(name = "challenge_template_id") + private ChallengeTemplate template; + + @OneToMany(cascade = CascadeType.ALL) + @JoinColumn(name = "challenge_id") + private List<Progress> progressList; - @OneToMany(cascade = CascadeType.ALL) - @JoinColumn(name = "challenge_id") - private List<Progress> progressList; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/goal/ChallengeTemplate.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/goal/ChallengeTemplate.java index b71a09c987ffe42f5375713fcdec4a273ac08081..55e3495399b669fac5ca8c3e2eb478d14de5b563 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/goal/ChallengeTemplate.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/goal/ChallengeTemplate.java @@ -26,24 +26,25 @@ import java.math.BigDecimal; @Table(name = "challenge_template") public class ChallengeTemplate { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "challenge_template_id") - private Long id; - - @NonNull - @Column(name = "challenge_text", nullable = false) - private String text; - - @NonNull - @Column(name = "challenge_name", nullable = false) - private String challengeName; - - @Column(name = "challenge_amount", nullable = false) - private BigDecimal amount; - - @NonNull - @Enumerated(EnumType.STRING) - @Column(name = "challenge_type", nullable = false) - private ChallengeType challengeType; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "challenge_template_id") + private Long id; + + @NonNull + @Column(name = "challenge_text", nullable = false) + private String text; + + @NonNull + @Column(name = "challenge_name", nullable = false) + private String challengeName; + + @Column(name = "challenge_amount", nullable = false) + private BigDecimal amount; + + @NonNull + @Enumerated(EnumType.STRING) + @Column(name = "challenge_type", nullable = false) + private ChallengeType challengeType; + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/goal/DifficultyLevel.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/goal/DifficultyLevel.java index c9956760dba105a0efea28f2f9147fa18ab2c615..02e8b6cfc4fb98adf60289968675223c124ebc7b 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/goal/DifficultyLevel.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/goal/DifficultyLevel.java @@ -25,16 +25,17 @@ import lombok.NonNull; @Table(name = "difficulty_level") public class DifficultyLevel { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "difficulty_level_id") - private Long id; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "difficulty_level_id") + private Long id; - @NonNull - @Column(name = "difficulty_level_text", nullable = false) - private String diffucultyLevelText; + @NonNull + @Column(name = "difficulty_level_text", nullable = false) + private String diffucultyLevelText; + + @OneToMany(cascade = CascadeType.ALL) + @JoinColumn(name = "difficulty_level_id") + private List<Challenge> challengeList; - @OneToMany(cascade = CascadeType.ALL) - @JoinColumn(name = "difficulty_level_id") - private List<Challenge> challengeList; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/goal/Goal.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/goal/Goal.java index 39c35201bc6e293911fe98ae9d28cddcf4b09693..7545c5b731e33e294d77f1a00d4f526adee242b6 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/goal/Goal.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/goal/Goal.java @@ -12,8 +12,8 @@ import lombok.NonNull; import no.ntnu.idi.stud.savingsapp.model.user.User; /** - * Represents a saving goal. - * This entity has a list of generated {@link Challenge SavingChallanges} associated with it. + * Represents a saving goal. This entity has a list of generated {@link Challenge + * SavingChallanges} associated with it. */ @Data @AllArgsConstructor @@ -22,37 +22,37 @@ import no.ntnu.idi.stud.savingsapp.model.user.User; @Table(name = "goal") public class Goal { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "goal_id") - private Long id; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "goal_id") + private Long id; - @NonNull - @Column(name = "goal_name", nullable = false) - private String name; + @NonNull + @Column(name = "goal_name", nullable = false) + private String name; - @NonNull - @Column(name = "goal_description", nullable = false) - private String description; + @NonNull + @Column(name = "goal_description", nullable = false) + private String description; - @Column(name = "target_amount", nullable = false) - private int targetAmount; + @Column(name = "target_amount", nullable = false) + private int targetAmount; - @NonNull - @Column(name = "target_date", nullable = false) - private Timestamp targetDate; + @NonNull + @Column(name = "target_date", nullable = false) + private Timestamp targetDate; - @NonNull - @Column(name = "created_at", nullable = false) - private Timestamp createdAt; + @NonNull + @Column(name = "created_at", nullable = false) + private Timestamp createdAt; - @OneToMany(cascade = CascadeType.ALL) - @JoinTable(name = "goal_challenge", - joinColumns = @JoinColumn(name = "goal_id"), - inverseJoinColumns = @JoinColumn(name = "challenge_id")) - private List<Challenge> challenges; + @OneToMany(cascade = CascadeType.ALL) + @JoinTable(name = "goal_challenge", joinColumns = @JoinColumn(name = "goal_id"), + inverseJoinColumns = @JoinColumn(name = "challenge_id")) + private List<Challenge> challenges; + + @ManyToOne + @JoinColumn(name = "user_id") + private User user; - @ManyToOne - @JoinColumn(name = "user_id") - private User user; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/goal/Group.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/goal/Group.java index 46a9403a3d8718e9bccb1f4baea946683e3576c3..6c2be121513acf94f4b0a201bf20d171c75a7ca8 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/goal/Group.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/goal/Group.java @@ -17,16 +17,17 @@ import java.util.List; @Table(name = "group") public class Group { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "group_id") - private Long id; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "group_id") + private Long id; - @OneToMany - @Column(name = "goals") - private List<Goal> goals; + @OneToMany + @Column(name = "goals") + private List<Goal> goals; + + @ManyToOne + @JoinColumn(name = "user_id") + private User creator; - @ManyToOne - @JoinColumn(name = "user_id") - private User creator; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/goal/Progress.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/goal/Progress.java index 29df38033be0b05005b622d4e8c6344403f45679..632bccac89aba1fbd7b7b70a8c7b503113aa73f3 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/goal/Progress.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/goal/Progress.java @@ -15,9 +15,8 @@ import lombok.NoArgsConstructor; import lombok.NonNull; /** - * Represents the progress of daily challenges. - * This entity keeps track of when challenges are completed, and whihc day they need to be - * completed at. + * Represents the progress of daily challenges. This entity keeps track of when challenges + * are completed, and whihc day they need to be completed at. */ @Data @NoArgsConstructor @@ -26,18 +25,19 @@ import lombok.NonNull; @Table(name = "progress") public class Progress { - @Id() - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "progess_id") - private Long id; + @Id() + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "progess_id") + private Long id; - @Column(name = "challenge_day", nullable = false) - private int day; + @Column(name = "challenge_day", nullable = false) + private int day; - @Column(name = "progress_amount", nullable = false) - private BigDecimal amount; + @Column(name = "progress_amount", nullable = false) + private BigDecimal amount; + + @NonNull + @Column(name = "completed_at", nullable = false) + private Timestamp completedAt; - @NonNull - @Column(name = "completed_at", nullable = false) - private Timestamp completedAt; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/image/Image.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/image/Image.java index 466c31c4905c64f32e3d17bd088b4161a6c5faa0..7269bc3c244ee6deb5e96b8a76982577f8efd9c0 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/image/Image.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/image/Image.java @@ -16,16 +16,17 @@ import lombok.NonNull; @Table(name = "image") public class Image { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "image_id") - private Long id; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "image_id") + private Long id; - @NonNull - @Column(name = "name", nullable = false) - private String name; + @NonNull + @Column(name = "name", nullable = false) + private String name; + + @Lob + @Column(name = "data", length = Integer.MAX_VALUE) + private byte[] data; - @Lob - @Column(name = "data", length = Integer.MAX_VALUE) - private byte[] data; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/leaderboard/Leaderboard.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/leaderboard/Leaderboard.java index 1d6b4a3803407ddb35a8dbb8b76301a2e2065fd1..1e62720d2281299d1bbe6925d45873e34830e55b 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/leaderboard/Leaderboard.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/leaderboard/Leaderboard.java @@ -13,7 +13,11 @@ import lombok.NoArgsConstructor; @NoArgsConstructor @AllArgsConstructor public class Leaderboard { - private List<LeaderboardEntry> entries; - private LeaderboardType type; - private LeaderboardFilter filter; + + private List<LeaderboardEntry> entries; + + private LeaderboardType type; + + private LeaderboardFilter filter; + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/leaderboard/LeaderboardEntry.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/leaderboard/LeaderboardEntry.java index b5eccb1050ce2c7fde55afa87fee81f2010cca17..5a3b99a6d7fb56c4c2c2fe4776bfcc1a7ff26c82 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/leaderboard/LeaderboardEntry.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/leaderboard/LeaderboardEntry.java @@ -12,7 +12,11 @@ import no.ntnu.idi.stud.savingsapp.model.user.User; @NoArgsConstructor @AllArgsConstructor public class LeaderboardEntry { - private User user; - private int score; - private long rank; + + private User user; + + private int score; + + private long rank; + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/leaderboard/LeaderboardFilter.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/leaderboard/LeaderboardFilter.java index 25ceb402f744f8ebcfd7817248ede7caf1f0752e..493e2a11ef889febaffe9c13ff8380a76855a2c3 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/leaderboard/LeaderboardFilter.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/leaderboard/LeaderboardFilter.java @@ -5,6 +5,6 @@ package no.ntnu.idi.stud.savingsapp.model.leaderboard; */ public enum LeaderboardFilter { - GLOBAL, - FRIENDS + GLOBAL, FRIENDS + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/leaderboard/LeaderboardType.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/leaderboard/LeaderboardType.java index 04b92f66e6afa169609a50f1b82381d1f2db0230..457a7a4388ab73d17d222bfc637e12456a396e05 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/leaderboard/LeaderboardType.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/leaderboard/LeaderboardType.java @@ -5,7 +5,6 @@ package no.ntnu.idi.stud.savingsapp.model.leaderboard; */ public enum LeaderboardType { - TOTAL_POINTS, - CURRENT_STREAK, - TOP_STREAK + TOTAL_POINTS, CURRENT_STREAK, TOP_STREAK + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/notification/Notification.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/notification/Notification.java index 0c99427bf514a1d589e865e3d27aebac8b234b05..93f15659bd0c9f7b6677f59a3822a59e891eb59e 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/notification/Notification.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/notification/Notification.java @@ -29,29 +29,30 @@ import org.hibernate.annotations.OnDeleteAction; @Table(name = "notification") public class Notification { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "notification_id") - private Long id; - - @ManyToOne - @OnDelete(action = OnDeleteAction.CASCADE) - @JoinColumn(name = "user_id") - private User user; - - @NonNull - @Column(name = "message", nullable = false) - private String message; - - @NonNull - @Column(name = "unread", nullable = false) - private boolean unread; - - @NonNull - @Enumerated(EnumType.STRING) - @Column(name = "notification_type", nullable = false) - private NotificationType notificationType; - - @Column(name = "created_at") - private Timestamp createdAt; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "notification_id") + private Long id; + + @ManyToOne + @OnDelete(action = OnDeleteAction.CASCADE) + @JoinColumn(name = "user_id") + private User user; + + @NonNull + @Column(name = "message", nullable = false) + private String message; + + @NonNull + @Column(name = "unread", nullable = false) + private boolean unread; + + @NonNull + @Enumerated(EnumType.STRING) + @Column(name = "notification_type", nullable = false) + private NotificationType notificationType; + + @Column(name = "created_at") + private Timestamp createdAt; + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/notification/NotificationType.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/notification/NotificationType.java index debae242ec8629749a7511df9c2e72065a301a24..5e746edc5b7948248aa9f69a547f53a1e504ff45 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/notification/NotificationType.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/notification/NotificationType.java @@ -5,8 +5,6 @@ package no.ntnu.idi.stud.savingsapp.model.notification; */ public enum NotificationType { - BADGE, - FRIEND_REQUEST, - COMPLETED_GOAL + BADGE, FRIEND_REQUEST, COMPLETED_GOAL } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/store/Inventory.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/store/Inventory.java index ccec0bebf9cd720a8749c94125cf563f8c20d6b5..a615a472109afb226a26d698f3ba4bc403033860 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/store/Inventory.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/store/Inventory.java @@ -7,7 +7,6 @@ import jakarta.persistence.EmbeddedId; import jakarta.persistence.Entity; import jakarta.persistence.Table; - import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -21,9 +20,11 @@ import lombok.NoArgsConstructor; @Entity @Table(name = "inventory") public class Inventory { - @EmbeddedId - private InventoryId inventoryId; - @Column(name = "bought_at") - private Timestamp boughtAt; + @EmbeddedId + private InventoryId inventoryId; + + @Column(name = "bought_at") + private Timestamp boughtAt; + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/store/InventoryId.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/store/InventoryId.java index f7bb8a1bbec8e041635a463ffe097991a501fd3c..8180d71decef91496c1be86b31b2b213cac15869 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/store/InventoryId.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/store/InventoryId.java @@ -1,4 +1,5 @@ package no.ntnu.idi.stud.savingsapp.model.store; + import jakarta.persistence.Embeddable; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; @@ -16,11 +17,13 @@ import no.ntnu.idi.stud.savingsapp.model.user.User; @AllArgsConstructor @Embeddable public class InventoryId implements Serializable { - @ManyToOne - @JoinColumn(name = "item_id") - private Item item; - @ManyToOne - @JoinColumn(name = "user_id") - private User user; + @ManyToOne + @JoinColumn(name = "item_id") + private Item item; + + @ManyToOne + @JoinColumn(name = "user_id") + private User user; + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/store/Item.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/store/Item.java index fb191a21df74cbe8163e4d8d806cd9d45984c40a..8304dccf0cb1b950661cb54063df3bd47da1211f 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/store/Item.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/store/Item.java @@ -9,7 +9,6 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; - import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -24,19 +23,20 @@ import no.ntnu.idi.stud.savingsapp.model.image.Image; @Entity @Table(name = "item") public class Item { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "item_id") - private Long id; - @Column(name = "item_name") - private String itemName; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "item_id") + private Long id; - @Column(name = "price") - private int price; + @Column(name = "item_name") + private String itemName; - @ManyToOne - @JoinColumn(name = "image_id") - private Image image; -} + @Column(name = "price") + private int price; + @ManyToOne + @JoinColumn(name = "image_id") + private Image image; + +} diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/Badge.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/Badge.java index c5882a9e4914b33b813eade0d05d4ed6697e3967..202c10f28e7e49acd27ca31d9df8cb85bf65b53a 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/Badge.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/Badge.java @@ -27,24 +27,25 @@ import no.ntnu.idi.stud.savingsapp.model.image.Image; @Table(name = "badge") public class Badge { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "badge_id") - private Long id; - - @NonNull - @Column(name = "badge_name", nullable = false) - private String badgeName; - - @NonNull - @Column(name = "criteria", nullable = false) - private int criteria; - - @OneToOne - @JoinColumn(name = "image_id") - private Image image; - - @OneToMany(cascade = CascadeType.ALL) - @JoinColumn(name = "badge_id") - private List<BadgeUser> badgeUserList; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "badge_id") + private Long id; + + @NonNull + @Column(name = "badge_name", nullable = false) + private String badgeName; + + @NonNull + @Column(name = "criteria", nullable = false) + private int criteria; + + @OneToOne + @JoinColumn(name = "image_id") + private Image image; + + @OneToMany(cascade = CascadeType.ALL) + @JoinColumn(name = "badge_id") + private List<BadgeUser> badgeUserList; + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/BadgeUser.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/BadgeUser.java index b5c0637d9622d6aead6e46e9aa500d64ae7207eb..f35d5b874baa8f0b913635093c8af0291d92f4d5 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/BadgeUser.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/BadgeUser.java @@ -19,9 +19,10 @@ import lombok.NoArgsConstructor; @Table(name = "badge_user") public class BadgeUser { - @EmbeddedId - private BadgeUserId badgeUserId; + @EmbeddedId + private BadgeUserId badgeUserId; + + @Column(name = "earned_at") + private Timestamp earnedAt; - @Column(name = "earned_at") - private Timestamp earnedAt; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/BadgeUserId.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/BadgeUserId.java index 1ca13338b71aa2c843e77313d8850ca84271094b..632e5efb10b68ba36ef8619caf85e8ec473c5151 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/BadgeUserId.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/BadgeUserId.java @@ -17,13 +17,12 @@ import lombok.NoArgsConstructor; @Embeddable public class BadgeUserId implements Serializable { - @ManyToOne - @JoinColumn(name = "badge_id") - private Badge badge; - - @ManyToOne - @JoinColumn(name = "user_id") - private User user; + @ManyToOne + @JoinColumn(name = "badge_id") + private Badge badge; + @ManyToOne + @JoinColumn(name = "user_id") + private User user; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/Feedback.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/Feedback.java index 845b85e52efc53c828fb83fb103c3a78be9a3048..9ce1e47a764b19c81578180a4d48334e03698639 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/Feedback.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/Feedback.java @@ -1,4 +1,5 @@ package no.ntnu.idi.stud.savingsapp.model.user; + import jakarta.persistence.*; import java.sql.Timestamp; import lombok.*; @@ -14,20 +15,21 @@ import lombok.*; @Table(name = "feedback") public class Feedback { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "feedback_id") - private long id; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "feedback_id") + private long id; + + @NonNull + @Column(name = "email", nullable = false) + private String email; - @NonNull - @Column(name = "email", nullable = false) - private String email; + @NonNull + @Column(name = "message", nullable = false) + private String message; - @NonNull - @Column(name = "message", nullable = false) - private String message; + @NonNull + @Column(name = "created_at", nullable = false) + private Timestamp createdAt; - @NonNull - @Column(name = "created_at", nullable = false) - private Timestamp createdAt; } \ No newline at end of file diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/Friend.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/Friend.java index 68773c9031830e2b69c498a7ec64120b15009883..62bf33a604b0556c2a6d5f7fc56c2b713ce35a5d 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/Friend.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/Friend.java @@ -20,13 +20,14 @@ import lombok.NonNull; @Table(name = "friend") public class Friend { - @NonNull - @EmbeddedId - private FriendId id; + @NonNull + @EmbeddedId + private FriendId id; - @Column(name = "pending", nullable = false) - private boolean pending; + @Column(name = "pending", nullable = false) + private boolean pending; + + @Column(name = "created_at") + private Timestamp createdAt; - @Column(name = "created_at") - private Timestamp createdAt; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/FriendId.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/FriendId.java index adf6311a563a9c5f8e99b71137334621836ec6e8..e687091ed130c33cf49ed14a75d5f3c1c6e802a3 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/FriendId.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/FriendId.java @@ -18,13 +18,14 @@ import lombok.NonNull; @Embeddable public class FriendId implements Serializable { - @NonNull - @ManyToOne - @JoinColumn(name = "user_id") - private User user; + @NonNull + @ManyToOne + @JoinColumn(name = "user_id") + private User user; + + @NonNull + @ManyToOne + @JoinColumn(name = "friend_id") + private User friend; - @NonNull - @ManyToOne - @JoinColumn(name = "friend_id") - private User friend; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/PasswordResetToken.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/PasswordResetToken.java index 7c1800f9557b609b2ca2c0a9108ee95e4cd77b3f..57c76582e6c79fa84cdf37f89b3d18bb5f04446a 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/PasswordResetToken.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/PasswordResetToken.java @@ -18,20 +18,21 @@ import java.sql.Timestamp; @Table(name = "password_reset_token") public class PasswordResetToken { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - private Long id; - - @NonNull - @ManyToOne - @JoinColumn(name = "user_id") - private User user; - - @NonNull - @Column(name = "token", unique = true) - private String token; - - @NonNull - @Column(name = "created_at") - private Timestamp createdAt; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @NonNull + @ManyToOne + @JoinColumn(name = "user_id") + private User user; + + @NonNull + @Column(name = "token", unique = true) + private String token; + + @NonNull + @Column(name = "created_at") + private Timestamp createdAt; + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/Point.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/Point.java index d74ecd0a9f162835250f977cb7da57d70e6608b4..92cbad707395cb041bbbee208436d456491ea746 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/Point.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/Point.java @@ -20,14 +20,15 @@ import lombok.NoArgsConstructor; @Table(name = "point") public class Point { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "point_id") - private Long id; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "point_id") + private Long id; - @Column(name = "current_points", nullable = false) - private int currentPoints; + @Column(name = "current_points", nullable = false) + private int currentPoints; + + @Column(name = "total_earned_points", nullable = false) + private int totalEarnedPoints; - @Column(name = "total_earned_points", nullable = false) - private int totalEarnedPoints; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/ProfilePicture.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/ProfilePicture.java index 0e42f8cd64a6a2e7222ba01fb16cebed25a802f4..22e73afd478c2f5da7af56373e6f5e02c4c18e8a 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/ProfilePicture.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/ProfilePicture.java @@ -21,17 +21,16 @@ import lombok.NonNull; @Table(name = "profile_picture") public class ProfilePicture { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "profile_picture_id") - private Long id; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "profile_picture_id") + private Long id; - @NonNull - @Column(name = "description", nullable = false) - private String description; - - @Column(name = "price", nullable = false) - private int price; + @NonNull + @Column(name = "description", nullable = false) + private String description; + @Column(name = "price", nullable = false) + private int price; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/ProfilePictureUser.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/ProfilePictureUser.java index 833454a53f5d4652d42b143a5349ad37fa80a9f5..febee6563c88533a524046e18f953efd5d147b2f 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/ProfilePictureUser.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/ProfilePictureUser.java @@ -22,18 +22,19 @@ import lombok.NoArgsConstructor; @Table(name = "profile_picture_user") public class ProfilePictureUser { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "profile_picture_user_id") - private Long id; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "profile_picture_user_id") + private Long id; - @ManyToOne - @JoinColumn(name = "user_id") - private User user; + @ManyToOne + @JoinColumn(name = "user_id") + private User user; - @ManyToOne - @JoinColumn(name = "profile_picture_id") - private ProfilePicture profilePicture; + @ManyToOne + @JoinColumn(name = "profile_picture_id") + private ProfilePicture profilePicture; + + private boolean inUse; - private boolean inUse; } \ No newline at end of file diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/Role.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/Role.java index 0e3f2be93e7ffc4021ed68632350d5a57fa981e7..00ec4e177ef3edcd7e6575e810a4352eccd0d87b 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/Role.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/Role.java @@ -5,7 +5,8 @@ package no.ntnu.idi.stud.savingsapp.model.user; */ public enum Role { - USER, + USER, + + ADMIN - ADMIN } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/SearchFilter.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/SearchFilter.java index 377ca799162e171af43a2b2062aa4d10d81f4c48..62acb8aad109f02530d7899fc3b4f229a285c36d 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/SearchFilter.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/SearchFilter.java @@ -4,6 +4,7 @@ package no.ntnu.idi.stud.savingsapp.model.user; * Enum representing the search filter. */ public enum SearchFilter { - NON_FRIENDS, - FRIENDS + + NON_FRIENDS, FRIENDS + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/Streak.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/Streak.java index b7bc817e1052cc54c3856c68e6cf1aa2ff9d31d1..3844bc94b5149a899f3475eff4e4fa2b309b2c4c 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/Streak.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/Streak.java @@ -22,30 +22,31 @@ import lombok.NonNull; @Table(name = "streak") public class Streak { - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "streak_id") - private Long id; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "streak_id") + private Long id; - @Column(name = "current_streak", nullable = false) - private int currentStreak; + @Column(name = "current_streak", nullable = false) + private int currentStreak; - @NonNull - @Column(name = "current_streak_created_at", nullable = false) - private Timestamp currentStreakCreatedAt; + @NonNull + @Column(name = "current_streak_created_at", nullable = false) + private Timestamp currentStreakCreatedAt; - @NonNull - @Column(name = "current_streak_updated_at", nullable = false) - private Timestamp currentStreakUpdatedAt; + @NonNull + @Column(name = "current_streak_updated_at", nullable = false) + private Timestamp currentStreakUpdatedAt; - @Column(name = "highest_streak", nullable = false) - private int highestStreak; + @Column(name = "highest_streak", nullable = false) + private int highestStreak; - @NonNull - @Column(name = "highest_streak_created_at", nullable = false) - private Timestamp highestStreakCreatedAt; + @NonNull + @Column(name = "highest_streak_created_at", nullable = false) + private Timestamp highestStreakCreatedAt; + + @NonNull + @Column(name = "highest_streak_ended_at") + private Timestamp highestStreakEndedAt; - @NonNull - @Column(name = "highest_streak_ended_at") - private Timestamp highestStreakEndedAt; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/SubscriptionLevel.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/SubscriptionLevel.java index 2a8a76f71ac1b2c6a8881be89e406ffdb72eb01b..6e9267f26cc525bff1cefd28696dec663ba94fe2 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/SubscriptionLevel.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/SubscriptionLevel.java @@ -4,7 +4,7 @@ package no.ntnu.idi.stud.savingsapp.model.user; * Enum representing the type of subscription level. */ public enum SubscriptionLevel { - DEFAULT, - PREMIUM, - NO_ADS + + DEFAULT, PREMIUM, NO_ADS + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/User.java b/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/User.java index feef7f23c34d123853c5d4f957e1e284ed9e966f..15a3ff168e2ede8b2b93bf46adfde8609e0645de 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/User.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/model/user/User.java @@ -14,7 +14,6 @@ import jakarta.persistence.ManyToMany; import jakarta.persistence.OneToOne; import jakarta.persistence.Table; - import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -31,148 +30,143 @@ import java.util.Collection; import java.util.List; /** - * Represents a user in the system. - * This class implements the UserDetails interface, providing the necessary information for - * Spring Security to authenticate and authorize users and for use in testing. + * Represents a user in the system. This class implements the UserDetails interface, + * providing the necessary information for Spring Security to authenticate and authorize + * users and for use in testing. */ @Data @AllArgsConstructor @NoArgsConstructor @Entity @Table(name = "`user`") -public class User implements UserDetails{ - - @Id - @GeneratedValue(strategy = GenerationType.IDENTITY) - @Column(name = "user_id") - private Long id; - - @NonNull - @Column(name = "first_name", nullable = false) - private String firstName; - - @NonNull - @Column(name = "last_name", nullable = false) - private String lastName; - - @NonNull - @Column(name = "email", unique = true) - private String email; - - @Column(name = "profile_image") - private Long profileImage; - - @Column(name = "banner_image") - private Long bannerImage; - - @Column(name = "checking_account_bban") - private Long checkingAccountBBAN; - - @Column(name = "savings_account_bban") - private Long savingsAccountBBAN; - - @NonNull - @Column(name = "password") - private String password; - - @Column(name = "bankid_sub", unique = true) - private String bankIdSub; - - @NonNull - @Column(name = "created_at", nullable = false) - private Timestamp createdAt; - - @NonNull - @Enumerated(EnumType.STRING) - @Column(name = "role", nullable = false) - private Role role; - - @ManyToMany - @JoinTable(name = "badge_user", - joinColumns = @JoinColumn(name = "user_id"), - inverseJoinColumns = @JoinColumn(name = "badge_id")) - private List<Badge> badges; - - @ManyToMany - @JoinTable(name = "inventory", - joinColumns = @JoinColumn(name = "user_id"), - inverseJoinColumns = @JoinColumn(name = "item_id")) - private List<Item> items; - - @OneToOne - @JoinColumn(name = "point_id") - private Point point; - - @OneToOne - @JoinColumn(name = "streak_id") - private Streak streak; - - @OneToOne(cascade = CascadeType.ALL) - @JoinColumn(name = "configuration_id") - private Configuration configuration; - - @Enumerated(EnumType.STRING) - @Column(name = "subscription_level", nullable = false) - private SubscriptionLevel subscriptionLevel = SubscriptionLevel.DEFAULT; - - /** - * Get the authorities granted to the user. - * - * @return A list of GrantedAuthority objects representing the authorities granted to the user. - */ - @Override - public Collection<? extends GrantedAuthority> getAuthorities() { - return List.of(new SimpleGrantedAuthority(role.name())); - } - - /** - * Get a unique representation of the user. - * This method uses the email as the username. - * - * @return The email of the email of the user. - */ - @Override - public String getUsername() { - return this.email; - } - - /** - * Indicates whether the user's account has expired. - * - * @return true if the user's account is valid (i.e., non-expired), false otherwise. - */ - @Override - public boolean isAccountNonExpired() { - return true; - } - - /** - * Indicates whether the user is locked or unlocked. - * - * @return true if the user is not locked, false otherwise. - */ - @Override - public boolean isAccountNonLocked() { - return true; - } - - /** - * Indicates whether the user's credentials (password) has expired. - * - * @return true if the user's credentials are valid (i.e., non-expired), false otherwise. - */ - @Override - public boolean isCredentialsNonExpired() { - return true; - } - - /** - * Indicates whether the user is enabled or disabled. - * - * @return true if the user is enabled, false otherwise. - */ - @Override - public boolean isEnabled() { - return true; - } +public class User implements UserDetails { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "user_id") + private Long id; + + @NonNull + @Column(name = "first_name", nullable = false) + private String firstName; + + @NonNull + @Column(name = "last_name", nullable = false) + private String lastName; + + @NonNull + @Column(name = "email", unique = true) + private String email; + + @Column(name = "profile_image") + private Long profileImage; + + @Column(name = "banner_image") + private Long bannerImage; + + @Column(name = "checking_account_bban") + private Long checkingAccountBBAN; + + @Column(name = "savings_account_bban") + private Long savingsAccountBBAN; + + @NonNull + @Column(name = "password") + private String password; + + @Column(name = "bankid_sub", unique = true) + private String bankIdSub; + + @NonNull + @Column(name = "created_at", nullable = false) + private Timestamp createdAt; + + @NonNull + @Enumerated(EnumType.STRING) + @Column(name = "role", nullable = false) + private Role role; + + @ManyToMany + @JoinTable(name = "badge_user", joinColumns = @JoinColumn(name = "user_id"), + inverseJoinColumns = @JoinColumn(name = "badge_id")) + private List<Badge> badges; + + @ManyToMany + @JoinTable(name = "inventory", joinColumns = @JoinColumn(name = "user_id"), + inverseJoinColumns = @JoinColumn(name = "item_id")) + private List<Item> items; + + @OneToOne + @JoinColumn(name = "point_id") + private Point point; + + @OneToOne + @JoinColumn(name = "streak_id") + private Streak streak; + + @OneToOne(cascade = CascadeType.ALL) + @JoinColumn(name = "configuration_id") + private Configuration configuration; + + @Enumerated(EnumType.STRING) + @Column(name = "subscription_level", nullable = false) + private SubscriptionLevel subscriptionLevel = SubscriptionLevel.DEFAULT; + + /** + * Get the authorities granted to the user. + * @return A list of GrantedAuthority objects representing the authorities granted to + * the user. + */ + @Override + public Collection<? extends GrantedAuthority> getAuthorities() { + return List.of(new SimpleGrantedAuthority(role.name())); + } + + /** + * Get a unique representation of the user. This method uses the email as the + * username. + * @return The email of the email of the user. + */ + @Override + public String getUsername() { + return this.email; + } + + /** + * Indicates whether the user's account has expired. + * @return true if the user's account is valid (i.e., non-expired), false otherwise. + */ + @Override + public boolean isAccountNonExpired() { + return true; + } + + /** + * Indicates whether the user is locked or unlocked. + * @return true if the user is not locked, false otherwise. + */ + @Override + public boolean isAccountNonLocked() { + return true; + } + + /** + * Indicates whether the user's credentials (password) has expired. + * @return true if the user's credentials are valid (i.e., non-expired), false + * otherwise. + */ + @Override + public boolean isCredentialsNonExpired() { + return true; + } + + /** + * Indicates whether the user is enabled or disabled. + * @return true if the user is enabled, false otherwise. + */ + @Override + public boolean isEnabled() { + return true; + } + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/properties/TokenProperties.java b/src/main/java/no/ntnu/idi/stud/savingsapp/properties/TokenProperties.java index 1f9405ef846a2e8e171d2b29b4b71b0b5870c92c..a76de740ac30b131450acc8a9c14db5ba13c206a 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/properties/TokenProperties.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/properties/TokenProperties.java @@ -8,14 +8,14 @@ import org.springframework.stereotype.Component; @Component public final class TokenProperties { - /** - * The secret key used for token generation. - */ - public static final String SECRET = "topsecretkey"; + /** + * The secret key used for token generation. + */ + public static final String SECRET = "topsecretkey"; - /** - * The duration of the token validity in minutes. - */ - public static final int DURATION = 30; + /** + * The duration of the token validity in minutes. + */ + public static final int DURATION = 30; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/properties/UserProperties.java b/src/main/java/no/ntnu/idi/stud/savingsapp/properties/UserProperties.java index 417a7c30696d990b74ce7b16e4f5332f692686bb..6c13cb08fcb81a36679aebe99ccfc49fe115f0c2 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/properties/UserProperties.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/properties/UserProperties.java @@ -8,20 +8,32 @@ import org.springframework.stereotype.Component; @Component public final class UserProperties { - // Name - public static final String NAME_EMPTY = "Name is required"; - public static final int NAME_LEN_MIN = 2; - public static final int NAME_LEN_MAX = 64; - public static final String NAME_LEN_MSG = "Name must be between " + NAME_LEN_MIN + " and " + NAME_LEN_MAX + " characters"; - public static final String NAME_REGEX = "^[a-zA-Z]+(?:[-'\\s][a-zA-Z]+)*$"; - public static final String NAME_REGEX_MSG = "Invalid name"; - - // Password - public static final String PASS_EMPTY = "Password is required"; - public static final int PASS_LEN_MIN = 4; - public static final int PASS_LEN_MAX = 16; - public static final String PASS_LEN_MSG = "Password must be between " + PASS_LEN_MIN + " and " + PASS_LEN_MAX + " characters"; - public static final String PASS_REGEX = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)[\\w]+$"; - public static final String PASS_REGEX_MSG = "Password must contain at least one lowercase letter one uppercase letter and one digit"; + // Name + public static final String NAME_EMPTY = "Name is required"; + + public static final int NAME_LEN_MIN = 2; + + public static final int NAME_LEN_MAX = 64; + + public static final String NAME_LEN_MSG = "Name must be between " + NAME_LEN_MIN + " and " + NAME_LEN_MAX + + " characters"; + + public static final String NAME_REGEX = "^[a-zA-Z]+(?:[-'\\s][a-zA-Z]+)*$"; + + public static final String NAME_REGEX_MSG = "Invalid name"; + + // Password + public static final String PASS_EMPTY = "Password is required"; + + public static final int PASS_LEN_MIN = 4; + + public static final int PASS_LEN_MAX = 16; + + public static final String PASS_LEN_MSG = "Password must be between " + PASS_LEN_MIN + " and " + PASS_LEN_MAX + + " characters"; + + public static final String PASS_REGEX = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)[\\w]+$"; + + public static final String PASS_REGEX_MSG = "Password must contain at least one lowercase letter one uppercase letter and one digit"; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/repository/BadgeRepository.java b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/BadgeRepository.java index af9ac377d1c2331ad064c17081b680d61f04bee5..3f7454e4274f77beae7fd063d56e94093837c10b 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/repository/BadgeRepository.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/BadgeRepository.java @@ -14,72 +14,47 @@ import org.springframework.stereotype.Repository; @Repository public interface BadgeRepository extends JpaRepository<Badge, Long> { - /** - * Returns a {@link Badge} by its id. - * - * @param badgeId The id of the badge - * @return the badge associated with the id. - */ - Optional<Badge> findBadgeById(long badgeId); + /** + * Returns a {@link Badge} by its id. + * @param badgeId The id of the badge + * @return the badge associated with the id. + */ + Optional<Badge> findBadgeById(long badgeId); - /** - * Returns a list of all {@link Badge} objects. - * - * @return the list of all badges. - */ - @Query(value = - "SELECT b.* FROM badge b;" - , nativeQuery = true) - List<Badge> findAllBadges(); + /** + * Returns a list of all {@link Badge} objects. + * @return the list of all badges. + */ + @Query(value = "SELECT b.* FROM badge b;", nativeQuery = true) + List<Badge> findAllBadges(); - /** - * Returns a list of {@link Badge} that are unlocked by a user. - * - * @param userId the id of to the user - * @return the list of all unlocked badges of the user. - */ - @Query(value = - "SELECT b.* " + - "FROM badge b " + - "JOIN badge_user bu ON bu.badge_id = b.badge_id " + - "WHERE bu.user_id = :userId" - , nativeQuery = true) - List<Badge> findBadgesUnlockedByUserId(@Param("userId") long userId); + /** + * Returns a list of {@link Badge} that are unlocked by a user. + * @param userId the id of to the user + * @return the list of all unlocked badges of the user. + */ + @Query(value = "SELECT b.* " + "FROM badge b " + "JOIN badge_user bu ON bu.badge_id = b.badge_id " + + "WHERE bu.user_id = :userId", nativeQuery = true) + List<Badge> findBadgesUnlockedByUserId(@Param("userId") long userId); - /** - * Returns a list of {@link Badge} that are not unlocked by a user. - * - * @param userId the id of to the user - * @return the list of all locked badges of the user. - */ - @Query(value = - "SELECT b.* " + - "FROM badge b " + - "WHERE NOT EXISTS (" + - " SELECT 1 FROM badge_user bu " + - " WHERE bu.badge_id = b.badge_id AND bu.user_id = :userId" + - ")" - , nativeQuery = true) - List<Badge> findBadgesNotUnlockedByUserId(@Param("userId") long userId); + /** + * Returns a list of {@link Badge} that are not unlocked by a user. + * @param userId the id of to the user + * @return the list of all locked badges of the user. + */ + @Query(value = "SELECT b.* " + "FROM badge b " + "WHERE NOT EXISTS (" + " SELECT 1 FROM badge_user bu " + + " WHERE bu.badge_id = b.badge_id AND bu.user_id = :userId" + ")", nativeQuery = true) + List<Badge> findBadgesNotUnlockedByUserId(@Param("userId") long userId); + + /** + * Returns a list of {@link Badge} that are newly unlocked by a user. + * @param userId the id of to the user + * @return the list of all newly unlocked badges of the user. + */ + @Query(value = "SELECT b.* " + "FROM badge b, user u, point p " + "WHERE u.user_id = :userId " + + "AND u.point_id = p.point_id " + "AND p.total_earned_points >= b.criteria " + "AND NOT EXISTS (" + + "SELECT 1 " + "FROM badge_user bu " + "WHERE bu.badge_id = b.badge_id " + "AND bu.user_id = u.user_id" + + ")", nativeQuery = true) + List<Badge> findNewlyUnlockedBadgesByUserId(@Param("userId") long userId); - /** - * Returns a list of {@link Badge} that are newly unlocked by a user. - * - * @param userId the id of to the user - * @return the list of all newly unlocked badges of the user. - */ - @Query(value = - "SELECT b.* " + - "FROM badge b, user u, point p " + - "WHERE u.user_id = :userId " + - "AND u.point_id = p.point_id " + - "AND p.total_earned_points >= b.criteria " + - "AND NOT EXISTS (" + - "SELECT 1 " + - "FROM badge_user bu " + - "WHERE bu.badge_id = b.badge_id " + - "AND bu.user_id = u.user_id" + - ")" - , nativeQuery = true) - List<Badge> findNewlyUnlockedBadgesByUserId(@Param("userId") long userId); } \ No newline at end of file diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/repository/BadgeUserRepository.java b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/BadgeUserRepository.java index 75e6f5b778b752485eef520afc86cd01c308ad00..75538915135fd7a3bec7eff34be326af0aeff954 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/repository/BadgeUserRepository.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/BadgeUserRepository.java @@ -1,7 +1,7 @@ package no.ntnu.idi.stud.savingsapp.repository; import no.ntnu.idi.stud.savingsapp.model.user.BadgeUser; -import no.ntnu.idi.stud.savingsapp.model.user.BadgeUserId; +import no.ntnu.idi.stud.savingsapp.model.user.BadgeUserId; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @@ -9,6 +9,6 @@ import org.springframework.stereotype.Repository; * Repository interface for {@link BadgeUser} entities. */ @Repository -public interface BadgeUserRepository extends JpaRepository<BadgeUser, BadgeUserId> { +public interface BadgeUserRepository extends JpaRepository<BadgeUser, BadgeUserId> { } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/repository/BudgetRepository.java b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/BudgetRepository.java index 9b0fe90e1cc96875843bd564cd137a0e96a027a2..292d94b2424d7388319f1affe76737296110af66 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/repository/BudgetRepository.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/BudgetRepository.java @@ -10,28 +10,24 @@ import org.springframework.data.jpa.repository.JpaRepository; */ public interface BudgetRepository extends JpaRepository<Budget, Long> { - /** - * Finds a budget by the budget's id. - * - * @param id The belonging id of the budget - * @return An optional containing the budget if found, otherwise empty. - */ - Optional<Budget> findBudgetById(Long id); + /** + * Finds a budget by the budget's id. + * @param id The belonging id of the budget + * @return An optional containing the budget if found, otherwise empty. + */ + Optional<Budget> findBudgetById(Long id); - /** - * Deletes a budget by the budget's id. - * - * @param id The belonging id of the budget - */ - void deleteBudgetById(Long id); - - /** - * Finds all budget by a user's id. - * - * @param id The user's id - * @return A list of budgets. - */ - List<Budget> findBudgetsByUserId(Long id); + /** + * Deletes a budget by the budget's id. + * @param id The belonging id of the budget + */ + void deleteBudgetById(Long id); + /** + * Finds all budget by a user's id. + * @param id The user's id + * @return A list of budgets. + */ + List<Budget> findBudgetsByUserId(Long id); } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/repository/ChallengeRepository.java b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/ChallengeRepository.java index 7f8b3f2615a284501182ec266f39c49c72d978b3..b110fc7a7a58fa293359e657b8c17eadb5fae8f1 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/repository/ChallengeRepository.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/ChallengeRepository.java @@ -10,43 +10,42 @@ import org.springframework.stereotype.Repository; @Repository public interface ChallengeRepository extends JpaRepository<Challenge, Long> { - /** - * Find all the challenges with the same challenge type. - * - * @param challengeType The type of challenge to search for. - * @return A list of {@link Challenge SavingChallenges} - */ - //List<SavingChallenge> findAllByChallengeType(ChallengeType challengeType); - - - /** - * Find all SavingChallenges that have a given difficulty level. - * - * @param difficultyLevel The difficulty level of the challenges to be found. - * @return A list of {@link Challenge SavingChallenges}. - */ - /*@Query("SELECT sc.* FROM saving_challenge sc " - + "JOIN difficulty_level dl " - + "ON sc.difficulty_level_id = dl.difficulty_level_id " - + "WHERE dl.difficulty_level_id = :difLevel")*/ - //List<SavingChallenge> findAllByDifficultyLevel(@Param("difLevel") DifficultyLevel difficultyLevel); - - // TODO find all challenges in a list of challenges that are of a difficulty level. - - /** - * Find the difficulty level of a {@link Challenge}. - * - * @param savingChallengeId The id of the {@link Challenge} who's {@link DifficultyLevel} - * should be found. - * @return The {@link DifficultyLevel} of the {@link Challenge} if found, if not return - * empty. - */ - /*@Query("SELECT dl.* FROM difficulty_level dl JOIN saving_challenge sc " - + "ON dl.difficulty_level_id = sc.difficulty_level_id" - + "WHERE sc.saving_challenge_id = :savingChallengeId") - Optional<DifficultyLevel> findDifficultyLevelBySavingChallengeId( - @Param("savingChallengeId") - Long savingChallengeId - );*/ + /** + * Find all the challenges with the same challenge type. + * @param challengeType The type of challenge to search for. + * @return A list of {@link Challenge SavingChallenges} + */ + // List<SavingChallenge> findAllByChallengeType(ChallengeType challengeType); + + /** + * Find all SavingChallenges that have a given difficulty level. + * @param difficultyLevel The difficulty level of the challenges to be found. + * @return A list of {@link Challenge SavingChallenges}. + */ + /* + * @Query("SELECT sc.* FROM saving_challenge sc " + "JOIN difficulty_level dl " + + * "ON sc.difficulty_level_id = dl.difficulty_level_id " + + * "WHERE dl.difficulty_level_id = :difLevel") + */ + // List<SavingChallenge> findAllByDifficultyLevel(@Param("difLevel") DifficultyLevel + // difficultyLevel); + + // TODO find all challenges in a list of challenges that are of a difficulty level. + + /** + * Find the difficulty level of a {@link Challenge}. + * @param savingChallengeId The id of the {@link Challenge} who's + * {@link DifficultyLevel} should be found. + * @return The {@link DifficultyLevel} of the {@link Challenge} if found, if not + * return empty. + */ + /* + * @Query("SELECT dl.* FROM difficulty_level dl JOIN saving_challenge sc " + + * "ON dl.difficulty_level_id = sc.difficulty_level_id" + + * "WHERE sc.saving_challenge_id = :savingChallengeId") Optional<DifficultyLevel> + * findDifficultyLevelBySavingChallengeId( + * + * @Param("savingChallengeId") Long savingChallengeId ); + */ } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/repository/ChallengeTemplateRepository.java b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/ChallengeTemplateRepository.java index ff9ba6c655a152c6e03b161126095c5bf1e64d2d..a9297a0d1c05394083dc5fb748b2529ec51e2edf 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/repository/ChallengeTemplateRepository.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/ChallengeTemplateRepository.java @@ -12,12 +12,12 @@ import org.springframework.stereotype.Repository; @Repository public interface ChallengeTemplateRepository extends JpaRepository<ChallengeTemplate, Long> { - /** - * Retrieves a list of {@link ChallengeTemplate challangeTempletes} by a - * list of {@link ChallengeType challengeType} enums. - * - * @param challengeType the list challengeType enums - * @return the list of challengeTemplates. - */ - List<ChallengeTemplate> findAllByChallengeTypeIn(List<ChallengeType> challengeType); + /** + * Retrieves a list of {@link ChallengeTemplate challangeTempletes} by a list of + * {@link ChallengeType challengeType} enums. + * @param challengeType the list challengeType enums + * @return the list of challengeTemplates. + */ + List<ChallengeTemplate> findAllByChallengeTypeIn(List<ChallengeType> challengeType); + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/repository/ExpenseRepository.java b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/ExpenseRepository.java index 909b54aef114312a5e424ecdc338704bce8a3788..8875b55310ff4a7d5be5671d7931779c7ca0a987 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/repository/ExpenseRepository.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/ExpenseRepository.java @@ -10,26 +10,24 @@ import org.springframework.data.jpa.repository.JpaRepository; */ public interface ExpenseRepository extends JpaRepository<Expense, Long> { - /** - * Finds an expense by the expense's id. - * - * @param id The belonging id of the expense - * @return An optional containing the expense if found, otherwise empty. - */ - Optional<Expense> findExpenseById(Long id); + /** + * Finds an expense by the expense's id. + * @param id The belonging id of the expense + * @return An optional containing the expense if found, otherwise empty. + */ + Optional<Expense> findExpenseById(Long id); - /** - * Deletes an expense by the budget's id. - * - * @param id The belonging id of the expense - */ - void deleteExpenseById(Long id); + /** + * Deletes an expense by the budget's id. + * @param id The belonging id of the expense + */ + void deleteExpenseById(Long id); + + /** + * Finds all expenses by a budget's id. + * @param id The budget's id + * @return A list of expenses. + */ + List<Expense> findExpensesByBudgetId(Long id); - /** - * Finds all expenses by a budget's id. - * - * @param id The budget's id - * @return A list of expenses. - */ - List<Expense> findExpensesByBudgetId(Long id); } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/repository/FeedbackRepository.java b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/FeedbackRepository.java index c852f94a6f450a1fac94c6a10ef3f2e2ce240897..55e8554e75a72c5843e79855143c53cce20a6a9f 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/repository/FeedbackRepository.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/FeedbackRepository.java @@ -8,6 +8,6 @@ import org.springframework.stereotype.Repository; * Repository interface for {@link Feedback} entities. */ @Repository -public interface FeedbackRepository extends JpaRepository<Feedback, Long>{ +public interface FeedbackRepository extends JpaRepository<Feedback, Long> { } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/repository/FriendRepository.java b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/FriendRepository.java index 6e40943ab5301c3d90a561f5b245c9b9f2d3c0fe..c393cb4dcc1aa4d5c7833e5b8c09afaf3bf3a20a 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/repository/FriendRepository.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/FriendRepository.java @@ -16,40 +16,37 @@ import jakarta.transaction.Transactional; */ public interface FriendRepository extends JpaRepository<Friend, FriendId> { - /** - * Retrieves a list of all friends by user id or friend id. - * - * @param userId the user/friend identifier - * @return the list of all friends by user id or friend id. - */ - @Query("SELECT f FROM Friend f WHERE f.id.friend.id = :userId OR f.id.user.id = :userId") - List<Friend> findAllById_UserOrId_Friend(@Param("userId") Long userId); - - /** - * Retrieves a list of all friends by user id or friend id where pending is false. - * - * @param userId the user/friend identifier - * @return the list of all friends by user id or friend id. - */ - @Query("SELECT f FROM Friend f WHERE (f.id.friend.id = :userId OR f.id.user.id = :userId) AND f.pending = false") - List<Friend> findAllById_UserOrId_FriendAndPendingFalse(@Param("userId") Long userId); - - /** - * Retrieves a list of all friends by friend id where pending is true. - * - * @param userId the user/friend identifier - * @return the list of all friends by friend id. - */ - @Query("SELECT f FROM Friend f WHERE f.id.friend.id = :userId AND f.pending = true") - List<Friend> findAllById_FriendAndPendingTrue(@Param("userId") Long userId); - - /** - * Accepts a friend request by its friend id. - * - * @param friendId the id to the friend. - */ - @Transactional - @Modifying - @Query("UPDATE Friend f SET f.pending = false WHERE f.id = :friendId") - void acceptFriendRequest(FriendId friendId); + /** + * Retrieves a list of all friends by user id or friend id. + * @param userId the user/friend identifier + * @return the list of all friends by user id or friend id. + */ + @Query("SELECT f FROM Friend f WHERE f.id.friend.id = :userId OR f.id.user.id = :userId") + List<Friend> findAllById_UserOrId_Friend(@Param("userId") Long userId); + + /** + * Retrieves a list of all friends by user id or friend id where pending is false. + * @param userId the user/friend identifier + * @return the list of all friends by user id or friend id. + */ + @Query("SELECT f FROM Friend f WHERE (f.id.friend.id = :userId OR f.id.user.id = :userId) AND f.pending = false") + List<Friend> findAllById_UserOrId_FriendAndPendingFalse(@Param("userId") Long userId); + + /** + * Retrieves a list of all friends by friend id where pending is true. + * @param userId the user/friend identifier + * @return the list of all friends by friend id. + */ + @Query("SELECT f FROM Friend f WHERE f.id.friend.id = :userId AND f.pending = true") + List<Friend> findAllById_FriendAndPendingTrue(@Param("userId") Long userId); + + /** + * Accepts a friend request by its friend id. + * @param friendId the id to the friend. + */ + @Transactional + @Modifying + @Query("UPDATE Friend f SET f.pending = false WHERE f.id = :friendId") + void acceptFriendRequest(FriendId friendId); + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/repository/GoalRepository.java b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/GoalRepository.java index a1e3e2074f996d194f1e482872ebb6e580fae7a1..74aaa52ad4ccf5bd4cd817fdfce57f29c04e53d1 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/repository/GoalRepository.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/GoalRepository.java @@ -13,22 +13,24 @@ import java.util.Optional; @Repository public interface GoalRepository extends JpaRepository<Goal, Long> { - /** - * Retrieves all goals associated with a specified user ID. - * This method is typically used to fetch all goals created by a specific user, enabling the application to - * display a user-specific list of goals. - * - * @param userId The ID of the user whose goals are to be retrieved. - * @return A list of {@link Goal} entities that belong to the specified user. The list can be empty if no goals exist. - */ - List<Goal> findByUser_Id(long userId); + /** + * Retrieves all goals associated with a specified user ID. This method is typically + * used to fetch all goals created by a specific user, enabling the application to + * display a user-specific list of goals. + * @param userId The ID of the user whose goals are to be retrieved. + * @return A list of {@link Goal} entities that belong to the specified user. The list + * can be empty if no goals exist. + */ + List<Goal> findByUser_Id(long userId); + + /** + * Finds a goal that contains a specific challenge identified by its ID. This method + * is useful for operations that require verification of goal ownership or details + * when handling a specific challenge. + * @param id The ID of the challenge whose goal needs to be identified. + * @return An {@link Optional} containing the {@link Goal} if found, or an empty + * Optional if no such goal exists. + */ + Optional<Goal> findByChallenges_Id(long id); - /** - * Finds a goal that contains a specific challenge identified by its ID. - * This method is useful for operations that require verification of goal ownership or details when handling a specific challenge. - * - * @param id The ID of the challenge whose goal needs to be identified. - * @return An {@link Optional} containing the {@link Goal} if found, or an empty Optional if no such goal exists. - */ - Optional<Goal> findByChallenges_Id(long id); } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/repository/GroupRepository.java b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/GroupRepository.java index e768768a4ce5574e0ef786a0bd4a42ca806d6e41..211789e5c0256a87e42b25f4958fe701d2652b30 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/repository/GroupRepository.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/GroupRepository.java @@ -10,5 +10,6 @@ import java.util.Optional; @Repository public interface GroupRepository extends JpaRepository<Group, Long> { - Optional<Group> findByGoals_Id(long id); + Optional<Group> findByGoals_Id(long id); + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/repository/InventoryRepository.java b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/InventoryRepository.java index 9ef7f5e343f66156dbdfce9631fba478706560d8..a6137ac4ce9755149e358228547c6c74cdaa1755 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/repository/InventoryRepository.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/InventoryRepository.java @@ -17,12 +17,13 @@ import no.ntnu.idi.stud.savingsapp.model.store.Item; @Repository public interface InventoryRepository extends JpaRepository<Inventory, InventoryId> { - /** - * Retrieves the inventory belonging to a user. - * - * @param userId the id of the user - * @return a list containing {@link Item items}. - */ - @Query(value = "SELECT i.* FROM item i JOIN inventory inv ON i.item_id = inv.item_id WHERE inv.user_id = :userId", nativeQuery = true) - List<Item> getInventory(@Param("userId") Long userId); + /** + * Retrieves the inventory belonging to a user. + * @param userId the id of the user + * @return a list containing {@link Item items}. + */ + @Query(value = "SELECT i.* FROM item i JOIN inventory inv ON i.item_id = inv.item_id WHERE inv.user_id = :userId", + nativeQuery = true) + List<Item> getInventory(@Param("userId") Long userId); + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/repository/NotificationRepository.java b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/NotificationRepository.java index 3ff836456abb706c4298f3574e38a4f655eafa04..8af781521eb8f01c8af84b9394180c3bffd3686e 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/repository/NotificationRepository.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/NotificationRepository.java @@ -14,36 +14,28 @@ import org.springframework.stereotype.Repository; @Repository public interface NotificationRepository extends JpaRepository<Notification, Long> { - /** - * Retrieves a notification optional by its id. - * - * @param notificationId the unique identifier for the notification - * @return the optional {@link Notification} to the notificationId. - */ - Optional<Notification> findNotificationById(long notificationId); + /** + * Retrieves a notification optional by its id. + * @param notificationId the unique identifier for the notification + * @return the optional {@link Notification} to the notificationId. + */ + Optional<Notification> findNotificationById(long notificationId); - /** - * Retrieves a list of all notifications belonging to a user. - * - * @param userId the unique identifier for the user - * @return a list of {@link Notification} objects belonging to the user. - */ - @Query(value = - "SELECT n.* FROM notification n " + - "WHERE n.user_id = :userId" - , nativeQuery = true) - List<Notification> findNotificationsByUserId(@Param("userId") long userId); + /** + * Retrieves a list of all notifications belonging to a user. + * @param userId the unique identifier for the user + * @return a list of {@link Notification} objects belonging to the user. + */ + @Query(value = "SELECT n.* FROM notification n " + "WHERE n.user_id = :userId", nativeQuery = true) + List<Notification> findNotificationsByUserId(@Param("userId") long userId); + + /** + * Retrieves a list of all unread notifications belonging to a user. + * @param userId the unique identifier for the user + * @return a list of unread {@link Notification} objects belonging to the user. + */ + @Query(value = "SELECT n.* FROM notification n " + "WHERE n.user_id = :userId " + "AND n.unread = true", + nativeQuery = true) + List<Notification> findUnreadNotificationsByUserId(@Param("userId") long userId); - /** - * Retrieves a list of all unread notifications belonging to a user. - * - * @param userId the unique identifier for the user - * @return a list of unread {@link Notification} objects belonging to the user. - */ - @Query(value = - "SELECT n.* FROM notification n " + - "WHERE n.user_id = :userId " + - "AND n.unread = true" - , nativeQuery = true) - List<Notification> findUnreadNotificationsByUserId(@Param("userId") long userId); } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/repository/PasswordResetTokenRepository.java b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/PasswordResetTokenRepository.java index 9fed28c79516c02d54751289789cfaba9b2a4bb1..2eef737015883b497142dcae9343c961b6b7bb31 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/repository/PasswordResetTokenRepository.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/PasswordResetTokenRepository.java @@ -12,13 +12,14 @@ import java.util.Optional; @Repository public interface PasswordResetTokenRepository extends JpaRepository<PasswordResetToken, Long> { - /** - * Retrieves a password reset token by its token string. - * This method is used to fetch a password reset token from the database to verify its validity - * and to perform operations like password reset confirmation. - * - * @param token The unique string of the password reset token. - * @return An Optional containing the found PasswordResetToken or an empty Optional if no token is found. - */ - Optional<PasswordResetToken> findByToken(String token); + /** + * Retrieves a password reset token by its token string. This method is used to fetch + * a password reset token from the database to verify its validity and to perform + * operations like password reset confirmation. + * @param token The unique string of the password reset token. + * @return An Optional containing the found PasswordResetToken or an empty Optional if + * no token is found. + */ + Optional<PasswordResetToken> findByToken(String token); + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/repository/PointRepository.java b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/PointRepository.java index fe5c9e04c811705ed7940c046c0ce1ac3c48ab75..9500f91e84aa37c5e2d70583ad317b200f0ac3af 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/repository/PointRepository.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/PointRepository.java @@ -6,6 +6,6 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository -public interface PointRepository extends JpaRepository<Point, Long>{ - +public interface PointRepository extends JpaRepository<Point, Long> { + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/repository/StoreRepository.java b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/StoreRepository.java index 615cca941050021ebcc3d00025dd9806b8c57261..bebf760e212d2cf855d751d8e6d59c57c9f81713 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/repository/StoreRepository.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/StoreRepository.java @@ -15,12 +15,13 @@ import no.ntnu.idi.stud.savingsapp.model.store.Item; @Repository public interface StoreRepository extends JpaRepository<Item, Long> { - /** - * Retrieves the inventory belonging to a user. - * - * @param userId the id of the user - * @return a list containing {@link Item items}. - */ - @Query(value = "SELECT i.* FROM item i JOIN inventory inv ON i.item_id = inv.item_id WHERE inv.user_id = :userId", nativeQuery = true) - List<Item> getInventory(@Param("userId") Long userId); + /** + * Retrieves the inventory belonging to a user. + * @param userId the id of the user + * @return a list containing {@link Item items}. + */ + @Query(value = "SELECT i.* FROM item i JOIN inventory inv ON i.item_id = inv.item_id WHERE inv.user_id = :userId", + nativeQuery = true) + List<Item> getInventory(@Param("userId") Long userId); + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/repository/StreakRepository.java b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/StreakRepository.java index e77919001b591c59dcca0dfab0c63dc7f5b98a9f..570e9ebb6bd2a46f023b6fb5a89ed47d2616ca09 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/repository/StreakRepository.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/StreakRepository.java @@ -6,6 +6,6 @@ import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; @Repository -public interface StreakRepository extends JpaRepository<Streak, Long>{ - +public interface StreakRepository extends JpaRepository<Streak, Long> { + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/repository/UserRepository.java b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/UserRepository.java index 706fa8353b9e1791bf5014111a87f64a0e8f4ec3..5f88a2058ba50a61c0ef4ef854f78cb278fbb08b 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/repository/UserRepository.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/repository/UserRepository.java @@ -19,267 +19,197 @@ import jakarta.transaction.Transactional; @Repository public interface UserRepository extends JpaRepository<User, Long> { - /** - * Finds a user by their email. - * - * @param email The email of the user to be found - * @return An optional containing the user if found, otherwise empty. - */ - Optional<User> findByEmail(String email); + /** + * Finds a user by their email. + * @param email The email of the user to be found + * @return An optional containing the user if found, otherwise empty. + */ + Optional<User> findByEmail(String email); + + /** + * Finds users with names containing provided string. + * @param firstName The string containing any of the characters present in the first + * name of a user. + * @param lastName The string containing any of the characters present in the first + * name of a * user. + * @return A list of users with names containing the provided string. + */ + List<User> findUserByFirstNameContainingIgnoreCaseOrLastNameContainingIgnoreCase(String firstName, String lastName); + + /** + * Finds a user by their BankID subject identifier. This method queries the database + * to locate a user entity associated with the specified BankID subject identifier. + * The 'sub' is a unique identifier assigned by BankID to a user and is used to match + * a user in the application's database. + * @param sub The unique subject identifier provided by BankID for a user. + * @return An {@link Optional<User>} containing the user if found, or an empty + * Optional if no user is associated with the given sub. + */ + Optional<User> findByBankIdSub(String sub); + + /** + * Finds the top X users with the highest total earned points. + * @param entryCount The maximum number of users to return. + * @return A list of users sorted by total earned points in descending order. + */ + @Query(value = "SELECT u.* " + "FROM user u " + "JOIN point p ON u.point_id = p.point_id " + + "ORDER BY p.total_earned_points DESC " + "LIMIT :entryCount", nativeQuery = true) + List<User> findTopUsersByTotalEarnedPoints(@Param("entryCount") Integer entryCount); + + /** + * Finds the top X users with the highest ever streak. + * @param entryCount The maximum number of users to return. + * @return A list of users sorted by highest ever streak in descending order. + */ + @Query(value = "SELECT u.* " + "FROM user u " + "JOIN streak s ON u.streak_id = s.streak_id " + + "ORDER BY s.highest_streak DESC " + "LIMIT :entryCount", nativeQuery = true) + List<User> findTopUsersByHighestEverStreak(@Param("entryCount") Integer entryCount); + + /** + * Finds the top X users with the highest current streak. + * @param entryCount The maximum number of users to return. + * @return A list of users sorted by highest current streak in descending order. + */ + @Query(value = "SELECT u.* " + "FROM user u " + "JOIN streak s ON u.streak_id = s.streak_id " + + "ORDER BY s.current_streak DESC " + "LIMIT :entryCount", nativeQuery = true) + List<User> findTopUsersByHighestCurrentStreak(@Param("entryCount") Integer entryCount); + + /** + * Finds the top X friends with the highest total earned points. + * @param entryCount The maximum number of friends to return. + * @return A list of friends sorted by total earned points in descending order. + */ + @Query(value = "SELECT u.* FROM ( " + "SELECT DISTINCT u.user_id FROM user u " + + "JOIN friend f ON u.user_id = f.user_id OR u.user_id = f.friend_id " + + "WHERE (f.user_id = :userId OR f.friend_id = :userId) AND f.pending IS FALSE" + ") AS distinct_users " + + "JOIN user u ON u.user_id = distinct_users.user_id " + "JOIN point p ON u.point_id = p.point_id " + + "ORDER BY p.total_earned_points DESC " + "LIMIT :entryCount", nativeQuery = true) + List<User> findTopFriendsByTotalEarnedPoints(@Param("userId") Long userId, @Param("entryCount") Integer entryCount); + + /** + * Finds the top X friends with the highest ever streak. + * @param entryCount The maximum number of friends to return. + * @return A list of friends sorted by highest ever streak in descending order. + */ + @Query(value = "SELECT u.* FROM ( " + "SELECT DISTINCT u.user_id FROM user u " + + "JOIN friend f ON (u.user_id = f.user_id OR u.user_id = f.friend_id) " + + "WHERE (f.user_id = :userId OR f.friend_id = :userId) AND f.pending IS FALSE" + ") AS distinct_users " + + "JOIN user u ON u.user_id = distinct_users.user_id " + "JOIN streak s ON u.streak_id = s.streak_id " + + "ORDER BY s.highest_streak DESC " + "LIMIT :entryCount", nativeQuery = true) + List<User> findTopFriendsByHighestEverStreak(@Param("userId") Long userId, @Param("entryCount") Integer entryCount); + + /** + * Finds the top X friends with the highest current streak. + * @param entryCount The maximum number of friends to return. + * @return A list of friends sorted by highest current streak in descending order. + */ + @Query(value = "SELECT u.* FROM ( " + "SELECT DISTINCT u.user_id FROM user u " + + "JOIN friend f ON (u.user_id = f.user_id OR u.user_id = f.friend_id) " + + "WHERE (f.user_id = :userId OR f.friend_id = :userId) AND f.pending IS FALSE" + ") AS distinct_users " + + "JOIN user u ON u.user_id = distinct_users.user_id " + "JOIN streak s ON u.streak_id = s.streak_id " + + "ORDER BY s.current_streak DESC " + "LIMIT :entryCount", nativeQuery = true) + List<User> findTopFriendsByHighestCurrentStreak(@Param("userId") Long userId, + @Param("entryCount") Integer entryCount); + + /** + * Finds the X users surrounding a user by their total earned points. + * @param userId The ID of the user you want to be surrounded. + * @param entryCount The number of users above and below the user. + * @return A list of users with a user with userId and 2X users surrounding it by + * their total earned points. + */ + @Query(value = + // Define two CTEs (ranked_users and user_rank) + // ranked_users virtual table that holds user info and their rank desc (1 is lowest) + // user_rank virtual table that holds rank of the user with ID userId + "WITH ranked_users AS ( " + "SELECT u.*, RANK() OVER (ORDER BY p.total_earned_points DESC) AS user_rank " + + "FROM user u " + "JOIN point p ON u.point_id = p.point_id " + "), user_rank AS ( " + + "SELECT user_rank " + "FROM ranked_users " + "WHERE user_id = :userId ) " + + // Get user attributes from ranked_users + "SELECT ru.user_id, ru.created_at, ru.email, ru.first_name, ru.last_name, ru.password, ru.role," + + " ru.point_id, ru.streak_id, ru.checking_account_bban, ru.savings_account_bban, ru" + + ".configuration_id, ru.profile_image, ru.banner_image, ru.subscription_level, ru" + ".bankid_sub " + + "FROM ranked_users ru, user_rank ur " + + // Case handling for when user_rank is less than entryCount + "WHERE ru.user_rank BETWEEN (CASE WHEN ur.user_rank > :entryCount THEN ur.user_rank - :entryCount ELSE 1 END) AND (ur.user_rank + :entryCount)", + nativeQuery = true) + List<User> findSurroundingUsersByTotalEarnedPoints(@Param("userId") Long userId, + @Param("entryCount") Integer entryCount); + + @Query(value = + // Define two CTEs (ranked_users and user_rank) + // ranked_users virtual table that holds user info and their rank desc (1 is lowest) + // user_rank virtual table that holds rank of the user with ID userId + "WITH ranked_users AS ( " + "SELECT u.*, RANK() OVER (ORDER BY s.current_streak DESC) AS user_rank " + + "FROM user u " + "JOIN streak s ON u.streak_id = s.streak_id " + "), user_rank AS ( " + + "SELECT user_rank " + "FROM ranked_users " + "WHERE user_id = :userId ) " + + // Get user attributes from ranked_users + "SELECT ru.user_id, ru.created_at, ru.email, ru.first_name, ru.last_name, ru.password, ru.role," + + " ru.point_id, ru.streak_id, ru.checking_account_bban, ru.savings_account_bban, ru" + + ".configuration_id, ru.profile_image, ru.banner_image, ru.subscription_level, ru.bankid_sub" + " " + + "FROM ranked_users ru, user_rank ur " + + // Case handling for when user_rank is less than entryCount + "WHERE ru.user_rank BETWEEN (CASE WHEN ur.user_rank > :entryCount THEN ur.user_rank - :entryCount ELSE 1 END) AND (ur.user_rank + :entryCount)", + nativeQuery = true) + List<User> findSurroundingUsersByHighestCurrentStreak(@Param("userId") Long userId, + @Param("entryCount") Integer entryCount); + + @Query(value = + // Define two CTEs (ranked_users and user_rank) + // ranked_users virtual table that holds user info and their rank desc (1 is lowest) + // user_rank virtual table that holds rank of the user with ID userId + "WITH ranked_users AS ( " + "SELECT u.*, RANK() OVER (ORDER BY s.highest_streak DESC) AS user_rank " + + "FROM user u " + "JOIN streak s ON u.streak_id = s.streak_id " + "), user_rank AS ( " + + "SELECT user_rank " + "FROM ranked_users " + "WHERE user_id = :userId ) " + + // Get user attributes from ranked_users + "SELECT ru.user_id, ru.created_at, ru.email, ru.first_name, ru.last_name, ru.password, ru.role," + + " ru.point_id, ru.streak_id, ru.checking_account_bban, ru.savings_account_bban, ru" + + ".configuration_id, ru.profile_image, ru.banner_image, ru.subscription_level, ru.bankid_sub" + " " + + "FROM ranked_users ru, user_rank ur " + + // Case handling for when user_rank is less than entryCount + "WHERE ru.user_rank BETWEEN (CASE WHEN ur.user_rank > :entryCount THEN ur.user_rank - :entryCount ELSE 1 END) AND (ur.user_rank + :entryCount)", + nativeQuery = true) + List<User> findSurroundingUsersByHighestEverStreak(@Param("userId") Long userId, + @Param("entryCount") Integer entryCount); + + @Query(value = "WITH ranked_users AS (" + + " SELECT u.user_id, RANK() OVER (ORDER BY p.total_earned_points DESC) AS user_rank " + + " FROM user u " + " JOIN point p ON u.point_id = p.point_id " + "), " + "user_rank AS (" + + " SELECT user_rank " + " FROM ranked_users " + " WHERE user_id = :userId " + ") " + + "SELECT user_rank " + "FROM user_rank", nativeQuery = true) + long findUserRankByTotalEarnedPoints(@Param("userId") Long userId); + + @Query(value = "WITH ranked_users AS (" + + " SELECT u.user_id, RANK() OVER (ORDER BY s.current_streak DESC) AS user_rank " + " FROM user u " + + " JOIN streak s ON u.streak_id = s.streak_id " + "), " + "user_rank AS (" + " SELECT user_rank " + + " FROM ranked_users " + " WHERE user_id = :userId " + ") " + "SELECT user_rank " + "FROM user_rank", + nativeQuery = true) + long findUserRankByCurrentStreak(@Param("userId") Long userId); + + @Query(value = "WITH ranked_users AS (" + + " SELECT u.user_id, RANK() OVER (ORDER BY s.highest_streak DESC) AS user_rank " + " FROM user u " + + " JOIN streak s ON u.streak_id = s.streak_id " + "), " + "user_rank AS (" + " SELECT user_rank " + + " FROM ranked_users " + " WHERE user_id = :userId " + ") " + "SELECT user_rank " + "FROM user_rank", + nativeQuery = true) + long findUserRankByHighestEverStreak(@Param("userId") Long userId); + + @Query(value = "SELECT * FROM user u WHERE CONCAT(u.first_name, ' ', u.last_name) LIKE %:searchTerm%", + nativeQuery = true) + List<User> findUsersByName(@Param("searchTerm") String searchTerm); + + @Transactional + @Modifying + @Query("UPDATE User u SET u.subscriptionLevel = :subscriptionLevel WHERE u.id = :userId") + void updateSubscriptionLevel(@Param("userId") Long userId, + @Param("subscriptionLevel") SubscriptionLevel subscriptionLevel); + + @Query(value = "SELECT SUM(total_earned_points) FROM point", nativeQuery = true) + long getSumTotalEarnedPoints(); + + @Transactional + @Modifying + @Query(value = "UPDATE point p " + "JOIN user u ON u.point_id = p.point_id " + + "SET p.current_points = p.current_points - :points " + "WHERE u.user_id = :userId", nativeQuery = true) + void deductPoints(@Param("userId") Long userId, @Param("points") int points); - /** - * Finds users with names containing provided string. - * - * @param firstName The string containing any of the characters present in the first name of a - * user. - * @param lastName The string containing any of the characters present in the first name of a - * * user. - * @return A list of users with names containing the provided string. - */ - List<User> findUserByFirstNameContainingIgnoreCaseOrLastNameContainingIgnoreCase( - String firstName, String lastName); - - /** - * Finds a user by their BankID subject identifier. - * This method queries the database to locate a user entity associated with the specified BankID subject identifier. - * The 'sub' is a unique identifier assigned by BankID to a user and is used to match a user in the application's database. - * - * @param sub The unique subject identifier provided by BankID for a user. - * @return An {@link Optional<User>} containing the user if found, or an empty Optional if no user is associated with the given sub. - */ - Optional<User> findByBankIdSub(String sub); - - /** - * Finds the top X users with the highest total earned points. - * @param entryCount The maximum number of users to return. - * @return A list of users sorted by total earned points in descending order. - */ - @Query(value = - "SELECT u.* " + - "FROM user u " + - "JOIN point p ON u.point_id = p.point_id " + - "ORDER BY p.total_earned_points DESC " + - "LIMIT :entryCount", nativeQuery = true) - List<User> findTopUsersByTotalEarnedPoints(@Param("entryCount") Integer entryCount); - - /** - * Finds the top X users with the highest ever streak. - * @param entryCount The maximum number of users to return. - * @return A list of users sorted by highest ever streak in descending order. - */ - @Query(value = - "SELECT u.* " + - "FROM user u " + - "JOIN streak s ON u.streak_id = s.streak_id " + - "ORDER BY s.highest_streak DESC " + - "LIMIT :entryCount", nativeQuery = true) - List<User> findTopUsersByHighestEverStreak(@Param("entryCount") Integer entryCount); - - /** - * Finds the top X users with the highest current streak. - * @param entryCount The maximum number of users to return. - * @return A list of users sorted by highest current streak in descending order. - */ - @Query(value = - "SELECT u.* " + - "FROM user u " + - "JOIN streak s ON u.streak_id = s.streak_id " + - "ORDER BY s.current_streak DESC " + - "LIMIT :entryCount", nativeQuery = true) - List<User> findTopUsersByHighestCurrentStreak(@Param("entryCount") Integer entryCount); - - /** - * Finds the top X friends with the highest total earned points. - * @param entryCount The maximum number of friends to return. - * @return A list of friends sorted by total earned points in descending order. - */ - @Query(value = - "SELECT u.* FROM ( " + - "SELECT DISTINCT u.user_id FROM user u " + - "JOIN friend f ON u.user_id = f.user_id OR u.user_id = f.friend_id " + - "WHERE (f.user_id = :userId OR f.friend_id = :userId) AND f.pending IS FALSE" + - ") AS distinct_users " + - "JOIN user u ON u.user_id = distinct_users.user_id " + - "JOIN point p ON u.point_id = p.point_id " + - "ORDER BY p.total_earned_points DESC " + - "LIMIT :entryCount", nativeQuery = true) - List<User> findTopFriendsByTotalEarnedPoints(@Param("userId") Long userId, @Param("entryCount") Integer entryCount); - - /** - * Finds the top X friends with the highest ever streak. - * @param entryCount The maximum number of friends to return. - * @return A list of friends sorted by highest ever streak in descending order. - */ - @Query(value = - "SELECT u.* FROM ( " + - "SELECT DISTINCT u.user_id FROM user u " + - "JOIN friend f ON (u.user_id = f.user_id OR u.user_id = f.friend_id) " + - "WHERE (f.user_id = :userId OR f.friend_id = :userId) AND f.pending IS FALSE" + - ") AS distinct_users " + - "JOIN user u ON u.user_id = distinct_users.user_id " + - "JOIN streak s ON u.streak_id = s.streak_id " + - "ORDER BY s.highest_streak DESC " + - "LIMIT :entryCount", nativeQuery = true) - List<User> findTopFriendsByHighestEverStreak(@Param("userId") Long userId, @Param("entryCount") Integer entryCount); - - /** - * Finds the top X friends with the highest current streak. - * @param entryCount The maximum number of friends to return. - * @return A list of friends sorted by highest current streak in descending order. - */ - @Query(value = - "SELECT u.* FROM ( " + - "SELECT DISTINCT u.user_id FROM user u " + - "JOIN friend f ON (u.user_id = f.user_id OR u.user_id = f.friend_id) " + - "WHERE (f.user_id = :userId OR f.friend_id = :userId) AND f.pending IS FALSE" + - ") AS distinct_users " + - "JOIN user u ON u.user_id = distinct_users.user_id " + - "JOIN streak s ON u.streak_id = s.streak_id " + - "ORDER BY s.current_streak DESC " + - "LIMIT :entryCount", nativeQuery = true) - List<User> findTopFriendsByHighestCurrentStreak(@Param("userId") Long userId, @Param("entryCount") Integer entryCount); - - - /** - * Finds the X users surrounding a user by their total earned points. - * @param userId The ID of the user you want to be surrounded. - * @param entryCount The number of users above and below the user. - * @return A list of users with a user with userId and 2X users surrounding it by their total earned points. - */ - @Query(value = - // Define two CTEs (ranked_users and user_rank) - // ranked_users virtual table that holds user info and their rank desc (1 is lowest) - // user_rank virtual table that holds rank of the user with ID userId - "WITH ranked_users AS ( " + - "SELECT u.*, RANK() OVER (ORDER BY p.total_earned_points DESC) AS user_rank " + - "FROM user u " + - "JOIN point p ON u.point_id = p.point_id " + - "), user_rank AS ( " + - "SELECT user_rank " + - "FROM ranked_users " + - "WHERE user_id = :userId ) " + - // Get user attributes from ranked_users - "SELECT ru.user_id, ru.created_at, ru.email, ru.first_name, ru.last_name, ru.password, ru.role," - + " ru.point_id, ru.streak_id, ru.checking_account_bban, ru.savings_account_bban, ru" - + ".configuration_id, ru.profile_image, ru.banner_image, ru.subscription_level, ru" - + ".bankid_sub " + - "FROM ranked_users ru, user_rank ur " + - // Case handling for when user_rank is less than entryCount - "WHERE ru.user_rank BETWEEN (CASE WHEN ur.user_rank > :entryCount THEN ur.user_rank - :entryCount ELSE 1 END) AND (ur.user_rank + :entryCount)", - nativeQuery = true) - List<User> findSurroundingUsersByTotalEarnedPoints(@Param("userId") Long userId, @Param("entryCount") Integer entryCount); - - @Query(value = - // Define two CTEs (ranked_users and user_rank) - // ranked_users virtual table that holds user info and their rank desc (1 is lowest) - // user_rank virtual table that holds rank of the user with ID userId - "WITH ranked_users AS ( " + - "SELECT u.*, RANK() OVER (ORDER BY s.current_streak DESC) AS user_rank " + - "FROM user u " + - "JOIN streak s ON u.streak_id = s.streak_id " + - "), user_rank AS ( " + - "SELECT user_rank " + - "FROM ranked_users " + - "WHERE user_id = :userId ) " + - // Get user attributes from ranked_users - "SELECT ru.user_id, ru.created_at, ru.email, ru.first_name, ru.last_name, ru.password, ru.role," - + " ru.point_id, ru.streak_id, ru.checking_account_bban, ru.savings_account_bban, ru" - + ".configuration_id, ru.profile_image, ru.banner_image, ru.subscription_level, ru.bankid_sub" - + " " + - "FROM ranked_users ru, user_rank ur " + - // Case handling for when user_rank is less than entryCount - "WHERE ru.user_rank BETWEEN (CASE WHEN ur.user_rank > :entryCount THEN ur.user_rank - :entryCount ELSE 1 END) AND (ur.user_rank + :entryCount)", - nativeQuery = true) - List<User> findSurroundingUsersByHighestCurrentStreak (@Param("userId") Long userId, @Param("entryCount") Integer entryCount); - - @Query(value = - // Define two CTEs (ranked_users and user_rank) - // ranked_users virtual table that holds user info and their rank desc (1 is lowest) - // user_rank virtual table that holds rank of the user with ID userId - "WITH ranked_users AS ( " + - "SELECT u.*, RANK() OVER (ORDER BY s.highest_streak DESC) AS user_rank " + - "FROM user u " + - "JOIN streak s ON u.streak_id = s.streak_id " + - "), user_rank AS ( " + - "SELECT user_rank " + - "FROM ranked_users " + - "WHERE user_id = :userId ) " + - // Get user attributes from ranked_users - "SELECT ru.user_id, ru.created_at, ru.email, ru.first_name, ru.last_name, ru.password, ru.role," - + " ru.point_id, ru.streak_id, ru.checking_account_bban, ru.savings_account_bban, ru" - + ".configuration_id, ru.profile_image, ru.banner_image, ru.subscription_level, ru.bankid_sub" - + " " + - "FROM ranked_users ru, user_rank ur " + - // Case handling for when user_rank is less than entryCount - "WHERE ru.user_rank BETWEEN (CASE WHEN ur.user_rank > :entryCount THEN ur.user_rank - :entryCount ELSE 1 END) AND (ur.user_rank + :entryCount)", - nativeQuery = true) - List<User> findSurroundingUsersByHighestEverStreak (@Param("userId") Long userId, @Param("entryCount") Integer entryCount); - - @Query(value = - "WITH ranked_users AS (" + - " SELECT u.user_id, RANK() OVER (ORDER BY p.total_earned_points DESC) AS user_rank " + - " FROM user u " + - " JOIN point p ON u.point_id = p.point_id " + - "), " + - "user_rank AS (" + - " SELECT user_rank " + - " FROM ranked_users " + - " WHERE user_id = :userId " + - ") " + - "SELECT user_rank " + - "FROM user_rank", - nativeQuery = true) - long findUserRankByTotalEarnedPoints(@Param("userId") Long userId); - - @Query(value = - "WITH ranked_users AS (" + - " SELECT u.user_id, RANK() OVER (ORDER BY s.current_streak DESC) AS user_rank " + - " FROM user u " + - " JOIN streak s ON u.streak_id = s.streak_id " + - "), " + - "user_rank AS (" + - " SELECT user_rank " + - " FROM ranked_users " + - " WHERE user_id = :userId " + - ") " + - "SELECT user_rank " + - "FROM user_rank", - nativeQuery = true) - long findUserRankByCurrentStreak(@Param("userId") Long userId); - - @Query(value = - "WITH ranked_users AS (" + - " SELECT u.user_id, RANK() OVER (ORDER BY s.highest_streak DESC) AS user_rank " + - " FROM user u " + - " JOIN streak s ON u.streak_id = s.streak_id " + - "), " + - "user_rank AS (" + - " SELECT user_rank " + - " FROM ranked_users " + - " WHERE user_id = :userId " + - ") " + - "SELECT user_rank " + - "FROM user_rank", - nativeQuery = true) - long findUserRankByHighestEverStreak(@Param("userId") Long userId); - - - @Query(value = "SELECT * FROM user u WHERE CONCAT(u.first_name, ' ', u.last_name) LIKE %:searchTerm%", nativeQuery = true) - List<User> findUsersByName(@Param("searchTerm") String searchTerm); - - @Transactional - @Modifying - @Query("UPDATE User u SET u.subscriptionLevel = :subscriptionLevel WHERE u.id = :userId") - void updateSubscriptionLevel(@Param("userId") Long userId, @Param("subscriptionLevel") SubscriptionLevel subscriptionLevel); - - @Query(value = "SELECT SUM(total_earned_points) FROM point", nativeQuery = true) - long getSumTotalEarnedPoints(); - - @Transactional - @Modifying - @Query(value = "UPDATE point p " + - "JOIN user u ON u.point_id = p.point_id " + - "SET p.current_points = p.current_points - :points " + - "WHERE u.user_id = :userId", nativeQuery = true) - void deductPoints(@Param("userId") Long userId, @Param("points") int points); } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/security/AuthIdentity.java b/src/main/java/no/ntnu/idi/stud/savingsapp/security/AuthIdentity.java index 526337d69f45fe0600eadcb7e83df612fc4b673c..50fbb091c272934445c72fee60ae8fbfb8ca3ce6 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/security/AuthIdentity.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/security/AuthIdentity.java @@ -10,13 +10,14 @@ import lombok.Data; @AllArgsConstructor public class AuthIdentity { - /** - * The ID of the authenticated user. - */ - private long id; + /** + * The ID of the authenticated user. + */ + private long id; + + /** + * The role of the authenticated user. + */ + private String role; - /** - * The role of the authenticated user. - */ - private String role; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/security/AuthorizationFilter.java b/src/main/java/no/ntnu/idi/stud/savingsapp/security/AuthorizationFilter.java index c440a8375e81cbd84ce416f273712709dc0878fd..ef21b5deddf7f06ed7c4835c92a052213353b157 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/security/AuthorizationFilter.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/security/AuthorizationFilter.java @@ -23,65 +23,64 @@ import java.io.IOException; import java.util.Collections; /** - * Filter responsible for JSON Web Token (JWT) authorization. - * It extracts the JWT from the request header, validates it, and sets - * the authentication context. + * Filter responsible for JSON Web Token (JWT) authorization. It extracts the JWT from the + * request header, validates it, and sets the authentication context. */ public class AuthorizationFilter extends OncePerRequestFilter { - private static final Logger LOGGER = LogManager.getLogger(AuthorizationFilter.class); - private static final int TOKEN_PREFIX_LENGTH = 7; + private static final Logger LOGGER = LogManager.getLogger(AuthorizationFilter.class); - /** - * Filters incoming requests and processes JWT authorization. - * - * @param request The HTTP servlet request. - * @param response The HTTP servlet response. - * @param filterChain The filter chain for the request. - * @throws ServletException If an error occurs during servlet processing. - * @throws IOException If an I/O error occurs during request processing. - */ - @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, - FilterChain filterChain) throws ServletException, IOException { - final String header = request.getHeader(HttpHeaders.AUTHORIZATION); - if (header == null || !header.startsWith("Bearer ")) { - filterChain.doFilter(request, response); - return; - } + private static final int TOKEN_PREFIX_LENGTH = 7; - String token = header.substring(TOKEN_PREFIX_LENGTH); - final DecodedJWT decodedJWT = validateToken(token); - if (decodedJWT == null) { - filterChain.doFilter(request, response); - return; - } - long userId = Long.parseLong(decodedJWT.getSubject()); - String userRole = decodedJWT.getClaim("user_role").asString(); - String role = userRole.equals(Role.ADMIN.name()) ? "ADMIN" : "USER"; + /** + * Filters incoming requests and processes JWT authorization. + * @param request The HTTP servlet request. + * @param response The HTTP servlet response. + * @param filterChain The filter chain for the request. + * @throws ServletException If an error occurs during servlet processing. + * @throws IOException If an I/O error occurs during request processing. + */ + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + final String header = request.getHeader(HttpHeaders.AUTHORIZATION); + if (header == null || !header.startsWith("Bearer ")) { + filterChain.doFilter(request, response); + return; + } - UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( - new AuthIdentity(userId, role), null, - Collections.singletonList(new SimpleGrantedAuthority(role))); - SecurityContextHolder.getContext().setAuthentication(authentication); + String token = header.substring(TOKEN_PREFIX_LENGTH); + final DecodedJWT decodedJWT = validateToken(token); + if (decodedJWT == null) { + filterChain.doFilter(request, response); + return; + } + long userId = Long.parseLong(decodedJWT.getSubject()); + String userRole = decodedJWT.getClaim("user_role").asString(); + String role = userRole.equals(Role.ADMIN.name()) ? "ADMIN" : "USER"; - filterChain.doFilter(request, response); - } + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( + new AuthIdentity(userId, role), null, Collections.singletonList(new SimpleGrantedAuthority(role))); + SecurityContextHolder.getContext().setAuthentication(authentication); + + filterChain.doFilter(request, response); + } + + /** + * Validates the JWT token. + * @param token The JWT token to validate. + * @return The decoded JWT if valid, null otherwise. + */ + public DecodedJWT validateToken(final String token) { + try { + final Algorithm hmac512 = Algorithm.HMAC512(TokenProperties.SECRET); + final JWTVerifier verifier = JWT.require(hmac512).build(); + return verifier.verify(token); + } + catch (final JWTVerificationException verificationEx) { + LOGGER.warn("token is invalid: {}", verificationEx.getMessage()); + return null; + } + } - /** - * Validates the JWT token. - * - * @param token The JWT token to validate. - * @return The decoded JWT if valid, null otherwise. - */ - public DecodedJWT validateToken(final String token) { - try { - final Algorithm hmac512 = Algorithm.HMAC512(TokenProperties.SECRET); - final JWTVerifier verifier = JWT.require(hmac512).build(); - return verifier.verify(token); - } catch (final JWTVerificationException verificationEx) { - LOGGER.warn("token is invalid: {}", verificationEx.getMessage()); - return null; - } - } } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/security/SecurityConfig.java b/src/main/java/no/ntnu/idi/stud/savingsapp/security/SecurityConfig.java index 5badcbd18a8a37cdb5a1907971d2acbfbcb8a5f8..b26610ce104db0f71d78569d1189493e9a200553 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/security/SecurityConfig.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/security/SecurityConfig.java @@ -19,62 +19,63 @@ import java.util.Arrays; import java.util.List; /** - * Configuration class responsible for defining security configurations for the application. + * Configuration class responsible for defining security configurations for the + * application. */ @Configuration @EnableWebSecurity public class SecurityConfig { - /** - * Provides a bean for password encoder. - * - * @return A PasswordEncoder instance. - */ - @Bean - public PasswordEncoder encoder() { - return new BCryptPasswordEncoder(); - } + /** + * Provides a bean for password encoder. + * @return A PasswordEncoder instance. + */ + @Bean + public PasswordEncoder encoder() { + return new BCryptPasswordEncoder(); + } - /** - * Configures the security filter chain. - * - * @param http The HttpSecurity object to configure. - * @return A SecurityFilterChain instance. - * @throws Exception If an error occurs during configuration. - */ - @Bean - public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { - return http.cors() - .and() - .csrf() - .disable() - .authorizeHttpRequests(auth -> { - auth.dispatcherTypeMatchers(DispatcherType.ERROR).permitAll() - .requestMatchers("/swagger/**", "/api/auth/**", "/api/users/reset-password", "/api/users/send-feedback", - "/api/users/confirm-password", "/api/question/**", "/api/images/**", "/redirect", - "/bank/v1/account/balance/**").permitAll().anyRequest().authenticated(); - }) - .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() - .addFilterBefore(new AuthorizationFilter(), UsernamePasswordAuthenticationFilter.class) - .build(); - } + /** + * Configures the security filter chain. + * @param http The HttpSecurity object to configure. + * @return A SecurityFilterChain instance. + * @throws Exception If an error occurs during configuration. + */ + @Bean + public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { + return http.cors().and().csrf().disable().authorizeHttpRequests(auth -> { + auth.dispatcherTypeMatchers(DispatcherType.ERROR) + .permitAll() + .requestMatchers("/swagger/**", "/api/auth/**", "/api/users/reset-password", "/api/users/send-feedback", + "/api/users/confirm-password", "/api/question/**", "/api/images/**", "/redirect", + "/bank/v1/account/balance/**") + .permitAll() + .anyRequest() + .authenticated(); + }) + .sessionManagement() + .sessionCreationPolicy(SessionCreationPolicy.STATELESS) + .and() + .addFilterBefore(new AuthorizationFilter(), UsernamePasswordAuthenticationFilter.class) + .build(); + } - /** - * Provides a bean for configuring CORS (Cross-Origin Resource Sharing). - * - * @return A CorsConfigurationSource instance. - */ - @Bean - public CorsConfigurationSource corsConfigurationSource() { - CorsConfiguration config = new CorsConfiguration(); - config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS")); - config.setAllowedOrigins(List.of(SparestiApplication.getFrontendURL())); - config.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type", "Cache-Control")); - config.setAllowCredentials(true); + /** + * Provides a bean for configuring CORS (Cross-Origin Resource Sharing). + * @return A CorsConfigurationSource instance. + */ + @Bean + public CorsConfigurationSource corsConfigurationSource() { + CorsConfiguration config = new CorsConfiguration(); + config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS")); + config.setAllowedOrigins(List.of(SparestiApplication.getFrontendURL())); + config.setAllowedHeaders(Arrays.asList("Authorization", "Content-Type", "Cache-Control")); + config.setAllowCredentials(true); - UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); - source.registerCorsConfiguration("/**", config); + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", config); + + return source; + } - return source; - } } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/service/BadgeService.java b/src/main/java/no/ntnu/idi/stud/savingsapp/service/BadgeService.java index debe165b24f5707b02cabef3cb72ff4d05fed17d..48d754345c4a4d64707b00def22b5704fe5b1045 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/service/BadgeService.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/service/BadgeService.java @@ -11,50 +11,44 @@ import org.springframework.stereotype.Service; @Service public interface BadgeService { - /** - * Retrieves a badge by its badge id. - * - * @param badgeId the badge id - * @return the badge associated with its id. - */ - Badge findBadgeByBadgeId(Long badgeId); - - /** - * Retrieves a list of all badges. - * - * @return a list of all badges. - */ - List<Badge> findAllBadges(); - - /** - * Retrieves a list of all badges unlocked by a user. - * - * @param userId the id of the user - * @return a list of badges. - */ - List<Badge> findBadgesUnlockedByUser(Long userId); - - /** - * Retrieves a list of all badges that are not unlocked by a user. - * - * @param userId the id of the user - * @return a list of badges. - */ - List<Badge> findBadgesNotUnlockedByUser(Long userId); - - /** - * Retrieves a list of all badges that are not newly unlocked by a user. - * - * @param userId the id of the user - * @return a list of newly unlocked badges. - */ - List<Badge> findNewlyUnlockedBadgesByUserId(Long userId); - - /** - * Adds a badge to a user badge inventory. - * - * @param badgeUserId the BadgeUserId reference. - */ - void addBadgeToUser(BadgeUserId badgeUserId); + /** + * Retrieves a badge by its badge id. + * @param badgeId the badge id + * @return the badge associated with its id. + */ + Badge findBadgeByBadgeId(Long badgeId); + + /** + * Retrieves a list of all badges. + * @return a list of all badges. + */ + List<Badge> findAllBadges(); + + /** + * Retrieves a list of all badges unlocked by a user. + * @param userId the id of the user + * @return a list of badges. + */ + List<Badge> findBadgesUnlockedByUser(Long userId); + + /** + * Retrieves a list of all badges that are not unlocked by a user. + * @param userId the id of the user + * @return a list of badges. + */ + List<Badge> findBadgesNotUnlockedByUser(Long userId); + + /** + * Retrieves a list of all badges that are not newly unlocked by a user. + * @param userId the id of the user + * @return a list of newly unlocked badges. + */ + List<Badge> findNewlyUnlockedBadgesByUserId(Long userId); + + /** + * Adds a badge to a user badge inventory. + * @param badgeUserId the BadgeUserId reference. + */ + void addBadgeToUser(BadgeUserId badgeUserId); } \ No newline at end of file diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/service/BudgetService.java b/src/main/java/no/ntnu/idi/stud/savingsapp/service/BudgetService.java index ecb1fb03ffd366adb51ce115ed0d036b93213612..0d499802e577de01a7d2706e46e3793173d5f28e 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/service/BudgetService.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/service/BudgetService.java @@ -10,81 +10,73 @@ import org.springframework.stereotype.Service; */ @Service public interface BudgetService { - /** - * Retrieves a list of budgets associated with a user id. - * - * @param userId the if of the user - * @return a list of budgets. - */ - List<Budget> findBudgetsByUserId(Long userId); - /** - * Retrieves a list of expenses associated with a budget id. - * - * @param budgetId the id of the budget - * @return a list of expenses. - */ - List<Expense> findExpensesByBudgetId(Long budgetId); + /** + * Retrieves a list of budgets associated with a user id. + * @param userId the if of the user + * @return a list of budgets. + */ + List<Budget> findBudgetsByUserId(Long userId); - /** - * Creates a new budget. - * - * @param budget the budget to create - * @return the created budget. - */ - Budget createBudget(Budget budget); + /** + * Retrieves a list of expenses associated with a budget id. + * @param budgetId the id of the budget + * @return a list of expenses. + */ + List<Expense> findExpensesByBudgetId(Long budgetId); - /** - * Updates an existing budget. - * - * @param budget the budget to update - * @return the updated budget. - */ - Budget updateBudget(Budget budget); + /** + * Creates a new budget. + * @param budget the budget to create + * @return the created budget. + */ + Budget createBudget(Budget budget); - /** - * Retrieves a budget by its id. - * - * @param budgetId The id of the budget - * @return The budget with the specified id. - */ - Budget findBudgetById(Long budgetId); + /** + * Updates an existing budget. + * @param budget the budget to update + * @return the updated budget. + */ + Budget updateBudget(Budget budget); - /** - * Deletes a budget by its id. - * - * @param budgetId the id of the budget to delete - */ - void deleteBudgetById(Long budgetId); + /** + * Retrieves a budget by its id. + * @param budgetId The id of the budget + * @return The budget with the specified id. + */ + Budget findBudgetById(Long budgetId); - /** - * Creates a new expense. - * - * @param expense the expense to create - * @return the created expense - */ - Expense createExpense(Expense expense); + /** + * Deletes a budget by its id. + * @param budgetId the id of the budget to delete + */ + void deleteBudgetById(Long budgetId); - /** - * Updates an existing expense. - * - * @param expense the expense to update - * @return the updated expense - */ - Expense updateExpense(Expense expense); + /** + * Creates a new expense. + * @param expense the expense to create + * @return the created expense + */ + Expense createExpense(Expense expense); - /** - * Retrieves an expense by its id. - * - * @param expenseId the id of the expense - * @return the expense with the specified id. - */ - Expense findExpenseById(Long expenseId); + /** + * Updates an existing expense. + * @param expense the expense to update + * @return the updated expense + */ + Expense updateExpense(Expense expense); + + /** + * Retrieves an expense by its id. + * @param expenseId the id of the expense + * @return the expense with the specified id. + */ + Expense findExpenseById(Long expenseId); + + /** + * Deletes an expense by its id. + * @param expenseId the id of the expense to delete. + */ + void deleteExpenseById(Long expenseId); - /** - * Deletes an expense by its id. - * - * @param expenseId the id of the expense to delete. - */ - void deleteExpenseById(Long expenseId); } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/service/ChallengeService.java b/src/main/java/no/ntnu/idi/stud/savingsapp/service/ChallengeService.java index 0c02092a2192761a7665d3d6cd584cfcb51bda4a..555289ef26e09e4d4cd2d655ed41dc0c0e1a5776 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/service/ChallengeService.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/service/ChallengeService.java @@ -14,49 +14,51 @@ import java.util.List; @Service public interface ChallengeService { - /** - * Generates a list of challenges for a specified goal based on the user's preferences and the goal's details. - * This method should consider user-specific settings and the duration of the goal to tailor challenges accordingly. - * - * @param goal The goal for which challenges are being generated. - * @param user The user associated with the goal, whose preferences should influence the challenges. - * @return A list of generated Challenge objects that are tailored to the user's preferences and the goal's duration. - */ - List<Challenge> generateChallenges(Goal goal, User user); - - /** - * Updates the progress of a specific challenge on a given day by recording the amount achieved. - * This method is responsible for ensuring that the progress update is valid and that the user has permission to update the specified challenge. - * - * @param userId The ID of the user attempting to update the challenge. - * @param id The unique identifier of the challenge being updated. - * @param day The specific day of the challenge for which progress is being updated. - * @param amount The amount or value achieved on the specified day. - * @throws IllegalArgumentException if the user does not have permission to update the challenge or if the day or amount parameters are invalid. - */ - void updateProgress(long userId, long id, int day, BigDecimal amount); - - /** - * Updates the saving amount for a specific challenge identified by its ID. - * This method allows modifying the potential saving target for a given challenge, ensuring that - * users can adjust their saving goals as needed. - * - * @param userId The ID of the user who owns the challenge. This is used to verify ownership - * and permission to update the challenge. - * @param id The ID of the challenge whose saving amount is to be updated. - * @param amount The new saving amount to be set for the challenge. This amount should - * reflect the new target savings the user aims to achieve. - */ - void updateSavingAmount(long userId, long id, BigDecimal amount); - - /** - * Replaces that challenge in a given goal identified by the challenge ID. - * This method is useful for letting the user change out challenges they know - * they will not be able to do - * - * @param userId the ID of the user who sends the request - * @param challengeId The ID of the challenge that will be replaced - * @return The updated goal containing the new challenge - */ - Challenge regenerateChallenge(long userId, long challengeId); + /** + * Generates a list of challenges for a specified goal based on the user's preferences + * and the goal's details. This method should consider user-specific settings and the + * duration of the goal to tailor challenges accordingly. + * @param goal The goal for which challenges are being generated. + * @param user The user associated with the goal, whose preferences should influence + * the challenges. + * @return A list of generated Challenge objects that are tailored to the user's + * preferences and the goal's duration. + */ + List<Challenge> generateChallenges(Goal goal, User user); + + /** + * Updates the progress of a specific challenge on a given day by recording the amount + * achieved. This method is responsible for ensuring that the progress update is valid + * and that the user has permission to update the specified challenge. + * @param userId The ID of the user attempting to update the challenge. + * @param id The unique identifier of the challenge being updated. + * @param day The specific day of the challenge for which progress is being updated. + * @param amount The amount or value achieved on the specified day. + * @throws IllegalArgumentException if the user does not have permission to update the + * challenge or if the day or amount parameters are invalid. + */ + void updateProgress(long userId, long id, int day, BigDecimal amount); + + /** + * Updates the saving amount for a specific challenge identified by its ID. This + * method allows modifying the potential saving target for a given challenge, ensuring + * that users can adjust their saving goals as needed. + * @param userId The ID of the user who owns the challenge. This is used to verify + * ownership and permission to update the challenge. + * @param id The ID of the challenge whose saving amount is to be updated. + * @param amount The new saving amount to be set for the challenge. This amount should + * reflect the new target savings the user aims to achieve. + */ + void updateSavingAmount(long userId, long id, BigDecimal amount); + + /** + * Replaces that challenge in a given goal identified by the challenge ID. This method + * is useful for letting the user change out challenges they know they will not be + * able to do + * @param userId the ID of the user who sends the request + * @param challengeId The ID of the challenge that will be replaced + * @return The updated goal containing the new challenge + */ + Challenge regenerateChallenge(long userId, long challengeId); + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/service/FriendService.java b/src/main/java/no/ntnu/idi/stud/savingsapp/service/FriendService.java index 5a79156ae4b88bf27cdffbf1bace419cddb7f675..13676084eff655cc50c547882051d4485e9f13bb 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/service/FriendService.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/service/FriendService.java @@ -12,59 +12,54 @@ import no.ntnu.idi.stud.savingsapp.model.user.User; */ @Service public interface FriendService { - /** - * Retrieves all friends associated with a given user ID. - * - * @param userId The ID of the user whose friends are to be retrieved. - * @return A list of Friend objects representing the user's friends. - */ - List<Friend> getFriends(Long userId); - - /** - * Retrieves all pending friend requests for a given user ID. - * - * @param userId The ID of the user whose friend requests are to be retrieved. - * @return A list of Friend objects representing the friend requests. - */ - List<Friend> getFriendRequests(Long userId); - /** - * Sends a friend request from one user to another. - * - * @param user The user sending the friend request. - * @param friend The user to receive the friend request. - */ - void addFriendRequest(User user, User friend); + /** + * Retrieves all friends associated with a given user ID. + * @param userId The ID of the user whose friends are to be retrieved. + * @return A list of Friend objects representing the user's friends. + */ + List<Friend> getFriends(Long userId); - /** - * Retrieves a specific friend request between two users. - * - * @param user The user who sent the friend request. - * @param friend The user who received the friend request. - * @return The Friend object if a request exists, otherwise null. - */ - Friend getFriendRequest(User user, User friend); + /** + * Retrieves all pending friend requests for a given user ID. + * @param userId The ID of the user whose friend requests are to be retrieved. + * @return A list of Friend objects representing the friend requests. + */ + List<Friend> getFriendRequests(Long userId); - /** - * Accepts a friend request, changing the attribute pending to false. - * - * @param friendRequest The friend request to be accepted. - */ - void acceptFriendRequest(Friend friendRequest); + /** + * Sends a friend request from one user to another. + * @param user The user sending the friend request. + * @param friend The user to receive the friend request. + */ + void addFriendRequest(User user, User friend); - /** - * Get a Friend object if a relationship between the two users exists. - * - * @param user The first user. - * @param friend The second user. - * @return The Friend object representing the current status of their relationship. - */ - Friend getFriendStatus(User user, User friend); + /** + * Retrieves a specific friend request between two users. + * @param user The user who sent the friend request. + * @param friend The user who received the friend request. + * @return The Friend object if a request exists, otherwise null. + */ + Friend getFriendRequest(User user, User friend); + + /** + * Accepts a friend request, changing the attribute pending to false. + * @param friendRequest The friend request to be accepted. + */ + void acceptFriendRequest(Friend friendRequest); + + /** + * Get a Friend object if a relationship between the two users exists. + * @param user The first user. + * @param friend The second user. + * @return The Friend object representing the current status of their relationship. + */ + Friend getFriendStatus(User user, User friend); + + /** + * Deletes a friendship or a friend request between two users. + * @param friendStatus The friendship or friend request to be deleted. + */ + void deleteFriendOrFriendRequest(Friend friendStatus); - /** - * Deletes a friendship or a friend request between two users. - * - * @param friendStatus The friendship or friend request to be deleted. - */ - void deleteFriendOrFriendRequest(Friend friendStatus); } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/service/GoalService.java b/src/main/java/no/ntnu/idi/stud/savingsapp/service/GoalService.java index d4ca02e5d75f26b04c6f9977046be4591320d3b8..d7f8ca5f4ad9038b4478a28f0261e1a0a18ef8e1 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/service/GoalService.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/service/GoalService.java @@ -13,40 +13,37 @@ import java.util.List; @Service public interface GoalService { - /** - * Creates and persists a new goal for a specific user. - * This method is responsible for setting the initial parameters of the goal, associating it with a user, - * and saving it to the database. - * - * @param goal The goal object containing the initial data for the goal. - * @param userId The ID of the user for whom the goal is being created. - * @return The newly created and persisted Goal object. - */ - Goal createGoal(Goal goal, List<GroupUserDTO> GroupUsers, long userId); - - /** - * Retrieves all goals associated with a specific user. - * This method is used to fetch all goals that belong to a user, based on the user's ID. - * - * @param userId The ID of the user whose goals are to be retrieved. - * @return A list of Goal objects associated with the specified user. - * The list may be empty if the user has no goals. - */ - List<Goal> getGoals(long userId); - - /** - * Retrieves a goal associated with a specific user. - * - * @param goalId The ID of the user whose goals are to be retrieved. - * @return A goal object associated with the specified user. - */ - Goal getGoal(long goalId); - - /** - * Retrieves a group associated with a specific goal - * - * @param goalId the goal that the group contains - * @return A group object associated with the specified goal - */ - Group getGroup(Long goalId); + /** + * Creates and persists a new goal for a specific user. This method is responsible for + * setting the initial parameters of the goal, associating it with a user, and saving + * it to the database. + * @param goal The goal object containing the initial data for the goal. + * @param userId The ID of the user for whom the goal is being created. + * @return The newly created and persisted Goal object. + */ + Goal createGoal(Goal goal, List<GroupUserDTO> GroupUsers, long userId); + + /** + * Retrieves all goals associated with a specific user. This method is used to fetch + * all goals that belong to a user, based on the user's ID. + * @param userId The ID of the user whose goals are to be retrieved. + * @return A list of Goal objects associated with the specified user. The list may be + * empty if the user has no goals. + */ + List<Goal> getGoals(long userId); + + /** + * Retrieves a goal associated with a specific user. + * @param goalId The ID of the user whose goals are to be retrieved. + * @return A goal object associated with the specified user. + */ + Goal getGoal(long goalId); + + /** + * Retrieves a group associated with a specific goal + * @param goalId the goal that the group contains + * @return A group object associated with the specified goal + */ + Group getGroup(Long goalId); + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/service/ImageService.java b/src/main/java/no/ntnu/idi/stud/savingsapp/service/ImageService.java index c51eb6674f043b39372b307cdc544bc6b11bd01d..811c875bdb32ee02104aa221507000778e690a18 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/service/ImageService.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/service/ImageService.java @@ -9,21 +9,20 @@ import org.springframework.stereotype.Service; @Service public interface ImageService { - /** - * Saves an image in the data store. - * - * @param name The name of the image file. - * @param data The binary data of the image. - * @return The Image object representing the saved image, including its metadata. - */ - Image saveImage(String name, byte[] data); + /** + * Saves an image in the data store. + * @param name The name of the image file. + * @param data The binary data of the image. + * @return The Image object representing the saved image, including its metadata. + */ + Image saveImage(String name, byte[] data); + + /** + * Retrieves an image from the data store by its unique identifier. + * @param id The unique identifier of the image to retrieve. + * @return The Image object containing all relevant data about the image, including + * its binary data. + */ + Image getImage(long id); - /** - * Retrieves an image from the data store by its unique identifier. - * - * @param id The unique identifier of the image to retrieve. - * @return The Image object containing all relevant data about the image, - * including its binary data. - */ - Image getImage(long id); } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/service/ItemService.java b/src/main/java/no/ntnu/idi/stud/savingsapp/service/ItemService.java index cc6106951cb5aa86470de38925ff8d69425401ab..c1013f85cf092ecad7502702008958e633858e2f 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/service/ItemService.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/service/ItemService.java @@ -12,34 +12,35 @@ import no.ntnu.idi.stud.savingsapp.model.user.User; */ @Service public interface ItemService { - /** - * Retrieves the inventory of items for a specific user. - * - * @param userId the unique identifier of the user whose inventory is to be retrieved - * @return a list of {@link Item} objects representing the user's inventory - */ - List<Item> getInventory(Long userId); - - /** - * Retrieves a list of all items available in the store. - * - * @return a list of {@link Item} objects representing all items currently available in the store - */ - List<Item> getStore(); - - /** - * Retrieves a specific item from the store based on its identifier. - * - * @param itemId the unique identifier of the item to be retrieved - * @return the {@link Item} corresponding to the provided identifier, or null if no such item exists - */ - Item getItemFromId(Long itemId); - - /** - * Adds an item to the inventory of a specified user. - * - * @param user the {@link User} object representing the user to whom the item will be added - * @param item the {@link Item} to be added to the user's inventory - */ - Boolean addItem(User user, Item item); + + /** + * Retrieves the inventory of items for a specific user. + * @param userId the unique identifier of the user whose inventory is to be retrieved + * @return a list of {@link Item} objects representing the user's inventory + */ + List<Item> getInventory(Long userId); + + /** + * Retrieves a list of all items available in the store. + * @return a list of {@link Item} objects representing all items currently available + * in the store + */ + List<Item> getStore(); + + /** + * Retrieves a specific item from the store based on its identifier. + * @param itemId the unique identifier of the item to be retrieved + * @return the {@link Item} corresponding to the provided identifier, or null if no + * such item exists + */ + Item getItemFromId(Long itemId); + + /** + * Adds an item to the inventory of a specified user. + * @param user the {@link User} object representing the user to whom the item will be + * added + * @param item the {@link Item} to be added to the user's inventory + */ + Boolean addItem(User user, Item item); + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/service/LeaderboardService.java b/src/main/java/no/ntnu/idi/stud/savingsapp/service/LeaderboardService.java index 680f6e8d50f7c8f21d6ddd9bece869fa4886d714..5864bdfe37b1de23ba2ef249a4b795677feec7dc 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/service/LeaderboardService.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/service/LeaderboardService.java @@ -11,35 +11,40 @@ import no.ntnu.idi.stud.savingsapp.model.leaderboard.LeaderboardType; */ @Service public interface LeaderboardService { - /** - * Retrieves a leaderboard containing the top users based on the specified type and filter. - * - * @param type The type of leaderboard to retrieve (e.g., TOTAL_POINTS, CURRENT_STREAK, TOP_STREAK). - * @param filter The filter for who the leaderboard should contain (e.g., GLOBAL or FRIENDS). - * @param entryCount The amount of entries you want the leaderboard to contain. - * @param userId The ID of the user if you wanna find a leaderboard filtered on FRIENDS. - * @return A Leaderboard object containing the top entries for the specified type and filter. - */ - Leaderboard getTopUsers(LeaderboardType type, LeaderboardFilter filter, int entryCount, Long userId); - /** - * Retrieves a leaderboard containing the users surrounding a user on the specified type and filter. - * User with ID userID will be in the middle. - * - * @param type The type of leaderboard to retrieve (e.g., TOTAL_POINTS, CURRENT_STREAK, TOP_STREAK). - * @param filter The filter for who the leaderboard should contain (e.g., GLOBAL or FRIENDS). - * @param entryCount The amount of entries you want the leaderboard to contain. - * @param userId The ID of the user you want to be in the middle of the leaderboard. - * @return A Leaderboard object containing the specified user entry in the middle and entries surrounding it for the specified type and filter. - */ - Leaderboard getSurrounding(LeaderboardType type, LeaderboardFilter filter, int entryCount, Long userId); + /** + * Retrieves a leaderboard containing the top users based on the specified type and + * filter. + * @param type The type of leaderboard to retrieve (e.g., TOTAL_POINTS, + * CURRENT_STREAK, TOP_STREAK). + * @param filter The filter for who the leaderboard should contain (e.g., GLOBAL or + * FRIENDS). + * @param entryCount The amount of entries you want the leaderboard to contain. + * @param userId The ID of the user if you wanna find a leaderboard filtered on + * FRIENDS. + * @return A Leaderboard object containing the top entries for the specified type and + * filter. + */ + Leaderboard getTopUsers(LeaderboardType type, LeaderboardFilter filter, int entryCount, Long userId); - /** - * Get the total sum of the total points of all users. - * - * @return Long - */ - long getSumTotalEarnedPoints(); + /** + * Retrieves a leaderboard containing the users surrounding a user on the specified + * type and filter. User with ID userID will be in the middle. + * @param type The type of leaderboard to retrieve (e.g., TOTAL_POINTS, + * CURRENT_STREAK, TOP_STREAK). + * @param filter The filter for who the leaderboard should contain (e.g., GLOBAL or + * FRIENDS). + * @param entryCount The amount of entries you want the leaderboard to contain. + * @param userId The ID of the user you want to be in the middle of the leaderboard. + * @return A Leaderboard object containing the specified user entry in the middle and + * entries surrounding it for the specified type and filter. + */ + Leaderboard getSurrounding(LeaderboardType type, LeaderboardFilter filter, int entryCount, Long userId); + /** + * Get the total sum of the total points of all users. + * @return Long + */ + long getSumTotalEarnedPoints(); } \ No newline at end of file diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/service/NotificationService.java b/src/main/java/no/ntnu/idi/stud/savingsapp/service/NotificationService.java index e66c0d3550941929830ff62e15e51f1f37d40688..5f1fd2f972eca7b5a6ba99425cecf01ef476bbb3 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/service/NotificationService.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/service/NotificationService.java @@ -10,35 +10,32 @@ import org.springframework.stereotype.Service; @Service public interface NotificationService { - /** - * Retrieves a notification by its id. - * - * @param notificationId the unique identifier for the notification - * @return the {@link Notification} to the notificationId. - */ - Notification getNotificationById(long notificationId); + /** + * Retrieves a notification by its id. + * @param notificationId the unique identifier for the notification + * @return the {@link Notification} to the notificationId. + */ + Notification getNotificationById(long notificationId); - /** - * Retrieves a list of all notifications belonging to a user. - * - * @param userId the unique identifier for the user - * @return a list of {@link Notification} objects belonging to the user. - */ - List<Notification> getNotificationsByUserId(long userId); + /** + * Retrieves a list of all notifications belonging to a user. + * @param userId the unique identifier for the user + * @return a list of {@link Notification} objects belonging to the user. + */ + List<Notification> getNotificationsByUserId(long userId); - /** - * Retrieves a list of all unread notifications belonging to a user. - * - * @param userId the unique identifier for the user - * @return a list of unread {@link Notification} objects belonging to the user. - */ - List<Notification> getUnreadNotificationsByUserId(long userId); + /** + * Retrieves a list of all unread notifications belonging to a user. + * @param userId the unique identifier for the user + * @return a list of unread {@link Notification} objects belonging to the user. + */ + List<Notification> getUnreadNotificationsByUserId(long userId); + + /** + * Updates a notification by a new requested notification. Can alternatively create a + * new notification. + * @param notification the {@link Notification} object to update. + */ + void updateNotification(Notification notification); - /** - * Updates a notification by a new requested notification. - * Can alternatively create a new notification. - * - * @param notification the {@link Notification} object to update. - */ - void updateNotification(Notification notification); } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/service/UserService.java b/src/main/java/no/ntnu/idi/stud/savingsapp/service/UserService.java index 16adfa92404e68d3c9ae7aa35e3cd55560cabd28..d1ac32a7b94e8d6910bfc767c3915b7fd09e285f 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/service/UserService.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/service/UserService.java @@ -1,6 +1,5 @@ package no.ntnu.idi.stud.savingsapp.service; - import no.ntnu.idi.stud.savingsapp.model.user.Feedback; import no.ntnu.idi.stud.savingsapp.model.user.SearchFilter; import no.ntnu.idi.stud.savingsapp.model.user.SubscriptionLevel; @@ -16,170 +15,160 @@ import org.springframework.stereotype.Service; @Service public interface UserService { - /** - * Authenticates a user with the provided email and password. - * - * @param email The email address of the user. - * @param password The password associated with the user's account. - * @return The authenticated user object if login is successful, or null otherwise. - */ - User login(String email, String password); - - /** - * Registers a new user. - * - * @param user The user object containing registration information. - * @return The registered user object. - */ - User register(User user); - - /** - * Authenticates a user using the BankID authentication mechanism. - * This method processes the authentication by using a unique code and state received from the BankID service. - * - * @param code The unique authorization code received from BankID after the user's successful authorization. - * This code is used to request the access token from BankID servers. - * @param state The state parameter initially sent by the application to BankID to prevent CSRF attacks. - * This should match the state stored in the session or a similar safe place to ensure that - * the response corresponds to the user's request. - * @return A User object representing the authenticated user. This object includes user-specific data - * such as user ID, profile details, and roles, if authentication is successful. - */ - User bankIDAuth(String code, String state); - - /** - * Updates the information of an existing user. - * - * @param user The User object containing updated information. - * @return The updated User object, persisted in the database. - */ - User update(User user); - - /** - * Deletes a user from the system based on the specified user ID. - * This method permanently removes the user's record from the database. It should be used with caution, - * as this operation is irreversible and results in the loss of all data associated with the user's account. - * - * @param userId The unique identifier of the user to be deleted. - */ - void delete(long userId); - - /** - * Updates the password of a user. - * - * @param id The ID of the user - * @param oldPassword The old password - * @param newPassword The new password - * @return The updated User object, persisted in the database. - */ - User updatePassword(long id, String oldPassword, String newPassword); - - /** - * Retrieves a user by their email address. - * - * @param email The email address to search for in the user database. - * @return The User object associated with the specified email if found. - */ - User findByEmail(String email); - - /** - * Retrieves a user by their unique identifier. - * - * @param id The unique ID of the user. - * @return The User object associated with the specified ID if found. - */ - User findById(long id); - - /** - * Initiates the password reset process for a user identified by their email address. - * - * @param email The email address of the user requesting a password reset. - */ - void initiatePasswordReset(String email); - - /** - * Completes the password reset process by updating the user's password based on the provided reset token. - * - * @param token The password reset token that was sent to the user. - * @param password The new password to set for the user. - */ - void confirmPasswordReset(String token, String password); - - /** - * Retrieves a list of {@link User} objects representing the friends of the specified user. - * - * @param userId The ID of the user whose friends are to be retrieved - * @return a list of {@link User} instances representing the user's friends - */ - List<User> getFriends(Long userId); - - /** - * Retrieves a list of {@link User} objects representing the friend requests of the specified user. - * - * @param userId The ID of the user whose friend requests are to be retrieved - * @return a list of {@link User} instances representing the user's friend requests - */ - List<User> getFriendRequests(Long userId); - - /** - * Retrieves a list of User entities based on a search term and a specified filter. - * - * @param userId The ID of the user. Used to exclude that user and all of its friends - * from the result depending on filter. - * @param searchTerm The search term used to filter user names. - * @param filter A filter that is used to filter based on a category. - * @return A list of User objects that match the search criteria and filter. - */ - List<User> getUsersByNameAndFilter(Long userId, String searchTerm, SearchFilter filter); - - /** - * Retrieves a list of randomly selected {@link User} objects based on the specified filter. - * - * @param userId The ID of the user. Used to exclude that user and all of its friends - * from the result depending on filter. - * @param amount The number of random users to retrieve. - * @param filter A filter that is used to filter based on a category. - * @return A list of randomly selected {@link User} objects. - */ - List<User> getRandomUsers(Long userId, int amount, SearchFilter filter); - /** - * Updates the subscription level of a specified user. - * - * @param userId The ID of the user whose subscription level is to be updated. - * @param subscriptionLevel The new SubscriptionLevel to assign to the user. - */ - void updateSubscriptionLevel(Long userId, SubscriptionLevel subscriptionLevel); - - /** - * Sends feedback from an email. - * - * @param email The email. - * @param message The message. - */ - void sendFeedback(String email, String message); - - /** - * Get all feedback. - * - * @return A list containing all feedback. - */ - List<Feedback> getFeedback(); - - /** - * Check if the user has more than or equal to - * amount of current points as points - * - * @param user the user - * @param points the amount of points to compare with - * @return true or false - */ - Boolean hasMorePoints(User user, int points); - - /** - * Deduct a number of current points from the user - * - * @param userId The user - * @param points The amount of current points to deduct - */ - void deductPoints(Long userId, int points); + /** + * Authenticates a user with the provided email and password. + * @param email The email address of the user. + * @param password The password associated with the user's account. + * @return The authenticated user object if login is successful, or null otherwise. + */ + User login(String email, String password); + + /** + * Registers a new user. + * @param user The user object containing registration information. + * @return The registered user object. + */ + User register(User user); + + /** + * Authenticates a user using the BankID authentication mechanism. This method + * processes the authentication by using a unique code and state received from the + * BankID service. + * @param code The unique authorization code received from BankID after the user's + * successful authorization. This code is used to request the access token from BankID + * servers. + * @param state The state parameter initially sent by the application to BankID to + * prevent CSRF attacks. This should match the state stored in the session or a + * similar safe place to ensure that the response corresponds to the user's request. + * @return A User object representing the authenticated user. This object includes + * user-specific data such as user ID, profile details, and roles, if authentication + * is successful. + */ + User bankIDAuth(String code, String state); + + /** + * Updates the information of an existing user. + * @param user The User object containing updated information. + * @return The updated User object, persisted in the database. + */ + User update(User user); + + /** + * Deletes a user from the system based on the specified user ID. This method + * permanently removes the user's record from the database. It should be used with + * caution, as this operation is irreversible and results in the loss of all data + * associated with the user's account. + * @param userId The unique identifier of the user to be deleted. + */ + void delete(long userId); + + /** + * Updates the password of a user. + * @param id The ID of the user + * @param oldPassword The old password + * @param newPassword The new password + * @return The updated User object, persisted in the database. + */ + User updatePassword(long id, String oldPassword, String newPassword); + + /** + * Retrieves a user by their email address. + * @param email The email address to search for in the user database. + * @return The User object associated with the specified email if found. + */ + User findByEmail(String email); + + /** + * Retrieves a user by their unique identifier. + * @param id The unique ID of the user. + * @return The User object associated with the specified ID if found. + */ + User findById(long id); + + /** + * Initiates the password reset process for a user identified by their email address. + * @param email The email address of the user requesting a password reset. + */ + void initiatePasswordReset(String email); + + /** + * Completes the password reset process by updating the user's password based on the + * provided reset token. + * @param token The password reset token that was sent to the user. + * @param password The new password to set for the user. + */ + void confirmPasswordReset(String token, String password); + + /** + * Retrieves a list of {@link User} objects representing the friends of the specified + * user. + * @param userId The ID of the user whose friends are to be retrieved + * @return a list of {@link User} instances representing the user's friends + */ + List<User> getFriends(Long userId); + + /** + * Retrieves a list of {@link User} objects representing the friend requests of the + * specified user. + * @param userId The ID of the user whose friend requests are to be retrieved + * @return a list of {@link User} instances representing the user's friend requests + */ + List<User> getFriendRequests(Long userId); + + /** + * Retrieves a list of User entities based on a search term and a specified filter. + * @param userId The ID of the user. Used to exclude that user and all of its friends + * from the result depending on filter. + * @param searchTerm The search term used to filter user names. + * @param filter A filter that is used to filter based on a category. + * @return A list of User objects that match the search criteria and filter. + */ + List<User> getUsersByNameAndFilter(Long userId, String searchTerm, SearchFilter filter); + + /** + * Retrieves a list of randomly selected {@link User} objects based on the specified + * filter. + * @param userId The ID of the user. Used to exclude that user and all of its friends + * from the result depending on filter. + * @param amount The number of random users to retrieve. + * @param filter A filter that is used to filter based on a category. + * @return A list of randomly selected {@link User} objects. + */ + List<User> getRandomUsers(Long userId, int amount, SearchFilter filter); + + /** + * Updates the subscription level of a specified user. + * @param userId The ID of the user whose subscription level is to be updated. + * @param subscriptionLevel The new SubscriptionLevel to assign to the user. + */ + void updateSubscriptionLevel(Long userId, SubscriptionLevel subscriptionLevel); + + /** + * Sends feedback from an email. + * @param email The email. + * @param message The message. + */ + void sendFeedback(String email, String message); + + /** + * Get all feedback. + * @return A list containing all feedback. + */ + List<Feedback> getFeedback(); + + /** + * Check if the user has more than or equal to amount of current points as points + * @param user the user + * @param points the amount of points to compare with + * @return true or false + */ + Boolean hasMorePoints(User user, int points); + + /** + * Deduct a number of current points from the user + * @param userId The user + * @param points The amount of current points to deduct + */ + void deductPoints(Long userId, int points); + } \ No newline at end of file diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/BadgeServiceImpl.java b/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/BadgeServiceImpl.java index b88b6a1424ba4172254417ea1f8c3b744bf16a0c..b08fef808d70b1aad3a8555642112a399712c77e 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/BadgeServiceImpl.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/BadgeServiceImpl.java @@ -22,81 +22,77 @@ import org.springframework.stereotype.Service; @Slf4j public class BadgeServiceImpl implements BadgeService { - @Autowired - private BadgeRepository badgeRepository; + @Autowired + private BadgeRepository badgeRepository; - @Autowired - private BadgeUserRepository badgeUserRepository; + @Autowired + private BadgeUserRepository badgeUserRepository; - /** - * Retrieves a badge by its badge id. - * - * @param badgeId the badge id - * @return the badge associated with its id. - * @throws BadgeNotFoundException if the badge does not exist. - */ - @Override - public Badge findBadgeByBadgeId(Long badgeId) { - Optional<Badge> optionalBadge = badgeRepository.findBadgeById(badgeId); - if (optionalBadge.isPresent()) { - return optionalBadge.get(); - } else { - log.error("[BadgeServiceImpl:findBadgeByBadgeId] Badge is not found, id: {}", badgeId); - throw new BadgeNotFoundException(); - } - } + /** + * Retrieves a badge by its badge id. + * @param badgeId the badge id + * @return the badge associated with its id. + * @throws BadgeNotFoundException if the badge does not exist. + */ + @Override + public Badge findBadgeByBadgeId(Long badgeId) { + Optional<Badge> optionalBadge = badgeRepository.findBadgeById(badgeId); + if (optionalBadge.isPresent()) { + return optionalBadge.get(); + } + else { + log.error("[BadgeServiceImpl:findBadgeByBadgeId] Badge is not found, id: {}", badgeId); + throw new BadgeNotFoundException(); + } + } - /** - * Retrieves a list of all badges. - * - * @return a list of all badges. - */ - @Override - public List<Badge> findAllBadges() { - return badgeRepository.findAllBadges(); - } + /** + * Retrieves a list of all badges. + * @return a list of all badges. + */ + @Override + public List<Badge> findAllBadges() { + return badgeRepository.findAllBadges(); + } - /** - * Retrieves a list of all badges unlocked by a user. - * - * @param userId the id of the user - * @return a list of badges. - */ - @Override - public List<Badge> findBadgesUnlockedByUser(Long userId) { - return badgeRepository.findBadgesUnlockedByUserId(userId); - } + /** + * Retrieves a list of all badges unlocked by a user. + * @param userId the id of the user + * @return a list of badges. + */ + @Override + public List<Badge> findBadgesUnlockedByUser(Long userId) { + return badgeRepository.findBadgesUnlockedByUserId(userId); + } - /** - * Retrieves a list of all badges that are not unlocked by a user. - * - * @param userId the id of the user - * @return a list of badges. - */ - @Override - public List<Badge> findBadgesNotUnlockedByUser(Long userId) { - return badgeRepository.findBadgesNotUnlockedByUserId(userId); - } + /** + * Retrieves a list of all badges that are not unlocked by a user. + * @param userId the id of the user + * @return a list of badges. + */ + @Override + public List<Badge> findBadgesNotUnlockedByUser(Long userId) { + return badgeRepository.findBadgesNotUnlockedByUserId(userId); + } - /** - * Retrieves a list of all badges that are not newly unlocked by a user. - * - * @param userId the id of the user - * @return a list of newly unlocked badges. - */ - @Override - public List<Badge> findNewlyUnlockedBadgesByUserId(Long userId) { - return badgeRepository.findNewlyUnlockedBadgesByUserId(userId); - } + /** + * Retrieves a list of all badges that are not newly unlocked by a user. + * @param userId the id of the user + * @return a list of newly unlocked badges. + */ + @Override + public List<Badge> findNewlyUnlockedBadgesByUserId(Long userId) { + return badgeRepository.findNewlyUnlockedBadgesByUserId(userId); + } + + /** + * Adds a badge to a user badge inventory. + * @param badgeUserId the BadgeUserId reference. + */ + @Override + public void addBadgeToUser(BadgeUserId badgeUserId) { + BadgeUser badgeUser = new BadgeUser(badgeUserId, Timestamp.from(Instant.now())); + badgeUserRepository.save(badgeUser); + } - /** - * Adds a badge to a user badge inventory. - * - * @param badgeUserId the BadgeUserId reference. - */ - @Override - public void addBadgeToUser(BadgeUserId badgeUserId) { - BadgeUser badgeUser = new BadgeUser(badgeUserId, Timestamp.from(Instant.now())); - badgeUserRepository.save(badgeUser); - } } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/BudgetServiceImpl.java b/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/BudgetServiceImpl.java index a61ed7e363da3388cbd23ba487e04d03e5216172..6a6380097d8737b7ccbb4909ff35bd4f18a72b12 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/BudgetServiceImpl.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/BudgetServiceImpl.java @@ -23,170 +23,169 @@ import org.springframework.stereotype.Service; @Slf4j public class BudgetServiceImpl implements BudgetService { - @Autowired - private BudgetRepository budgetRepository; + @Autowired + private BudgetRepository budgetRepository; - @Autowired - private ExpenseRepository expenseRepository; + @Autowired + private ExpenseRepository expenseRepository; - /** - * Retrieves a list of budgets associated with a user id. - * - * @param userId the if of the user - * @return a list of budgets. - */ - @Override - public List<Budget> findBudgetsByUserId(Long userId) { - return budgetRepository.findBudgetsByUserId(userId); - } + /** + * Retrieves a list of budgets associated with a user id. + * @param userId the if of the user + * @return a list of budgets. + */ + @Override + public List<Budget> findBudgetsByUserId(Long userId) { + return budgetRepository.findBudgetsByUserId(userId); + } - /** - * Retrieves a list of expenses associated with a budget id. - * - * @param budgetId the id of the budget - * @return a list of expenses. - */ - @Override - public List<Expense> findExpensesByBudgetId(Long budgetId) { - return expenseRepository.findExpensesByBudgetId(budgetId); - } + /** + * Retrieves a list of expenses associated with a budget id. + * @param budgetId the id of the budget + * @return a list of expenses. + */ + @Override + public List<Expense> findExpensesByBudgetId(Long budgetId) { + return expenseRepository.findExpensesByBudgetId(budgetId); + } - /** - * Creates a new budget. - * - * @param budget the budget to create - * @return the created budget. - * @throws DataIntegrityViolationException if an error occurred. - */ - @Override - public Budget createBudget(Budget budget) { - budget.setCreatedAt(Timestamp.from(Instant.now())); - try { - return budgetRepository.save(budget); - } catch (DataIntegrityViolationException e) { - log.error("[BudgetServiceImpl:createBudget] Error while creating budget"); - throw new DataIntegrityViolationException("Error creating budget"); - } - } + /** + * Creates a new budget. + * @param budget the budget to create + * @return the created budget. + * @throws DataIntegrityViolationException if an error occurred. + */ + @Override + public Budget createBudget(Budget budget) { + budget.setCreatedAt(Timestamp.from(Instant.now())); + try { + return budgetRepository.save(budget); + } + catch (DataIntegrityViolationException e) { + log.error("[BudgetServiceImpl:createBudget] Error while creating budget"); + throw new DataIntegrityViolationException("Error creating budget"); + } + } - /** - * Updates an existing budget. - * - * @param budget the budget to update - * @return the updated budget. - * @throws DataIntegrityViolationException if an error occurred. - */ - @Override - public Budget updateBudget(Budget budget) { - try { - return budgetRepository.save(budget); - } catch (DataIntegrityViolationException e) { - log.error("[BudgetServiceImpl:updateBudget] Error while updating budget"); - throw new DataIntegrityViolationException("Error updating budget"); - } - } + /** + * Updates an existing budget. + * @param budget the budget to update + * @return the updated budget. + * @throws DataIntegrityViolationException if an error occurred. + */ + @Override + public Budget updateBudget(Budget budget) { + try { + return budgetRepository.save(budget); + } + catch (DataIntegrityViolationException e) { + log.error("[BudgetServiceImpl:updateBudget] Error while updating budget"); + throw new DataIntegrityViolationException("Error updating budget"); + } + } - /** - * Retrieves a budget by its id. - * - * @param budgetId the id of the budget - * @return the budget with the specified id. - * @throws BudgetNotFoundException if budget is not found. - */ - @Override - public Budget findBudgetById(Long budgetId) { - Optional<Budget> optionalBudget = budgetRepository.findBudgetById(budgetId); - if (optionalBudget.isPresent()) { - return optionalBudget.get(); - } else { - log.error("[BudgetServiceImpl:findBudgetById] Budget does not exists, id: {}", budgetId); - throw new BudgetNotFoundException(); - } - } + /** + * Retrieves a budget by its id. + * @param budgetId the id of the budget + * @return the budget with the specified id. + * @throws BudgetNotFoundException if budget is not found. + */ + @Override + public Budget findBudgetById(Long budgetId) { + Optional<Budget> optionalBudget = budgetRepository.findBudgetById(budgetId); + if (optionalBudget.isPresent()) { + return optionalBudget.get(); + } + else { + log.error("[BudgetServiceImpl:findBudgetById] Budget does not exists, id: {}", budgetId); + throw new BudgetNotFoundException(); + } + } - /** - * Deletes a budget by its id. - * - * @param budgetId The id of the budget to delete. - * @throws BudgetNotFoundException If budget is not found. - */ - @Override - public void deleteBudgetById(Long budgetId) { - Optional<Budget> optionalBudget = budgetRepository.findBudgetById(budgetId); - if (optionalBudget.isPresent()) { - budgetRepository.delete(optionalBudget.get()); - } else { - log.error("[BudgetServiceImpl:deleteBudgetById] Budget does not exists, id: {}", budgetId); - throw new BudgetNotFoundException(); - } - } + /** + * Deletes a budget by its id. + * @param budgetId The id of the budget to delete. + * @throws BudgetNotFoundException If budget is not found. + */ + @Override + public void deleteBudgetById(Long budgetId) { + Optional<Budget> optionalBudget = budgetRepository.findBudgetById(budgetId); + if (optionalBudget.isPresent()) { + budgetRepository.delete(optionalBudget.get()); + } + else { + log.error("[BudgetServiceImpl:deleteBudgetById] Budget does not exists, id: {}", budgetId); + throw new BudgetNotFoundException(); + } + } - /** - * Creates a new expense. - * - * @param expense the expense to create - * @return the created expense - * @throws DataIntegrityViolationException if an error occurred. - */ - @Override - public Expense createExpense(Expense expense) { - try { - return expenseRepository.save(expense); - } catch (DataIntegrityViolationException e) { - log.error("[BudgetServiceImpl:createExpanse] Error while creating expense"); - throw new DataIntegrityViolationException("Error creating expense"); - } - } + /** + * Creates a new expense. + * @param expense the expense to create + * @return the created expense + * @throws DataIntegrityViolationException if an error occurred. + */ + @Override + public Expense createExpense(Expense expense) { + try { + return expenseRepository.save(expense); + } + catch (DataIntegrityViolationException e) { + log.error("[BudgetServiceImpl:createExpanse] Error while creating expense"); + throw new DataIntegrityViolationException("Error creating expense"); + } + } - /** - * Updates an existing expense. - * - * @param expense The expense to update - * @return The updated expense - * @throws DataIntegrityViolationException If an error occurred. - */ - @Override - public Expense updateExpense(Expense expense) { - try { - return expenseRepository.save(expense); - } catch (DataIntegrityViolationException e) { - log.error("[BudgetServiceImpl:updateExpanse] Error while updating expense"); - throw new DataIntegrityViolationException("Error updating expense"); - } - } + /** + * Updates an existing expense. + * @param expense The expense to update + * @return The updated expense + * @throws DataIntegrityViolationException If an error occurred. + */ + @Override + public Expense updateExpense(Expense expense) { + try { + return expenseRepository.save(expense); + } + catch (DataIntegrityViolationException e) { + log.error("[BudgetServiceImpl:updateExpanse] Error while updating expense"); + throw new DataIntegrityViolationException("Error updating expense"); + } + } - /** - * Retrieves an expense by its id. - * - * @param expenseId The id of the expense - * @return The expense with the specified id. - * @throws ExpenseNotFoundException If expense is not found. - */ - @Override - public Expense findExpenseById(Long expenseId) { - Optional<Expense> optionalExpense = expenseRepository.findExpenseById(expenseId); - if (optionalExpense.isPresent()) { - return optionalExpense.get(); - } else { - log.error("[BudgetServiceImpl:findExpenseById] expense is not found, id: {}", expenseId); - throw new ExpenseNotFoundException(); - } - } + /** + * Retrieves an expense by its id. + * @param expenseId The id of the expense + * @return The expense with the specified id. + * @throws ExpenseNotFoundException If expense is not found. + */ + @Override + public Expense findExpenseById(Long expenseId) { + Optional<Expense> optionalExpense = expenseRepository.findExpenseById(expenseId); + if (optionalExpense.isPresent()) { + return optionalExpense.get(); + } + else { + log.error("[BudgetServiceImpl:findExpenseById] expense is not found, id: {}", expenseId); + throw new ExpenseNotFoundException(); + } + } + + /** + * Deletes an expense by its id. + * @param expenseId The id of the expense to delete. + * @throws ExpenseNotFoundException If expense is not found. + */ + @Override + public void deleteExpenseById(Long expenseId) { + Optional<Expense> optionalExpense = expenseRepository.findExpenseById(expenseId); + if (optionalExpense.isPresent()) { + expenseRepository.delete(optionalExpense.get()); + } + else { + log.error("[BudgetServiceImpl:deleteExpenseById] expense is not found, id: {}", expenseId); + throw new ExpenseNotFoundException(); + } + } - /** - * Deletes an expense by its id. - * - * @param expenseId The id of the expense to delete. - * @throws ExpenseNotFoundException If expense is not found. - */ - @Override - public void deleteExpenseById(Long expenseId) { - Optional<Expense> optionalExpense = expenseRepository.findExpenseById(expenseId); - if (optionalExpense.isPresent()) { - expenseRepository.delete(optionalExpense.get()); - } else { - log.error("[BudgetServiceImpl:deleteExpenseById] expense is not found, id: {}", expenseId); - throw new ExpenseNotFoundException(); - } - } } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/ChallengeServiceImpl.java b/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/ChallengeServiceImpl.java index 1f71131484219a7767a2a56fa9bcbe003388911f..19bea1345903444c1983d048e301b2e66b88e4d9 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/ChallengeServiceImpl.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/ChallengeServiceImpl.java @@ -32,226 +32,239 @@ import java.util.*; @Service public class ChallengeServiceImpl implements ChallengeService { - private static final Random random = new Random(); - - @Autowired - private GoalRepository goalRepository; - @Autowired - private ChallengeTemplateRepository challengeTemplateRepository; - @Autowired - private UserRepository userRepository; - - /** - * Generates a list of challenges for a given goal based on the user's preferences and goal's target date. - * Each challenge is generated based on predefined templates and adjusted for the duration of the goal. - * - * @param goal The goal for which to generate challenges. - * @param user The user who owns the goal. - * @return A list of generated Challenge objects. - */ - @Override - public List<Challenge> generateChallenges(Goal goal, User user) { - ChallengeTemplate t1 = new ChallengeTemplate(); - t1.setChallengeType(ChallengeType.NO_COFFEE); - t1.setAmount(BigDecimal.valueOf(40)); - t1.setText("Spar {unit_amount} kr hver gang du kjøper kaffe, totalt {checkDays} ganger over " + - "{totalDays} dager. Dette gir deg en total besparelse på {total_amount} kr."); - t1.setChallengeName("Spar på kaffe"); - ChallengeTemplate t2 = new ChallengeTemplate(); - t2.setChallengeType(ChallengeType.EAT_PACKED_LUNCH); - t2.setAmount(BigDecimal.valueOf(30)); - t2.setText("Spar {unit_amount} kr per gang du tar med deg hjemmelaget matpakke, " + - "totalt {checkDays} ganger over " + - "{totalDays} dager. Dette gir deg en total besparelse på {total_amount} kr."); - t2.setChallengeName("Spar på mat"); - - List<ChallengeTemplate> templates = Arrays.asList(t1, t2); - //templateRepository.findAllByChallengeTypeIn(user.getConfiguration().getChallengeTypes()); - Collections.shuffle(templates); - - LocalDateTime targetDate = goal.getTargetDate().toLocalDateTime(); - int remainingDays = (int) ChronoUnit.DAYS.between(LocalDate.now(), targetDate); - - List<Challenge> challenges = new ArrayList<>(); - int i = 0; - - int savedSoFar = 0; - - while (remainingDays > 0) { - int totalDays = Math.min(random.nextInt(23) + 7, remainingDays); - int checkDays = user.getConfiguration().getCommitment().getCheckDays(totalDays); - ChallengeTemplate template = templates.get(i++ % templates.size()); - Challenge challenge = new Challenge(); - challenge.setTemplate(template); - challenge.setPotentialAmount(template.getAmount()); - challenge.setPoints(checkDays * 10); - challenge.setCheckDays(checkDays); - challenge.setTotalDays(totalDays); - - savedSoFar += template.getAmount().intValue() * checkDays; - - if (challenges.isEmpty()) { - challenge.setStartDate(goal.getCreatedAt()); - } else { - Timestamp lastEndDate = challenges.get(challenges.size() - 1).getEndDate(); - LocalDate localDate = lastEndDate.toLocalDateTime().toLocalDate().plusDays(1); - Timestamp timestamp = Timestamp.valueOf(localDate.atStartOfDay()); - challenge.setStartDate(timestamp); - } - Timestamp lastEndDate = challenge.getStartDate(); - LocalDate localDate = lastEndDate.toLocalDateTime().toLocalDate().plusDays(totalDays); - Timestamp timestamp = Timestamp.valueOf(localDate.atStartOfDay()); - challenge.setEndDate(timestamp); - - if (challenge.getEndDate().after(goal.getTargetDate())) { - break; - } - - challenges.add(challenge); - - if(goal.getTargetAmount() < savedSoFar) { - break; - } - - remainingDays -= totalDays; - } - return challenges; - } - - /** - * Updates the progress for a specific challenge on a specified day with a given amount. - * Validates user permissions, challenge existence, and the validity of the specified day. - * - * @param userId The ID of the user updating the challenge. - * @param id The ID of the challenge to update. - * @param day The day of the challenge to mark as completed. - * @param amount The amount saved or achieved on the specified day. - * @throws PermissionDeniedException if the user does not own the goal associated with the challenge. - * @throws ChallengeNotFoundException if the challenge cannot be found within the goal. - * @throws InvalidChallengeDayException if the specified day is invalid or already completed. - * @throws GoalNotFoundException if the goal associated with the challenge is not found. - */ - @Override - public void updateProgress(long userId, long id, int day, BigDecimal amount) { - Goal goal = getGoalByChallengeId(id); - if (goal.getUser().getId() != userId) { - throw new PermissionDeniedException(); - } - - Challenge challenge = goal.getChallenges().stream().filter(c -> c.getId() == id).findFirst().orElse(null); - if (challenge == null) { - throw new ChallengeNotFoundException(); - } - List<Progress> progressList = challenge.getProgressList(); - - if (progressList.stream().anyMatch(p -> p.getDay() == day)) { - throw new InvalidChallengeDayException("Day is already completed"); - } - if (day > challenge.getCheckDays() || day < 1) { - throw new InvalidChallengeDayException("Day outside of range"); - } - - Progress progress = new Progress(); - progress.setDay(day); - progress.setCompletedAt(Timestamp.from(Instant.now())); - progress.setAmount(amount); - progressList.add(progress); - - goalRepository.save(goal); - } - - /** - * Updates the potential saving amount for a specific challenge within a goal. - * This method ensures that only the owner of the goal can update the challenge, and verifies that the challenge exists. - * - * @param userId The ID of the user attempting to update the saving amount. - * @param id The ID of the challenge whose saving amount is being updated. - * @param amount The new saving amount to be set for the challenge. - * @throws PermissionDeniedException if the user trying to update the saving amount does not own the goal. - * @throws ChallengeNotFoundException if no challenge with the given ID can be found within the goal. - * @throws GoalNotFoundException if no goal containing the specified challenge can be found. - */ - @Override - public void updateSavingAmount(long userId, long id, BigDecimal amount) { - Goal goal = getGoalByChallengeId(id); - if (goal.getUser().getId() != userId) { - throw new PermissionDeniedException(); - } - - Challenge challenge = goal.getChallenges().stream().filter(c -> c.getId() == id).findFirst().orElse(null); - if (challenge == null) { - throw new ChallengeNotFoundException(); - } - challenge.setPotentialAmount(amount); - - goalRepository.save(goal); - } - - /** - * Retrieves a goal that contains a specific challenge identified by the challenge ID. - * This method is useful for operations requiring access to a goal based on one of its challenges, - * ensuring the challenge's existence within the goal structure. - * - * @param challengeId The ID of the challenge whose goal is to be retrieved. - * @return The Goal containing the specified challenge. - * @throws GoalNotFoundException If no goal containing the specified challenge can be found. - */ - private Goal getGoalByChallengeId(long challengeId) { - Optional<Goal> goalOptional = goalRepository.findByChallenges_Id(challengeId); - if (goalOptional.isPresent()) { - return goalOptional.get(); - } else { - throw new ChallengeNotFoundException(); - } - } - - - /** - * Replaces that challenge in a given goal identified by the challenge ID. - * This method is useful for letting the user change out challenges they know - * they will not be able to do - * - * @param userId the ID of the user who sends the request - * @param challengeId The ID of the challenge that will be replaced - * @return The updated goal containing the new challenge - */ - public Challenge regenerateChallenge(long userId, long challengeId) { - Optional<User> userOptional = userRepository.findById(userId); - if (userOptional.isPresent()) { - User user = userOptional.get(); - - Goal goal = getGoalByChallengeId(challengeId); - if (goal.getUser().getId() != userId) { - throw new PermissionDeniedException(); - } - - Challenge challenge = goal.getChallenges().stream().filter(c -> c.getId() == challengeId).findFirst().orElse(null); - if (challenge == null) { - throw new ChallengeNotFoundException(); - } - - List<ChallengeType> challengeTypes = user.getConfiguration() - .getChallengeTypes(); - List<ChallengeTemplate> challengeTemplates = challengeTemplateRepository - .findAllByChallengeTypeIn(challengeTypes); - - int randomTemplateIndex = random.nextInt(challengeTemplates.size()); - - ChallengeTemplate newChallengeTemplate = challengeTemplates.get(randomTemplateIndex); - - int totalDays = challenge.getTotalDays(); - int checkDays = user.getConfiguration().getCommitment().getCheckDays(totalDays); - - - challenge.setPotentialAmount(newChallengeTemplate.getAmount()); - challenge.setCheckDays(checkDays); - challenge.setPoints(checkDays * 10); - challenge.setTemplate(newChallengeTemplate); - - goalRepository.save(goal); - return challenge; - } else { - throw new UserNotFoundException(); - } - } + private static final Random random = new Random(); + + @Autowired + private GoalRepository goalRepository; + + @Autowired + private ChallengeTemplateRepository challengeTemplateRepository; + + @Autowired + private UserRepository userRepository; + + /** + * Generates a list of challenges for a given goal based on the user's preferences and + * goal's target date. Each challenge is generated based on predefined templates and + * adjusted for the duration of the goal. + * @param goal The goal for which to generate challenges. + * @param user The user who owns the goal. + * @return A list of generated Challenge objects. + */ + @Override + public List<Challenge> generateChallenges(Goal goal, User user) { + ChallengeTemplate t1 = new ChallengeTemplate(); + t1.setChallengeType(ChallengeType.NO_COFFEE); + t1.setAmount(BigDecimal.valueOf(40)); + t1.setText("Spar {unit_amount} kr hver gang du kjøper kaffe, totalt {checkDays} ganger over " + + "{totalDays} dager. Dette gir deg en total besparelse på {total_amount} kr."); + t1.setChallengeName("Spar på kaffe"); + ChallengeTemplate t2 = new ChallengeTemplate(); + t2.setChallengeType(ChallengeType.EAT_PACKED_LUNCH); + t2.setAmount(BigDecimal.valueOf(30)); + t2.setText("Spar {unit_amount} kr per gang du tar med deg hjemmelaget matpakke, " + + "totalt {checkDays} ganger over " + + "{totalDays} dager. Dette gir deg en total besparelse på {total_amount} kr."); + t2.setChallengeName("Spar på mat"); + + List<ChallengeTemplate> templates = Arrays.asList(t1, t2); + // templateRepository.findAllByChallengeTypeIn(user.getConfiguration().getChallengeTypes()); + Collections.shuffle(templates); + + LocalDateTime targetDate = goal.getTargetDate().toLocalDateTime(); + int remainingDays = (int) ChronoUnit.DAYS.between(LocalDate.now(), targetDate); + + List<Challenge> challenges = new ArrayList<>(); + int i = 0; + + int savedSoFar = 0; + + while (remainingDays > 0) { + int totalDays = Math.min(random.nextInt(23) + 7, remainingDays); + int checkDays = user.getConfiguration().getCommitment().getCheckDays(totalDays); + ChallengeTemplate template = templates.get(i++ % templates.size()); + Challenge challenge = new Challenge(); + challenge.setTemplate(template); + challenge.setPotentialAmount(template.getAmount()); + challenge.setPoints(checkDays * 10); + challenge.setCheckDays(checkDays); + challenge.setTotalDays(totalDays); + + savedSoFar += template.getAmount().intValue() * checkDays; + + if (challenges.isEmpty()) { + challenge.setStartDate(goal.getCreatedAt()); + } + else { + Timestamp lastEndDate = challenges.get(challenges.size() - 1).getEndDate(); + LocalDate localDate = lastEndDate.toLocalDateTime().toLocalDate().plusDays(1); + Timestamp timestamp = Timestamp.valueOf(localDate.atStartOfDay()); + challenge.setStartDate(timestamp); + } + Timestamp lastEndDate = challenge.getStartDate(); + LocalDate localDate = lastEndDate.toLocalDateTime().toLocalDate().plusDays(totalDays); + Timestamp timestamp = Timestamp.valueOf(localDate.atStartOfDay()); + challenge.setEndDate(timestamp); + + if (challenge.getEndDate().after(goal.getTargetDate())) { + break; + } + + challenges.add(challenge); + + if (goal.getTargetAmount() < savedSoFar) { + break; + } + + remainingDays -= totalDays; + } + return challenges; + } + + /** + * Updates the progress for a specific challenge on a specified day with a given + * amount. Validates user permissions, challenge existence, and the validity of the + * specified day. + * @param userId The ID of the user updating the challenge. + * @param id The ID of the challenge to update. + * @param day The day of the challenge to mark as completed. + * @param amount The amount saved or achieved on the specified day. + * @throws PermissionDeniedException if the user does not own the goal associated with + * the challenge. + * @throws ChallengeNotFoundException if the challenge cannot be found within the + * goal. + * @throws InvalidChallengeDayException if the specified day is invalid or already + * completed. + * @throws GoalNotFoundException if the goal associated with the challenge is not + * found. + */ + @Override + public void updateProgress(long userId, long id, int day, BigDecimal amount) { + Goal goal = getGoalByChallengeId(id); + if (goal.getUser().getId() != userId) { + throw new PermissionDeniedException(); + } + + Challenge challenge = goal.getChallenges().stream().filter(c -> c.getId() == id).findFirst().orElse(null); + if (challenge == null) { + throw new ChallengeNotFoundException(); + } + List<Progress> progressList = challenge.getProgressList(); + + if (progressList.stream().anyMatch(p -> p.getDay() == day)) { + throw new InvalidChallengeDayException("Day is already completed"); + } + if (day > challenge.getCheckDays() || day < 1) { + throw new InvalidChallengeDayException("Day outside of range"); + } + + Progress progress = new Progress(); + progress.setDay(day); + progress.setCompletedAt(Timestamp.from(Instant.now())); + progress.setAmount(amount); + progressList.add(progress); + + goalRepository.save(goal); + } + + /** + * Updates the potential saving amount for a specific challenge within a goal. This + * method ensures that only the owner of the goal can update the challenge, and + * verifies that the challenge exists. + * @param userId The ID of the user attempting to update the saving amount. + * @param id The ID of the challenge whose saving amount is being updated. + * @param amount The new saving amount to be set for the challenge. + * @throws PermissionDeniedException if the user trying to update the saving amount + * does not own the goal. + * @throws ChallengeNotFoundException if no challenge with the given ID can be found + * within the goal. + * @throws GoalNotFoundException if no goal containing the specified challenge can be + * found. + */ + @Override + public void updateSavingAmount(long userId, long id, BigDecimal amount) { + Goal goal = getGoalByChallengeId(id); + if (goal.getUser().getId() != userId) { + throw new PermissionDeniedException(); + } + + Challenge challenge = goal.getChallenges().stream().filter(c -> c.getId() == id).findFirst().orElse(null); + if (challenge == null) { + throw new ChallengeNotFoundException(); + } + challenge.setPotentialAmount(amount); + + goalRepository.save(goal); + } + + /** + * Retrieves a goal that contains a specific challenge identified by the challenge ID. + * This method is useful for operations requiring access to a goal based on one of its + * challenges, ensuring the challenge's existence within the goal structure. + * @param challengeId The ID of the challenge whose goal is to be retrieved. + * @return The Goal containing the specified challenge. + * @throws GoalNotFoundException If no goal containing the specified challenge can be + * found. + */ + private Goal getGoalByChallengeId(long challengeId) { + Optional<Goal> goalOptional = goalRepository.findByChallenges_Id(challengeId); + if (goalOptional.isPresent()) { + return goalOptional.get(); + } + else { + throw new ChallengeNotFoundException(); + } + } + + /** + * Replaces that challenge in a given goal identified by the challenge ID. This method + * is useful for letting the user change out challenges they know they will not be + * able to do + * @param userId the ID of the user who sends the request + * @param challengeId The ID of the challenge that will be replaced + * @return The updated goal containing the new challenge + */ + public Challenge regenerateChallenge(long userId, long challengeId) { + Optional<User> userOptional = userRepository.findById(userId); + if (userOptional.isPresent()) { + User user = userOptional.get(); + + Goal goal = getGoalByChallengeId(challengeId); + if (goal.getUser().getId() != userId) { + throw new PermissionDeniedException(); + } + + Challenge challenge = goal.getChallenges() + .stream() + .filter(c -> c.getId() == challengeId) + .findFirst() + .orElse(null); + if (challenge == null) { + throw new ChallengeNotFoundException(); + } + + List<ChallengeType> challengeTypes = user.getConfiguration().getChallengeTypes(); + List<ChallengeTemplate> challengeTemplates = challengeTemplateRepository + .findAllByChallengeTypeIn(challengeTypes); + + int randomTemplateIndex = random.nextInt(challengeTemplates.size()); + + ChallengeTemplate newChallengeTemplate = challengeTemplates.get(randomTemplateIndex); + + int totalDays = challenge.getTotalDays(); + int checkDays = user.getConfiguration().getCommitment().getCheckDays(totalDays); + + challenge.setPotentialAmount(newChallengeTemplate.getAmount()); + challenge.setCheckDays(checkDays); + challenge.setPoints(checkDays * 10); + challenge.setTemplate(newChallengeTemplate); + + goalRepository.save(goal); + return challenge; + } + else { + throw new UserNotFoundException(); + } + } + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/EmailService.java b/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/EmailService.java index eb9f8e1e20f66dbfebb234115cc3cd703cccc69b..fce42c4a8f99fca72eca99da4e16026925c6d71b 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/EmailService.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/EmailService.java @@ -19,33 +19,33 @@ import java.nio.charset.StandardCharsets; @Service public class EmailService { - @Autowired - private JavaMailSender mailSender; - - /** - * Sends a password reset email to the specified email address. - * The email includes a unique password reset token embedded within the email content. - * - * @param email The email address to which the password reset email is sent. - * @param token The password reset token to be included in the email. - * @throws MessagingException if any error occurs while creating or sending the email. - * @throws IOException if there is an error reading the email template file. - */ - public void sendForgotPasswordEmail(String email, String token) throws MessagingException, IOException { - MimeMessage message = mailSender.createMimeMessage(); - MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8"); - helper.setFrom("noreply@sparesti.net", "Sparesti"); - helper.setTo(email); - helper.setSubject("Sparesti - Password Reset"); - - ClassPathResource htmlResource = new ClassPathResource("reset-password/reset-password.html"); - String html = StreamUtils.copyToString(htmlResource.getInputStream(), StandardCharsets.UTF_8); - html = html.replace("{RESET_TOKEN}", token); - html = html.replace("{FRONTEND_URL}", SparestiApplication.getFrontendURL()); - helper.setText(html, true); - - helper.addInline("logo", new ClassPathResource("reset-password/assets/logo.png")); - - mailSender.send(message); - } + @Autowired + private JavaMailSender mailSender; + + /** + * Sends a password reset email to the specified email address. The email includes a + * unique password reset token embedded within the email content. + * @param email The email address to which the password reset email is sent. + * @param token The password reset token to be included in the email. + * @throws MessagingException if any error occurs while creating or sending the email. + * @throws IOException if there is an error reading the email template file. + */ + public void sendForgotPasswordEmail(String email, String token) throws MessagingException, IOException { + MimeMessage message = mailSender.createMimeMessage(); + MimeMessageHelper helper = new MimeMessageHelper(message, true, "UTF-8"); + helper.setFrom("noreply@sparesti.net", "Sparesti"); + helper.setTo(email); + helper.setSubject("Sparesti - Password Reset"); + + ClassPathResource htmlResource = new ClassPathResource("reset-password/reset-password.html"); + String html = StreamUtils.copyToString(htmlResource.getInputStream(), StandardCharsets.UTF_8); + html = html.replace("{RESET_TOKEN}", token); + html = html.replace("{FRONTEND_URL}", SparestiApplication.getFrontendURL()); + helper.setText(html, true); + + helper.addInline("logo", new ClassPathResource("reset-password/assets/logo.png")); + + mailSender.send(message); + } + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/FriendServiceImpl.java b/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/FriendServiceImpl.java index 532176f6b789f437c5e95b50dd73c097eb54d314..5ff15ed507c6a44751eb046e16d2d19fa7eb1fc6 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/FriendServiceImpl.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/FriendServiceImpl.java @@ -1,6 +1,5 @@ package no.ntnu.idi.stud.savingsapp.service.impl; - import java.util.List; import java.util.Optional; import java.sql.Timestamp; @@ -19,106 +18,101 @@ import no.ntnu.idi.stud.savingsapp.service.FriendService; */ @Service public class FriendServiceImpl implements FriendService { - - @Autowired - private FriendRepository friendRepository; - /** - * Retrieves all friends associated with a given user ID. - * - * @param userId The ID of the user whose friends are to be retrieved. - * @return A list of Friend objects representing the user's friends. - */ - @Override - public List<Friend> getFriends(Long userId) { - return friendRepository.findAllById_UserOrId_FriendAndPendingFalse(userId); - } + @Autowired + private FriendRepository friendRepository; + + /** + * Retrieves all friends associated with a given user ID. + * @param userId The ID of the user whose friends are to be retrieved. + * @return A list of Friend objects representing the user's friends. + */ + @Override + public List<Friend> getFriends(Long userId) { + return friendRepository.findAllById_UserOrId_FriendAndPendingFalse(userId); + } + + /** + * Retrieves all pending friend requests for a given user ID. + * @param userId The ID of the user whose friend requests are to be retrieved. + * @return A list of Friend objects representing the friend requests. + */ + @Override + public List<Friend> getFriendRequests(Long userId) { + return friendRepository.findAllById_FriendAndPendingTrue(userId); + } + + /** + * Sends a friend request from one user to another. + * @param user The user sending the friend request. + * @param friend The user to receive the friend request. + */ + @Override + public void addFriendRequest(User user, User friend) { + FriendId friendId = new FriendId(); + friendId.setFriend(friend); + friendId.setUser(user); + friendRepository.save(new Friend(friendId, true, new Timestamp(System.currentTimeMillis()))); + } - /** - * Retrieves all pending friend requests for a given user ID. - * - * @param userId The ID of the user whose friend requests are to be retrieved. - * @return A list of Friend objects representing the friend requests. - */ - @Override - public List<Friend> getFriendRequests(Long userId) { - return friendRepository.findAllById_FriendAndPendingTrue(userId); - } + /** + * Get a Friend object if a relationship between the two users exists. + * @param user The first user. + * @param friend The second user. + * @return The Friend object representing the current status of their relationship. + */ + @Override + public Friend getFriendStatus(User user, User friend) { + // Attempt to find the friend entry where the user initiated the friendship + FriendId friendId = new FriendId(); + friendId.setFriend(friend); + friendId.setUser(user); + Optional<Friend> friendStatus = friendRepository.findById(friendId); - /** - * Sends a friend request from one user to another. - * - * @param user The user sending the friend request. - * @param friend The user to receive the friend request. - */ - @Override - public void addFriendRequest(User user, User friend) { - FriendId friendId = new FriendId(); - friendId.setFriend(friend); - friendId.setUser(user); - friendRepository.save(new Friend(friendId, true, new Timestamp(System.currentTimeMillis()))); - } + // If not found, try the reverse where the friend initiated the friendship + if (!friendStatus.isPresent()) { + friendId.setFriend(user); + friendId.setUser(friend); + friendStatus = friendRepository.findById(friendId); + } - /** - * Get a Friend object if a relationship between the two users exists. - * - * @param user The first user. - * @param friend The second user. - * @return The Friend object representing the current status of their relationship. - */ - @Override - public Friend getFriendStatus(User user, User friend) { - // Attempt to find the friend entry where the user initiated the friendship - FriendId friendId = new FriendId(); - friendId.setFriend(friend); - friendId.setUser(user); - Optional<Friend> friendStatus = friendRepository.findById(friendId); + // Return the friend entry if present, or null if no relationship exists + return friendStatus.orElse(null); + } - // If not found, try the reverse where the friend initiated the friendship - if(!friendStatus.isPresent()) { - friendId.setFriend(user); - friendId.setUser(friend); - friendStatus = friendRepository.findById(friendId); - } - - // Return the friend entry if present, or null if no relationship exists - return friendStatus.orElse(null); - } + /** + * Retrieves a specific friend request between two users. + * @param user The user who sent the friend request. + * @param friend The user who received the friend request. + * @return The Friend object if a request exists, otherwise null. + */ + @Override + public Friend getFriendRequest(User user, User friend) { + Friend friendRequest = getFriendStatus(user, friend); + if (friendRequest.isPending() == true && friendRequest.getId().getUser().getId().equals(friend.getId())) { + return friendRequest; + } + else { + return null; + } + } - /** - * Retrieves a specific friend request between two users. - * - * @param user The user who sent the friend request. - * @param friend The user who received the friend request. - * @return The Friend object if a request exists, otherwise null. - */ - @Override - public Friend getFriendRequest(User user, User friend) { - Friend friendRequest = getFriendStatus(user, friend); - if(friendRequest.isPending() == true && friendRequest.getId().getUser().getId().equals(friend.getId())) { - return friendRequest; - } else { - return null; - } - } + /** + * Accepts a friend request, changing the attribute pending to false. + * @param friendRequest The friend request to be accepted. + */ + @Override + public void acceptFriendRequest(Friend friendRequest) { + friendRepository.acceptFriendRequest(friendRequest.getId()); + } - /** - * Accepts a friend request, changing the attribute pending to false. - * - * @param friendRequest The friend request to be accepted. - */ - @Override - public void acceptFriendRequest(Friend friendRequest) { - friendRepository.acceptFriendRequest(friendRequest.getId()); - } + /** + * Deletes a friendship or a friend request between two users. + * @param friendStatus The friendship or friend request to be deleted. + */ + @Override + public void deleteFriendOrFriendRequest(Friend friendStatus) { + friendRepository.delete(friendStatus); + } - /** - * Deletes a friendship or a friend request between two users. - * - * @param friendStatus The friendship or friend request to be deleted. - */ - @Override - public void deleteFriendOrFriendRequest(Friend friendStatus) { - friendRepository.delete(friendStatus); - } } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/GoalServiceImpl.java b/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/GoalServiceImpl.java index 4b8e5077a2658b48b1c41ef8d7b5228396f440d7..16b6190a22e2e2b6853f0c2dcce556a3e8755d62 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/GoalServiceImpl.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/GoalServiceImpl.java @@ -29,98 +29,97 @@ import org.springframework.stereotype.Service; @Slf4j public class GoalServiceImpl implements GoalService { - @Autowired - private UserService userService; + @Autowired + private UserService userService; - @Autowired - private GoalRepository goalRepository; + @Autowired + private GoalRepository goalRepository; - @Autowired - private ChallengeService challengeService; + @Autowired + private ChallengeService challengeService; - @Autowired - private GroupRepository groupRepository; + @Autowired + private GroupRepository groupRepository; - /** - * Creates a new goal for a specific user and generates associated challenges. - * - * @param goal The goal to be created, containing initial data. - * @param userId The ID of the user for whom the goal is being created. - * @return The newly created Goal, now populated with generated challenges and persisted in the database. - */ - @Override - public Goal createGoal(Goal goal, List<GroupUserDTO> GroupUsers, long userId) { - User user = userService.findById(userId); - goal.setCreatedAt(Timestamp.from(Instant.now())); - goal.setUser(user); - List<Challenge> challenges = challengeService.generateChallenges(goal, user); - goal.setChallenges(challenges); + /** + * Creates a new goal for a specific user and generates associated challenges. + * @param goal The goal to be created, containing initial data. + * @param userId The ID of the user for whom the goal is being created. + * @return The newly created Goal, now populated with generated challenges and + * persisted in the database. + */ + @Override + public Goal createGoal(Goal goal, List<GroupUserDTO> GroupUsers, long userId) { + User user = userService.findById(userId); + goal.setCreatedAt(Timestamp.from(Instant.now())); + goal.setUser(user); + List<Challenge> challenges = challengeService.generateChallenges(goal, user); + goal.setChallenges(challenges); - //Create group goal if GroupUsers were added - if(GroupUsers != null && !GroupUsers.isEmpty()) { - List<Goal> groupGoalList = new ArrayList<>(); - for (GroupUserDTO groupUserDTO : GroupUsers) { - Goal groupGoal = new Goal(); - User groupUser = userService.findById(groupUserDTO.getUserId()); - groupGoal.setCreatedAt(Timestamp.from(Instant.now())); - groupGoal.setUser(groupUser); - List<Challenge> challengeList = challengeService.generateChallenges(groupGoal, groupUser); - groupGoal.setChallenges(challengeList); - goalRepository.save(groupGoal); - groupGoalList.add(groupGoal); - } + // Create group goal if GroupUsers were added + if (GroupUsers != null && !GroupUsers.isEmpty()) { + List<Goal> groupGoalList = new ArrayList<>(); + for (GroupUserDTO groupUserDTO : GroupUsers) { + Goal groupGoal = new Goal(); + User groupUser = userService.findById(groupUserDTO.getUserId()); + groupGoal.setCreatedAt(Timestamp.from(Instant.now())); + groupGoal.setUser(groupUser); + List<Challenge> challengeList = challengeService.generateChallenges(groupGoal, groupUser); + groupGoal.setChallenges(challengeList); + goalRepository.save(groupGoal); + groupGoalList.add(groupGoal); + } - Group group = new Group(); - group.setCreator(user); - group.setGoals(groupGoalList); - groupRepository.save(group); - } + Group group = new Group(); + group.setCreator(user); + group.setGoals(groupGoalList); + groupRepository.save(group); + } - return goalRepository.save(goal); - } + return goalRepository.save(goal); + } - /** - * Retrieves all goals associated with a given user ID. - * - * @param userId The ID of the user whose goals are to be retrieved. - * @return A list of Goals associated with the specified user. - */ - @Override - public List<Goal> getGoals(long userId) { - return goalRepository.findByUser_Id(userId); - } + /** + * Retrieves all goals associated with a given user ID. + * @param userId The ID of the user whose goals are to be retrieved. + * @return A list of Goals associated with the specified user. + */ + @Override + public List<Goal> getGoals(long userId) { + return goalRepository.findByUser_Id(userId); + } - /** - * Retrieves goal associated with a given goal ID. - * - * @param goalId The ID of the user whose goals are to be retrieved. - * @return The goal associated with the given goal ID. - */ - @Override - public Goal getGoal(long goalId) { - Optional<Goal> optionalGoal = goalRepository.findById(goalId); - if (optionalGoal.isPresent()) { - return optionalGoal.get(); - } else { - log.error("[GoalServiceImpl:getGoal] Goal is not found, id: {}", goalId); - throw new GoalNotFoundException(); - } - } + /** + * Retrieves goal associated with a given goal ID. + * @param goalId The ID of the user whose goals are to be retrieved. + * @return The goal associated with the given goal ID. + */ + @Override + public Goal getGoal(long goalId) { + Optional<Goal> optionalGoal = goalRepository.findById(goalId); + if (optionalGoal.isPresent()) { + return optionalGoal.get(); + } + else { + log.error("[GoalServiceImpl:getGoal] Goal is not found, id: {}", goalId); + throw new GoalNotFoundException(); + } + } + + /** + * @param goalId the goal that the group contains + * @return The group containing the goal + */ + @Override + public Group getGroup(Long goalId) { + Optional<Group> optionalGroup = groupRepository.findByGoals_Id(goalId); + if (optionalGroup.isPresent()) { + return optionalGroup.get(); + } + else { + log.error("[GoalServiceImpl:getGoal] Group is not found from goal, id: {}", goalId); + throw new GroupNotFoundException(); + } + } - /** - * - * - * @param goalId the goal that the group contains - * @return The group containing the goal - */ - @Override - public Group getGroup(Long goalId) { - Optional<Group> optionalGroup = groupRepository.findByGoals_Id(goalId); - if (optionalGroup.isPresent()) { - return optionalGroup.get(); - } else { - log.error("[GoalServiceImpl:getGoal] Group is not found from goal, id: {}", goalId); - throw new GroupNotFoundException(); - } - } } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/ImageServiceImpl.java b/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/ImageServiceImpl.java index b35faf7c473b6300b57db97074855376713b39e4..4a1ff1efc4ae11ba3183227e99d1ebf2ef63c9bc 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/ImageServiceImpl.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/ImageServiceImpl.java @@ -17,39 +17,39 @@ import java.util.Optional; @Slf4j public class ImageServiceImpl implements ImageService { - @Autowired - private ImageRepository imageRepository; + @Autowired + private ImageRepository imageRepository; - /** - * Saves an image to the database. - * - * @param name The name of the image file. - * @param data The binary data of the image. - * @return The persisted Image object, containing the image's metadata and identifier. - */ - @Override - public Image saveImage(String name, byte[] data) { - Image image = new Image(); - image.setName(name); - image.setData(data); - return imageRepository.save(image); - } + /** + * Saves an image to the database. + * @param name The name of the image file. + * @param data The binary data of the image. + * @return The persisted Image object, containing the image's metadata and identifier. + */ + @Override + public Image saveImage(String name, byte[] data) { + Image image = new Image(); + image.setName(name); + image.setData(data); + return imageRepository.save(image); + } + + /** + * Retrieves an image from the database by its ID. + * @param id The unique identifier of the image to be retrieved. + * @return The Image object containing all relevant data. + * @throws ImageNotFoundException if no image is found with the provided ID. + */ + @Override + public Image getImage(long id) { + Optional<Image> optionalImage = imageRepository.findById(id); + if (optionalImage.isPresent()) { + return optionalImage.get(); + } + else { + log.error("[ImageService:getImage] Image is not found, id: {}", id); + throw new ImageNotFoundException(); + } + } - /** - * Retrieves an image from the database by its ID. - * - * @param id The unique identifier of the image to be retrieved. - * @return The Image object containing all relevant data. - * @throws ImageNotFoundException if no image is found with the provided ID. - */ - @Override - public Image getImage(long id) { - Optional<Image> optionalImage = imageRepository.findById(id); - if (optionalImage.isPresent()) { - return optionalImage.get(); - } else { - log.error("[ImageService:getImage] Image is not found, id: {}", id); - throw new ImageNotFoundException(); - } - } } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/ItemServiceImpl.java b/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/ItemServiceImpl.java index cc71f27f15055126f633fbe7b301309c6c5ea3cf..51302969de5988136965138d524b93decf918e8a 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/ItemServiceImpl.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/ItemServiceImpl.java @@ -21,67 +21,70 @@ import no.ntnu.idi.stud.savingsapp.service.UserService; */ @Service public class ItemServiceImpl implements ItemService { - @Autowired - private InventoryRepository inventoryRepository; - @Autowired - private StoreRepository storeRepository; + @Autowired + private InventoryRepository inventoryRepository; - @Autowired - private UserService userService; + @Autowired + private StoreRepository storeRepository; - /** - * Retrieves the inventory of items for a specific user. - * - * @param userId the unique identifier of the user whose inventory is to be retrieved - * @return a list of {@link Item} objects representing the user's inventory - */ - @Override - public List<Item> getInventory(Long userId) { - return storeRepository.getInventory(userId); - } + @Autowired + private UserService userService; - /** - * Retrieves a list of all items available in the store. - * - * @return a list of {@link Item} objects representing all items currently available in the store - */ - @Override - public List<Item> getStore() { - return storeRepository.findAll(); - } + /** + * Retrieves the inventory of items for a specific user. + * @param userId the unique identifier of the user whose inventory is to be retrieved + * @return a list of {@link Item} objects representing the user's inventory + */ + @Override + public List<Item> getInventory(Long userId) { + return storeRepository.getInventory(userId); + } - /** - * Retrieves a specific item from the store based on its identifier. - * - * @param itemId the unique identifier of the item to be retrieved - * @return the {@link Item} corresponding to the provided identifier, or null if no such item exists - */ - @Override - public Item getItemFromId(Long itemId) { - Optional<Item> item = storeRepository.findById(itemId); - if(item.isPresent()) { - return item.get(); - } else { - return null; - } - } + /** + * Retrieves a list of all items available in the store. + * @return a list of {@link Item} objects representing all items currently available + * in the store + */ + @Override + public List<Item> getStore() { + return storeRepository.findAll(); + } + + /** + * Retrieves a specific item from the store based on its identifier. + * @param itemId the unique identifier of the item to be retrieved + * @return the {@link Item} corresponding to the provided identifier, or null if no + * such item exists + */ + @Override + public Item getItemFromId(Long itemId) { + Optional<Item> item = storeRepository.findById(itemId); + if (item.isPresent()) { + return item.get(); + } + else { + return null; + } + } + + /** + * Adds an item to the inventory of a specified user. + * @param user the {@link User} object representing the user to whom the item will be + * added + * @param item the {@link Item} to be added to the user's inventory + */ + @Override + public Boolean addItem(User user, Item item) { + InventoryId inventoryId = new InventoryId(item, user); + if (userService.hasMorePoints(user, item.getPrice())) { + inventoryRepository.save(new Inventory(inventoryId, new Timestamp(System.currentTimeMillis()))); + userService.deductPoints(user.getId(), item.getPrice()); + return true; + } + else { + return false; + } + } - /** - * Adds an item to the inventory of a specified user. - * - * @param user the {@link User} object representing the user to whom the item will be added - * @param item the {@link Item} to be added to the user's inventory - */ - @Override - public Boolean addItem(User user, Item item) { - InventoryId inventoryId = new InventoryId(item, user); - if(userService.hasMorePoints(user, item.getPrice())) { - inventoryRepository.save(new Inventory(inventoryId, new Timestamp(System.currentTimeMillis()))); - userService.deductPoints(user.getId(), item.getPrice()); - return true; - } else { - return false; - } - } } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/LeaderboardServiceImpl.java b/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/LeaderboardServiceImpl.java index dd0a2ee02fc950252d7725e07c9c0ddc46625127..3056a5416911beab1e1fdcc7a756c0e3c3b53245 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/LeaderboardServiceImpl.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/LeaderboardServiceImpl.java @@ -24,234 +24,239 @@ import java.util.stream.Collectors; @Service public class LeaderboardServiceImpl implements LeaderboardService { - @Autowired - private UserRepository userRepository; + @Autowired + private UserRepository userRepository; - @Autowired - private FriendRepository friendRepository; + @Autowired + private FriendRepository friendRepository; - /** - * Retrieves a leaderboard containing the top users based on the specified type and filter. - * - * @param type The type of leaderboard to retrieve (e.g., TOTAL_POINTS, CURRENT_STREAK, TOP_STREAK). - * @param filter The filter for who the leaderboard should contain (e.g., GLOBAL or FRIENDS). - * @param entryCount The amount of entries you want the leaderboard to contain. - * @param userId The ID of the user if you wanna find a leaderboard filtered on FRIENDS. - * @return A Leaderboard object containing the top entries for the specified type and filter. - */ - @Override - public Leaderboard getTopUsers(LeaderboardType type, LeaderboardFilter filter, int entryCount, Long userId) { - Leaderboard leaderboard = new Leaderboard(); - leaderboard.setType(type); - leaderboard.setFilter(filter); + /** + * Retrieves a leaderboard containing the top users based on the specified type and + * filter. + * @param type The type of leaderboard to retrieve (e.g., TOTAL_POINTS, + * CURRENT_STREAK, TOP_STREAK). + * @param filter The filter for who the leaderboard should contain (e.g., GLOBAL or + * FRIENDS). + * @param entryCount The amount of entries you want the leaderboard to contain. + * @param userId The ID of the user if you wanna find a leaderboard filtered on + * FRIENDS. + * @return A Leaderboard object containing the top entries for the specified type and + * filter. + */ + @Override + public Leaderboard getTopUsers(LeaderboardType type, LeaderboardFilter filter, int entryCount, Long userId) { + Leaderboard leaderboard = new Leaderboard(); + leaderboard.setType(type); + leaderboard.setFilter(filter); - List<LeaderboardEntry> entries = new ArrayList<>(); - List<User> users = new ArrayList<>(); + List<LeaderboardEntry> entries = new ArrayList<>(); + List<User> users = new ArrayList<>(); - switch (filter) { - case GLOBAL: - switch (type) { - case TOTAL_POINTS: - users = userRepository.findTopUsersByTotalEarnedPoints(entryCount); - break; - case CURRENT_STREAK: - users = userRepository.findTopUsersByHighestCurrentStreak(entryCount); - break; - case TOP_STREAK: - users = userRepository.findTopUsersByHighestEverStreak(entryCount); - break; - } - for (User user : users) { - int score = 0; - long rank = 0; - switch (type) { - case TOTAL_POINTS: - score = user.getPoint().getTotalEarnedPoints(); - rank = userRepository.findUserRankByTotalEarnedPoints(user.getId()); - break; - case CURRENT_STREAK: - score = user.getStreak().getCurrentStreak(); - rank = userRepository.findUserRankByCurrentStreak(user.getId()); - break; - case TOP_STREAK: - score = user.getStreak().getHighestStreak(); - rank = userRepository.findUserRankByHighestEverStreak(user.getId()); - break; - } - entries.add(new LeaderboardEntry(user, score, rank)); - } - break; + switch (filter) { + case GLOBAL: + switch (type) { + case TOTAL_POINTS: + users = userRepository.findTopUsersByTotalEarnedPoints(entryCount); + break; + case CURRENT_STREAK: + users = userRepository.findTopUsersByHighestCurrentStreak(entryCount); + break; + case TOP_STREAK: + users = userRepository.findTopUsersByHighestEverStreak(entryCount); + break; + } + for (User user : users) { + int score = 0; + long rank = 0; + switch (type) { + case TOTAL_POINTS: + score = user.getPoint().getTotalEarnedPoints(); + rank = userRepository.findUserRankByTotalEarnedPoints(user.getId()); + break; + case CURRENT_STREAK: + score = user.getStreak().getCurrentStreak(); + rank = userRepository.findUserRankByCurrentStreak(user.getId()); + break; + case TOP_STREAK: + score = user.getStreak().getHighestStreak(); + rank = userRepository.findUserRankByHighestEverStreak(user.getId()); + break; + } + entries.add(new LeaderboardEntry(user, score, rank)); + } + break; - case FRIENDS: - switch (type) { - case TOTAL_POINTS: - users = userRepository.findTopFriendsByTotalEarnedPoints(userId, entryCount); - break; - case CURRENT_STREAK: - users = userRepository.findTopFriendsByHighestCurrentStreak(userId, entryCount); - break; - case TOP_STREAK: - users = userRepository.findTopFriendsByHighestEverStreak(userId, entryCount); - break; - } - for (User user : users) { - int score = 0; - long rank = 0; - switch (type) { - case TOTAL_POINTS: - score = user.getPoint().getTotalEarnedPoints(); - rank = userRepository.findUserRankByTotalEarnedPoints(user.getId()); - break; - case CURRENT_STREAK: - score = user.getStreak().getCurrentStreak(); - rank = userRepository.findUserRankByCurrentStreak(user.getId()); - break; - case TOP_STREAK: - score = user.getStreak().getHighestStreak(); - rank = userRepository.findUserRankByHighestEverStreak(user.getId()); - break; - } - entries.add(new LeaderboardEntry(user, score, rank)); - } - break; - } + case FRIENDS: + switch (type) { + case TOTAL_POINTS: + users = userRepository.findTopFriendsByTotalEarnedPoints(userId, entryCount); + break; + case CURRENT_STREAK: + users = userRepository.findTopFriendsByHighestCurrentStreak(userId, entryCount); + break; + case TOP_STREAK: + users = userRepository.findTopFriendsByHighestEverStreak(userId, entryCount); + break; + } + for (User user : users) { + int score = 0; + long rank = 0; + switch (type) { + case TOTAL_POINTS: + score = user.getPoint().getTotalEarnedPoints(); + rank = userRepository.findUserRankByTotalEarnedPoints(user.getId()); + break; + case CURRENT_STREAK: + score = user.getStreak().getCurrentStreak(); + rank = userRepository.findUserRankByCurrentStreak(user.getId()); + break; + case TOP_STREAK: + score = user.getStreak().getHighestStreak(); + rank = userRepository.findUserRankByHighestEverStreak(user.getId()); + break; + } + entries.add(new LeaderboardEntry(user, score, rank)); + } + break; + } - leaderboard.setEntries(entries); - return leaderboard; - } + leaderboard.setEntries(entries); + return leaderboard; + } - /** - * Retrieves a leaderboard containing the users surrounding a user on the specified type and filter. - * User with ID userID will be in the middle. - * - * @param type The type of leaderboard to retrieve (e.g., TOTAL_POINTS, CURRENT_STREAK, TOP_STREAK). - * @param filter The filter for who the leaderboard should contain (e.g., GLOBAL or FRIENDS). - * @param entryCount The amount of entries you want the leaderboard to contain. - * @param userId The ID of the user you want to be in the middle of the leaderboard. - * @return A Leaderboard object containing the specified user entry in the middle and entries surrounding it for the specified type and filter. - */ - @Override - public Leaderboard getSurrounding(LeaderboardType type, LeaderboardFilter filter, int entryCount, Long userId) { - Leaderboard leaderboard = new Leaderboard(); - leaderboard.setType(type); - leaderboard.setFilter(filter); + /** + * Retrieves a leaderboard containing the users surrounding a user on the specified + * type and filter. User with ID userID will be in the middle. + * @param type The type of leaderboard to retrieve (e.g., TOTAL_POINTS, + * CURRENT_STREAK, TOP_STREAK). + * @param filter The filter for who the leaderboard should contain (e.g., GLOBAL or + * FRIENDS). + * @param entryCount The amount of entries you want the leaderboard to contain. + * @param userId The ID of the user you want to be in the middle of the leaderboard. + * @return A Leaderboard object containing the specified user entry in the middle and + * entries surrounding it for the specified type and filter. + */ + @Override + public Leaderboard getSurrounding(LeaderboardType type, LeaderboardFilter filter, int entryCount, Long userId) { + Leaderboard leaderboard = new Leaderboard(); + leaderboard.setType(type); + leaderboard.setFilter(filter); - List<LeaderboardEntry> entries = new ArrayList<>(); - List<User> users = new ArrayList<>(); + List<LeaderboardEntry> entries = new ArrayList<>(); + List<User> users = new ArrayList<>(); - switch (filter) { - case GLOBAL: - switch (type) { - case TOTAL_POINTS: - users = userRepository.findSurroundingUsersByTotalEarnedPoints(userId, entryCount); - break; - case CURRENT_STREAK: - users = userRepository.findSurroundingUsersByHighestCurrentStreak(userId, entryCount); - break; - case TOP_STREAK: - users = userRepository.findSurroundingUsersByHighestEverStreak(userId, entryCount); - break; - } - for (User user : users) { - int score = 0; - long rank = 0; - switch (type) { - case TOTAL_POINTS: - score = user.getPoint().getTotalEarnedPoints(); - rank = userRepository.findUserRankByTotalEarnedPoints(user.getId()); - break; - case CURRENT_STREAK: - score = user.getStreak().getCurrentStreak(); - rank = userRepository.findUserRankByCurrentStreak(user.getId()); - break; - case TOP_STREAK: - score = user.getStreak().getHighestStreak(); - rank = userRepository.findUserRankByHighestEverStreak(user.getId()); - break; - } - entries.add(new LeaderboardEntry(user, score, rank)); - } - break; - case FRIENDS: - List<Friend> friends = friendRepository.findAllById_UserOrId_FriendAndPendingFalse(userId); - - // Add friends to users and remove duplicates - users = friends.stream() - .map(friend -> friend.getId().getUser().getId().equals(userId) ? friend.getId().getFriend() : friend.getId().getUser()) - .distinct() - .collect(Collectors.toList()); - - // Add user to users - User yourself = userRepository.findById(userId).orElse(null); - if(yourself != null && !users.contains(yourself)) { - users.add(yourself); - } + switch (filter) { + case GLOBAL: + switch (type) { + case TOTAL_POINTS: + users = userRepository.findSurroundingUsersByTotalEarnedPoints(userId, entryCount); + break; + case CURRENT_STREAK: + users = userRepository.findSurroundingUsersByHighestCurrentStreak(userId, entryCount); + break; + case TOP_STREAK: + users = userRepository.findSurroundingUsersByHighestEverStreak(userId, entryCount); + break; + } + for (User user : users) { + int score = 0; + long rank = 0; + switch (type) { + case TOTAL_POINTS: + score = user.getPoint().getTotalEarnedPoints(); + rank = userRepository.findUserRankByTotalEarnedPoints(user.getId()); + break; + case CURRENT_STREAK: + score = user.getStreak().getCurrentStreak(); + rank = userRepository.findUserRankByCurrentStreak(user.getId()); + break; + case TOP_STREAK: + score = user.getStreak().getHighestStreak(); + rank = userRepository.findUserRankByHighestEverStreak(user.getId()); + break; + } + entries.add(new LeaderboardEntry(user, score, rank)); + } + break; + case FRIENDS: + List<Friend> friends = friendRepository.findAllById_UserOrId_FriendAndPendingFalse(userId); - // Sort users based on type - users = users.stream() - .sorted(Comparator.comparing(user -> { - switch (type) { - case TOTAL_POINTS: - return user.getPoint().getTotalEarnedPoints(); - case CURRENT_STREAK: - return user.getStreak().getCurrentStreak(); - case TOP_STREAK: - return user.getStreak().getHighestStreak(); - default: - return 0; - } - }, Comparator.reverseOrder())) - .collect(Collectors.toList()); - - // Find the index of user - int index = 0; - for(User user : users) { - if(user.getId().equals(userId)) { - break; - } - index++; - } - - // Calculate the start and end index of the surrounding friends - int startIndex = Math.max(index - entryCount, 0); - int endIndex = Math.min(index + entryCount + 1, users.size()); + // Add friends to users and remove duplicates + users = friends.stream() + .map(friend -> friend.getId().getUser().getId().equals(userId) ? friend.getId().getFriend() + : friend.getId().getUser()) + .distinct() + .collect(Collectors.toList()); - // Extract the sublist - users = users.subList(startIndex, endIndex); - - // Add the users as entries - for (User user : users) { - int score = 0; - long rank = 0; - switch (type) { - case TOTAL_POINTS: - score = user.getPoint().getTotalEarnedPoints(); - rank = userRepository.findUserRankByTotalEarnedPoints(user.getId()); - break; - case CURRENT_STREAK: - score = user.getStreak().getCurrentStreak(); - rank = userRepository.findUserRankByCurrentStreak(user.getId()); - break; - case TOP_STREAK: - score = user.getStreak().getHighestStreak(); - rank = userRepository.findUserRankByHighestEverStreak(user.getId()); - break; - } - entries.add(new LeaderboardEntry(user, score, rank)); - } - break; - } - leaderboard.setEntries(entries); - return leaderboard; - } + // Add user to users + User yourself = userRepository.findById(userId).orElse(null); + if (yourself != null && !users.contains(yourself)) { + users.add(yourself); + } + + // Sort users based on type + users = users.stream().sorted(Comparator.comparing(user -> { + switch (type) { + case TOTAL_POINTS: + return user.getPoint().getTotalEarnedPoints(); + case CURRENT_STREAK: + return user.getStreak().getCurrentStreak(); + case TOP_STREAK: + return user.getStreak().getHighestStreak(); + default: + return 0; + } + }, Comparator.reverseOrder())).collect(Collectors.toList()); + + // Find the index of user + int index = 0; + for (User user : users) { + if (user.getId().equals(userId)) { + break; + } + index++; + } + + // Calculate the start and end index of the surrounding friends + int startIndex = Math.max(index - entryCount, 0); + int endIndex = Math.min(index + entryCount + 1, users.size()); + + // Extract the sublist + users = users.subList(startIndex, endIndex); + + // Add the users as entries + for (User user : users) { + int score = 0; + long rank = 0; + switch (type) { + case TOTAL_POINTS: + score = user.getPoint().getTotalEarnedPoints(); + rank = userRepository.findUserRankByTotalEarnedPoints(user.getId()); + break; + case CURRENT_STREAK: + score = user.getStreak().getCurrentStreak(); + rank = userRepository.findUserRankByCurrentStreak(user.getId()); + break; + case TOP_STREAK: + score = user.getStreak().getHighestStreak(); + rank = userRepository.findUserRankByHighestEverStreak(user.getId()); + break; + } + entries.add(new LeaderboardEntry(user, score, rank)); + } + break; + } + leaderboard.setEntries(entries); + return leaderboard; + } + + /** + * Get the total sum of the total points of all users. + * @return Long + */ + @Override + public long getSumTotalEarnedPoints() { + return userRepository.getSumTotalEarnedPoints(); + } - /** - * Get the total sum of the total points of all users. - * - * @return Long - */ - @Override - public long getSumTotalEarnedPoints() { - return userRepository.getSumTotalEarnedPoints(); - } } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/NotificationServiceImpl.java b/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/NotificationServiceImpl.java index 9ff32d778c02ac414fc7b3adf5bc3152b2f92dbc..163e2db91e8dcd64ffe7897dd0aa6f551f40b6fc 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/NotificationServiceImpl.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/NotificationServiceImpl.java @@ -17,57 +17,56 @@ import org.springframework.stereotype.Service; @Slf4j public class NotificationServiceImpl implements NotificationService { - @Autowired - private NotificationRepository notificationRepository; + @Autowired + private NotificationRepository notificationRepository; - /** - * Retrieves a notification by its id. - * - * @param notificationId the unique identifier for the notification - * @return the {@link Notification} to the notificationId. - * @throws NotificationNotFoundException if notification is not found. - */ - @Override - public Notification getNotificationById(long notificationId) { - Optional<Notification> optionalNotification = notificationRepository.findNotificationById(notificationId); - if (optionalNotification.isPresent()) { - return optionalNotification.get(); - } else { - log.error("[NotificationServiceImpl:getNotificationById] notification does not exists, id: {}", notificationId); - throw new NotificationNotFoundException(); - } - } + /** + * Retrieves a notification by its id. + * @param notificationId the unique identifier for the notification + * @return the {@link Notification} to the notificationId. + * @throws NotificationNotFoundException if notification is not found. + */ + @Override + public Notification getNotificationById(long notificationId) { + Optional<Notification> optionalNotification = notificationRepository.findNotificationById(notificationId); + if (optionalNotification.isPresent()) { + return optionalNotification.get(); + } + else { + log.error("[NotificationServiceImpl:getNotificationById] notification does not exists, id: {}", + notificationId); + throw new NotificationNotFoundException(); + } + } - /** - * Retrieves a list of all notifications belonging to a user. - * - * @param userId the unique identifier for the user - * @return a list of {@link Notification} objects belonging to the user. - */ - @Override - public List<Notification> getNotificationsByUserId(long userId) { - return notificationRepository.findNotificationsByUserId(userId); - } + /** + * Retrieves a list of all notifications belonging to a user. + * @param userId the unique identifier for the user + * @return a list of {@link Notification} objects belonging to the user. + */ + @Override + public List<Notification> getNotificationsByUserId(long userId) { + return notificationRepository.findNotificationsByUserId(userId); + } - /** - * Retrieves a list of all unread notifications belonging to a user. - * - * @param userId the unique identifier for the user - * @return a list of unread {@link Notification} objects belonging to the user. - */ - @Override - public List<Notification> getUnreadNotificationsByUserId(long userId) { - return notificationRepository.findUnreadNotificationsByUserId(userId); - } + /** + * Retrieves a list of all unread notifications belonging to a user. + * @param userId the unique identifier for the user + * @return a list of unread {@link Notification} objects belonging to the user. + */ + @Override + public List<Notification> getUnreadNotificationsByUserId(long userId) { + return notificationRepository.findUnreadNotificationsByUserId(userId); + } + + /** + * Updates a notification by a new requested notification. Can alternatively create a + * new notification. + * @param notification the {@link Notification} object to update. + */ + @Override + public void updateNotification(Notification notification) { + notificationRepository.save(notification); + } - /** - * Updates a notification by a new requested notification. - * Can alternatively create a new notification. - * - * @param notification the {@link Notification} object to update. - */ - @Override - public void updateNotification(Notification notification) { - notificationRepository.save(notification); - } } \ No newline at end of file diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/UserServiceImpl.java b/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/UserServiceImpl.java index 75795298a2257cf74f5429a62a15e20cd3ba52f6..b76aec866f4791d56e6736377beab01ae9ef3cde 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/UserServiceImpl.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/service/impl/UserServiceImpl.java @@ -64,483 +64,494 @@ import java.util.Iterator; @Slf4j public class UserServiceImpl implements UserService { - private static final Duration PASSWORD_RESET_DURATION = Duration.ofHours(1); - - @Autowired - private UserRepository userRepository; - - @Autowired - private FriendService friendService; - - @Autowired - private PointRepository pointRepository; - - @Autowired - private StreakRepository streakRepository; - - @Autowired - private PasswordResetTokenRepository tokenRepository; - - @Autowired - private PasswordEncoder passwordEncoder; - - @Autowired - private EmailService emailService; - - @Autowired - AccountService accountService; - - @Autowired - FeedbackRepository feedbackRepository; - - /** - * Authenticates a user with the provided email and password. - * - * @param email The email address of the user. - * @param password The password associated with the user's account. - * @return The authenticated user object if login is successful. - * @throws InvalidCredentialsException if the provided credentials are invalid. - * @throws UserNotFoundException if the user with the provided email is not found. - */ - @Override - public User login(String email, String password) { - Optional<User> optionalUser = userRepository.findByEmail(email); - if (optionalUser.isPresent()) { - User user = optionalUser.get(); - boolean match = passwordEncoder.matches(password, user.getPassword()); - if (match) { - return user; - } else { - log.error("[UserServiceImpl:login] invalid credentials: email: {}, password: {}", email, password); - throw new InvalidCredentialsException(); - } - } else { - log.error("[UserServiceImpl:login] user is not found, email: {}", email); - throw new UserNotFoundException(); - } - } - - /** - * Registers a new user. - * - * @param user The user object containing registration information. - * @return The registered user object. - * @throws EmailAlreadyExistsException if the provided email already exists in the system. - */ - @Override - public User register(User user) { - String encodedPassword = passwordEncoder.encode(user.getPassword()); - user.setPassword(encodedPassword); - user.setRole(Role.USER); - user.setCreatedAt(Timestamp.from(Instant.now())); - - // Create and save a new Point object - Point point = new Point(); - point.setCurrentPoints(0); - point.setTotalEarnedPoints(0); - point = pointRepository.save(point); - - user.setPoint(point); - - Streak streak = new Streak(); - streak.setCurrentStreak(0); - streak.setCurrentStreakCreatedAt(Timestamp.from(Instant.now())); - streak.setCurrentStreakUpdatedAt(Timestamp.from(Instant.now())); - streak.setHighestStreak(0); - streak.setHighestStreakCreatedAt(Timestamp.from(Instant.now())); - streak.setHighestStreakEndedAt(Timestamp.from(Instant.now())); - streak = streakRepository.save(streak); - - user.setStreak(streak); - try { - return userRepository.save(user); - } catch (DataIntegrityViolationException e) { - log.error("[UserServiceImpl:register] email already exists: {}", user.getEmail()); - throw new EmailAlreadyExistsException(); - } - } - - /** - * Authenticates a user by exchanging a BankID authorization code for an access token and retrieves user information. - * This method contacts the BankID service to obtain an access token using the provided authorization code and then - * fetches the user details from the BankID userinfo endpoint. If the user is new, it registers them in the database. - * - * @param code The authorization code provided by the BankID authentication flow. - * @param state The state parameter to ensure the response corresponds to the request made by the user. - * @return A {@link User} object populated with details retrieved from BankID if authentication is successful, - * or null if an error occurs during the process. - */ - @Override - public User bankIDAuth(String code, String state) { - try { - String tokenUrl = "https://preprod.signicat.com/oidc/token"; - HttpPost httpPost = new HttpPost(tokenUrl); - httpPost.setHeader(HttpHeaders.ACCEPT, ContentType.APPLICATION_JSON.toString()); - httpPost.setHeader(HttpHeaders.AUTHORIZATION, "Basic " + "ZGVtby1wcmVwcm9kOm1xWi1fNzUtZjJ3TnNpUVRPTmI3T240YUFaN3pjMjE4bXJSVmsxb3VmYTg="); - List<NameValuePair> params = new ArrayList<>(); - params.add(new BasicNameValuePair("client_id", "demo-preprod")); - params.add(new BasicNameValuePair("redirect_uri", SparestiApplication.getBackendURL() + "/redirect")); - params.add(new BasicNameValuePair("grant_type", "authorization_code")); - params.add(new BasicNameValuePair("code", code)); - httpPost.setEntity(new UrlEncodedFormEntity(params, StandardCharsets.UTF_8)); - final String content = postRequest(httpPost); - // parse response - JSONObject jsonObject = new ObjectMapper().readValue(content, JSONObject.class); - String accessToken = (String) jsonObject.get("access_token"); - - //get userinfo - HttpPost httpPost_userinfo = new HttpPost("https://preprod.signicat.com/oidc/userinfo"); - httpPost_userinfo.setHeader(HttpHeaders.ACCEPT, ContentType.APPLICATION_JSON.toString()); - httpPost_userinfo.setHeader(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken); - final String content_userinfo = postRequest(httpPost_userinfo); - JSONObject jsonObject2 = new ObjectMapper().readValue(content_userinfo, JSONObject.class); - - String sub = (String) jsonObject2.get("sub"); - Optional<User> optionalUser = userRepository.findByBankIdSub(sub); - if (optionalUser.isPresent()) { - return optionalUser.get(); - } - User user = new User(); - user.setRole(Role.USER); - user.setCreatedAt(Timestamp.from(Instant.now())); - user.setBankIdSub(sub); - user.setFirstName((String) jsonObject2.get("given_name")); - user.setLastName((String) jsonObject2.get("family_name")); - userRepository.save(user); - return user; - } catch (Exception e) { - log.error("[UserServiceImpl:bankIDAuth] an error occurred"); - e.printStackTrace(); - } - return null; - } - - /** - * Sends an HTTP POST request and returns the response content as a string. - * This method is used internally to communicate with external services like BankID. - * - * @param httpPost The {@link HttpPost} object configured with the URL, headers, and body of the request. - * @return A string containing the response body. - * @throws Exception If the HTTP request fails or the server response indicates an error. - */ - protected String postRequest(final HttpPost httpPost) throws Exception { - try { - CloseableHttpClient httpClient = HttpClientBuilder.create().useSystemProperties().build(); - CloseableHttpResponse httpResponse = httpClient.execute(httpPost); - final int status = httpResponse.getStatusLine().getStatusCode(); - if (status == HttpStatus.SC_FORBIDDEN || status / 100 != 2) { - log.error("[UserServiceImpl:postRequest] an error occurred"); - throw new Exception("Something went wrong!! Handle this properly!!!"); - } - final String content = EntityUtils.toString(httpResponse.getEntity(), StandardCharsets.UTF_8); - return content; - } catch (final Exception e) { - log.error("[UserServiceImpl:postRequest] an error occurred"); - throw new Exception(e.getMessage()); - } - } - - /** - * Updates the details of an existing user in the database. - * - * @param user The user object containing updated fields that should be persisted. - * @return The updated user object as persisted in the database. - * @throws EmailAlreadyExistsException If an attempt to update the user data results in a violation of unique constraint for the email field. - */ - @Override - public User update(User user) { - try { - return userRepository.save(user); - } catch (DataIntegrityViolationException e) { - log.error("[UserServiceImpl:update] data integrity violation: {}", e.getMostSpecificCause().getMessage()); - throw new UserException(e.getMostSpecificCause().getMessage()); - } - } - - /** - * Deletes a user from the system based on the specified user ID. - * This method permanently removes the user's record from the database. It should be used with caution, - * as this operation is irreversible and results in the loss of all data associated with the user's account. - * - * @param userId The unique identifier of the user to be deleted. - */ - @Override - public void delete(long userId) { - userRepository.deleteById(userId); - } - - /** - * Updates the password of a user. - * - * @param id The ID of the user - * @param oldPassword The old password - * @param newPassword The new password - * @return The updated User object, persisted in the database. - * @throws InvalidCredentialsException if the old password is invalid. - */ - @Override - public User updatePassword(long id, String oldPassword, String newPassword) { - User user = findById(id); - boolean match = passwordEncoder.matches(oldPassword, user.getPassword()); - if (match) { - String encodedPassword = passwordEncoder.encode(newPassword); - user.setPassword(encodedPassword); - } else { - log.error("[UserServiceImpl:updatePassword] invalid old password: {}", oldPassword); - throw new InvalidCredentialsException("Old password is invalid"); - } - return userRepository.save(user); - } - - /** - * Retrieves a user by their email address. - * - * @param email The email address to search for in the database. - * @return The user object associated with the specified email address. - * @throws UserNotFoundException If no user is found associated with the provided email address. - */ - @Override - public User findByEmail(String email) { - Optional<User> optionalUser = userRepository.findByEmail(email); - if (optionalUser.isPresent()) { - return optionalUser.get(); - } else { - log.error("[UserServiceImpl:findByEmail] user is not found: {}", email); - throw new UserNotFoundException(); - } - } - - /** - * Retrieves a user by their unique identifier. - * - * @param userId The unique ID of the user to retrieve. - * @return The user object associated with the specified ID. - * @throws UserNotFoundException If no user is found with the specified ID. - */ - @Override - public User findById(long userId) { - Optional<User> optionalUser = userRepository.findById(userId); - if (optionalUser.isPresent()) { - return optionalUser.get(); - } else { - log.error("[UserServiceImpl:findById] user is not found: {}", userId); - throw new UserNotFoundException(); - } - } - - /** - * Initiates the password reset process by generating a reset token and sending an email. - * - * @param email The email of the user requesting a password reset. - */ - @Override - public void initiatePasswordReset(String email) { - User user = findByEmail(email); - PasswordResetToken resetToken = new PasswordResetToken(); - resetToken.setUser(user); - String token = UUID.randomUUID().toString(); - resetToken.setToken(token); - resetToken.setCreatedAt(Timestamp.from(Instant.now())); - try { - tokenRepository.save(resetToken); - } catch (DataIntegrityViolationException e) { - log.error("[UserServiceImpl:initiatePasswordReset] error generating token"); - throw new RuntimeException("Error generating token"); - } - try { - emailService.sendForgotPasswordEmail(email, token); - } catch (MessagingException | IOException e) { - log.error("[UserServiceImpl:initiatePasswordReset] an error occurred"); - throw new RuntimeException(e.getMessage()); - } - } - - /** - * Confirms and processes the password reset request by updating the user's password. - * - * @param token The reset token provided by the user. - * @param password The new password to be set for the user. - * @throws InvalidPasswordResetTokenException If the token is expired or invalid. - */ - @Override - public void confirmPasswordReset(String token, String password) { - Optional<PasswordResetToken> optionalResetToken = tokenRepository.findByToken(token); - if (optionalResetToken.isPresent()) { - PasswordResetToken resetToken = optionalResetToken.get(); - - LocalDateTime tokenCreationDate = resetToken.getCreatedAt().toLocalDateTime(); - Duration durationBetween = Duration.between(tokenCreationDate, LocalDateTime.now()); - if (durationBetween.isNegative() || durationBetween.compareTo(PASSWORD_RESET_DURATION) > 0) { - log.error("[UserServiceImpl:confirmPasswordReset] invalid token: {}", token); - throw new InvalidPasswordResetTokenException(); - } - - User user = resetToken.getUser(); - user.setPassword(passwordEncoder.encode(password)); - userRepository.save(user); - } else { - log.error("[UserServiceImpl:confirmPasswordReset] invalid token: {}", token); - throw new InvalidPasswordResetTokenException(); - } - } - - - /** - * Retrieves a list of {@link User} objects representing the friends of the specified user. - * - * @param userId The ID of the user whose friends are to be retrieved - * @return a list of {@link User} instances representing the user's friends - */ - @Override - public List<User> getFriends(Long userId) { - List<Friend> friendsFriend = friendService.getFriends(userId); - List<User> friendsUser = new ArrayList<>(); - - for(Friend friend : friendsFriend) { - if(friend.getId().getUser().getId() != userId) { - friendsUser.add(friend.getId().getUser()); - } else { - friendsUser.add(friend.getId().getFriend()); - } - } - return friendsUser; - } - - /** - * Retrieves a list of {@link User} objects representing the friend requests of the specified user. - * - * @param userId The ID of the user whose friend requests are to be retrieved - * @return a list of {@link User} instances representing the user's friend requests - */ - @Override - public List<User> getFriendRequests(Long userId) { - List<Friend> friendsFriend = friendService.getFriendRequests(userId); - List<User> friendsUser = new ArrayList<>(); - - for(Friend friend : friendsFriend) { - if(friend.getId().getUser().getId() != userId) { - friendsUser.add(friend.getId().getUser()); - } else { - friendsUser.add(friend.getId().getFriend()); - } - } - return friendsUser; - } - - /** - * Retrieves a list of User entities based on a search term and a specified filter. - * - * @param userId The ID of the user. Used to exclude that user and all of its friends - * from the result. - * @param searchTerm The search term used to filter user names. - * @param filter A filter that is used to filter based on a category. - * @return A list of User objects that match the search criteria and filter. - */ - @Override - public List<User> getUsersByNameAndFilter(Long userId, String searchTerm, SearchFilter filter) { - List<User> users = userRepository.findUsersByName(searchTerm); - users.removeIf(user -> user.getId().equals(userId)); - List<User> friends = new ArrayList<>(); - switch (filter) { - case NON_FRIENDS: - friends = getFriends(userId); - users.removeAll(friends); - break; - case FRIENDS: - friends = getFriends(userId); - Iterator<User> iterator = users.iterator(); - while (iterator.hasNext()) { - User user = iterator.next(); - if (!friends.contains(user)) { - iterator.remove(); - } - } - break; - } - return users; - } - - /** - * Retrieves a list of randomly selected {@link User} objects based on the specified filter. - * - * @param userId The ID of the user. Used to exclude that user and all of its friends - * from the result depending on filter. - * @param amount The number of random users to retrieve. - * @param filter A filter that is used to filter based on a category. - * @return A list of randomly selected {@link User} objects. - */ - @Override - public List<User> getRandomUsers(Long userId, int amount, SearchFilter filter) { - List<User> users = userRepository.findAll(); - users.removeIf(user -> user.getId().equals(userId)); - switch (filter) { - case NON_FRIENDS: - List<User> friends = getFriends(userId); - users.removeAll(friends); - break; - } - - Collections.shuffle(users); - while(users.size() > amount) { - users.remove(users.get(users.size() - 1)); - } - return users; - } - - - /** - * Updates the subscription level of a specified user. - * - * @param userId The ID of the user whose subscription level is to be updated. - * @param subscriptionLevel The new SubscriptionLevel to assign to the user. - */ - @Override - public void updateSubscriptionLevel(Long userId, SubscriptionLevel subscriptionLevel) { - userRepository.updateSubscriptionLevel(userId, subscriptionLevel); - } - /** - * Sends feedback from an email. - * - * @param email The email. - * @param message The message. - */ - @Override - public void sendFeedback(String email, String message) { - Feedback feedback = Feedback.builder().email(email).message(message).createdAt(Timestamp.from(Instant.now())).build(); - feedbackRepository.save(feedback); - } - - /** - * Get all feedback. - * - * @return A list containing all feedback. - */ - @Override - public List<Feedback> getFeedback() { - return feedbackRepository.findAll(); - } - - /** - * Check if the user has more than or equal to - * amount of current points as points - * - * @param user the user - * @param points the amount of points to compare with - * @return true or false - */ - @Override - public Boolean hasMorePoints(User user, int points) { - return user.getPoint().getCurrentPoints() >= points; - } - - /** - * Deduct a number of current points from the user - * - * @param userId The user - * @param points The amount of current points to deduct - */ - @Override - public void deductPoints(Long userId, int points) { - userRepository.deductPoints(userId, points); - } + private static final Duration PASSWORD_RESET_DURATION = Duration.ofHours(1); + + @Autowired + private UserRepository userRepository; + + @Autowired + private FriendService friendService; + + @Autowired + private PointRepository pointRepository; + + @Autowired + private StreakRepository streakRepository; + + @Autowired + private PasswordResetTokenRepository tokenRepository; + + @Autowired + private PasswordEncoder passwordEncoder; + + @Autowired + private EmailService emailService; + + @Autowired + AccountService accountService; + + @Autowired + FeedbackRepository feedbackRepository; + + /** + * Authenticates a user with the provided email and password. + * @param email The email address of the user. + * @param password The password associated with the user's account. + * @return The authenticated user object if login is successful. + * @throws InvalidCredentialsException if the provided credentials are invalid. + * @throws UserNotFoundException if the user with the provided email is not found. + */ + @Override + public User login(String email, String password) { + Optional<User> optionalUser = userRepository.findByEmail(email); + if (optionalUser.isPresent()) { + User user = optionalUser.get(); + boolean match = passwordEncoder.matches(password, user.getPassword()); + if (match) { + return user; + } + else { + log.error("[UserServiceImpl:login] invalid credentials: email: {}, password: {}", email, password); + throw new InvalidCredentialsException(); + } + } + else { + log.error("[UserServiceImpl:login] user is not found, email: {}", email); + throw new UserNotFoundException(); + } + } + + /** + * Registers a new user. + * @param user The user object containing registration information. + * @return The registered user object. + * @throws EmailAlreadyExistsException if the provided email already exists in the + * system. + */ + @Override + public User register(User user) { + String encodedPassword = passwordEncoder.encode(user.getPassword()); + user.setPassword(encodedPassword); + user.setRole(Role.USER); + user.setCreatedAt(Timestamp.from(Instant.now())); + + // Create and save a new Point object + Point point = new Point(); + point.setCurrentPoints(0); + point.setTotalEarnedPoints(0); + point = pointRepository.save(point); + + user.setPoint(point); + + Streak streak = new Streak(); + streak.setCurrentStreak(0); + streak.setCurrentStreakCreatedAt(Timestamp.from(Instant.now())); + streak.setCurrentStreakUpdatedAt(Timestamp.from(Instant.now())); + streak.setHighestStreak(0); + streak.setHighestStreakCreatedAt(Timestamp.from(Instant.now())); + streak.setHighestStreakEndedAt(Timestamp.from(Instant.now())); + streak = streakRepository.save(streak); + + user.setStreak(streak); + try { + return userRepository.save(user); + } + catch (DataIntegrityViolationException e) { + log.error("[UserServiceImpl:register] email already exists: {}", user.getEmail()); + throw new EmailAlreadyExistsException(); + } + } + + /** + * Authenticates a user by exchanging a BankID authorization code for an access token + * and retrieves user information. This method contacts the BankID service to obtain + * an access token using the provided authorization code and then fetches the user + * details from the BankID userinfo endpoint. If the user is new, it registers them in + * the database. + * @param code The authorization code provided by the BankID authentication flow. + * @param state The state parameter to ensure the response corresponds to the request + * made by the user. + * @return A {@link User} object populated with details retrieved from BankID if + * authentication is successful, or null if an error occurs during the process. + */ + @Override + public User bankIDAuth(String code, String state) { + try { + String tokenUrl = "https://preprod.signicat.com/oidc/token"; + HttpPost httpPost = new HttpPost(tokenUrl); + httpPost.setHeader(HttpHeaders.ACCEPT, ContentType.APPLICATION_JSON.toString()); + httpPost.setHeader(HttpHeaders.AUTHORIZATION, + "Basic " + "ZGVtby1wcmVwcm9kOm1xWi1fNzUtZjJ3TnNpUVRPTmI3T240YUFaN3pjMjE4bXJSVmsxb3VmYTg="); + List<NameValuePair> params = new ArrayList<>(); + params.add(new BasicNameValuePair("client_id", "demo-preprod")); + params.add(new BasicNameValuePair("redirect_uri", SparestiApplication.getBackendURL() + "/redirect")); + params.add(new BasicNameValuePair("grant_type", "authorization_code")); + params.add(new BasicNameValuePair("code", code)); + httpPost.setEntity(new UrlEncodedFormEntity(params, StandardCharsets.UTF_8)); + final String content = postRequest(httpPost); + // parse response + JSONObject jsonObject = new ObjectMapper().readValue(content, JSONObject.class); + String accessToken = (String) jsonObject.get("access_token"); + + // get userinfo + HttpPost httpPost_userinfo = new HttpPost("https://preprod.signicat.com/oidc/userinfo"); + httpPost_userinfo.setHeader(HttpHeaders.ACCEPT, ContentType.APPLICATION_JSON.toString()); + httpPost_userinfo.setHeader(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken); + final String content_userinfo = postRequest(httpPost_userinfo); + JSONObject jsonObject2 = new ObjectMapper().readValue(content_userinfo, JSONObject.class); + + String sub = (String) jsonObject2.get("sub"); + Optional<User> optionalUser = userRepository.findByBankIdSub(sub); + if (optionalUser.isPresent()) { + return optionalUser.get(); + } + User user = new User(); + user.setRole(Role.USER); + user.setCreatedAt(Timestamp.from(Instant.now())); + user.setBankIdSub(sub); + user.setFirstName((String) jsonObject2.get("given_name")); + user.setLastName((String) jsonObject2.get("family_name")); + userRepository.save(user); + return user; + } + catch (Exception e) { + log.error("[UserServiceImpl:bankIDAuth] an error occurred"); + e.printStackTrace(); + } + return null; + } + + /** + * Sends an HTTP POST request and returns the response content as a string. This + * method is used internally to communicate with external services like BankID. + * @param httpPost The {@link HttpPost} object configured with the URL, headers, and + * body of the request. + * @return A string containing the response body. + * @throws Exception If the HTTP request fails or the server response indicates an + * error. + */ + protected String postRequest(final HttpPost httpPost) throws Exception { + try { + CloseableHttpClient httpClient = HttpClientBuilder.create().useSystemProperties().build(); + CloseableHttpResponse httpResponse = httpClient.execute(httpPost); + final int status = httpResponse.getStatusLine().getStatusCode(); + if (status == HttpStatus.SC_FORBIDDEN || status / 100 != 2) { + log.error("[UserServiceImpl:postRequest] an error occurred"); + throw new Exception("Something went wrong!! Handle this properly!!!"); + } + final String content = EntityUtils.toString(httpResponse.getEntity(), StandardCharsets.UTF_8); + return content; + } + catch (final Exception e) { + log.error("[UserServiceImpl:postRequest] an error occurred"); + throw new Exception(e.getMessage()); + } + } + + /** + * Updates the details of an existing user in the database. + * @param user The user object containing updated fields that should be persisted. + * @return The updated user object as persisted in the database. + * @throws EmailAlreadyExistsException If an attempt to update the user data results + * in a violation of unique constraint for the email field. + */ + @Override + public User update(User user) { + try { + return userRepository.save(user); + } + catch (DataIntegrityViolationException e) { + log.error("[UserServiceImpl:update] data integrity violation: {}", e.getMostSpecificCause().getMessage()); + throw new UserException(e.getMostSpecificCause().getMessage()); + } + } + + /** + * Deletes a user from the system based on the specified user ID. This method + * permanently removes the user's record from the database. It should be used with + * caution, as this operation is irreversible and results in the loss of all data + * associated with the user's account. + * @param userId The unique identifier of the user to be deleted. + */ + @Override + public void delete(long userId) { + userRepository.deleteById(userId); + } + + /** + * Updates the password of a user. + * @param id The ID of the user + * @param oldPassword The old password + * @param newPassword The new password + * @return The updated User object, persisted in the database. + * @throws InvalidCredentialsException if the old password is invalid. + */ + @Override + public User updatePassword(long id, String oldPassword, String newPassword) { + User user = findById(id); + boolean match = passwordEncoder.matches(oldPassword, user.getPassword()); + if (match) { + String encodedPassword = passwordEncoder.encode(newPassword); + user.setPassword(encodedPassword); + } + else { + log.error("[UserServiceImpl:updatePassword] invalid old password: {}", oldPassword); + throw new InvalidCredentialsException("Old password is invalid"); + } + return userRepository.save(user); + } + + /** + * Retrieves a user by their email address. + * @param email The email address to search for in the database. + * @return The user object associated with the specified email address. + * @throws UserNotFoundException If no user is found associated with the provided + * email address. + */ + @Override + public User findByEmail(String email) { + Optional<User> optionalUser = userRepository.findByEmail(email); + if (optionalUser.isPresent()) { + return optionalUser.get(); + } + else { + log.error("[UserServiceImpl:findByEmail] user is not found: {}", email); + throw new UserNotFoundException(); + } + } + + /** + * Retrieves a user by their unique identifier. + * @param userId The unique ID of the user to retrieve. + * @return The user object associated with the specified ID. + * @throws UserNotFoundException If no user is found with the specified ID. + */ + @Override + public User findById(long userId) { + Optional<User> optionalUser = userRepository.findById(userId); + if (optionalUser.isPresent()) { + return optionalUser.get(); + } + else { + log.error("[UserServiceImpl:findById] user is not found: {}", userId); + throw new UserNotFoundException(); + } + } + + /** + * Initiates the password reset process by generating a reset token and sending an + * email. + * @param email The email of the user requesting a password reset. + */ + @Override + public void initiatePasswordReset(String email) { + User user = findByEmail(email); + PasswordResetToken resetToken = new PasswordResetToken(); + resetToken.setUser(user); + String token = UUID.randomUUID().toString(); + resetToken.setToken(token); + resetToken.setCreatedAt(Timestamp.from(Instant.now())); + try { + tokenRepository.save(resetToken); + } + catch (DataIntegrityViolationException e) { + log.error("[UserServiceImpl:initiatePasswordReset] error generating token"); + throw new RuntimeException("Error generating token"); + } + try { + emailService.sendForgotPasswordEmail(email, token); + } + catch (MessagingException | IOException e) { + log.error("[UserServiceImpl:initiatePasswordReset] an error occurred"); + throw new RuntimeException(e.getMessage()); + } + } + + /** + * Confirms and processes the password reset request by updating the user's password. + * @param token The reset token provided by the user. + * @param password The new password to be set for the user. + * @throws InvalidPasswordResetTokenException If the token is expired or invalid. + */ + @Override + public void confirmPasswordReset(String token, String password) { + Optional<PasswordResetToken> optionalResetToken = tokenRepository.findByToken(token); + if (optionalResetToken.isPresent()) { + PasswordResetToken resetToken = optionalResetToken.get(); + + LocalDateTime tokenCreationDate = resetToken.getCreatedAt().toLocalDateTime(); + Duration durationBetween = Duration.between(tokenCreationDate, LocalDateTime.now()); + if (durationBetween.isNegative() || durationBetween.compareTo(PASSWORD_RESET_DURATION) > 0) { + log.error("[UserServiceImpl:confirmPasswordReset] invalid token: {}", token); + throw new InvalidPasswordResetTokenException(); + } + + User user = resetToken.getUser(); + user.setPassword(passwordEncoder.encode(password)); + userRepository.save(user); + } + else { + log.error("[UserServiceImpl:confirmPasswordReset] invalid token: {}", token); + throw new InvalidPasswordResetTokenException(); + } + } + + /** + * Retrieves a list of {@link User} objects representing the friends of the specified + * user. + * @param userId The ID of the user whose friends are to be retrieved + * @return a list of {@link User} instances representing the user's friends + */ + @Override + public List<User> getFriends(Long userId) { + List<Friend> friendsFriend = friendService.getFriends(userId); + List<User> friendsUser = new ArrayList<>(); + + for (Friend friend : friendsFriend) { + if (friend.getId().getUser().getId() != userId) { + friendsUser.add(friend.getId().getUser()); + } + else { + friendsUser.add(friend.getId().getFriend()); + } + } + return friendsUser; + } + + /** + * Retrieves a list of {@link User} objects representing the friend requests of the + * specified user. + * @param userId The ID of the user whose friend requests are to be retrieved + * @return a list of {@link User} instances representing the user's friend requests + */ + @Override + public List<User> getFriendRequests(Long userId) { + List<Friend> friendsFriend = friendService.getFriendRequests(userId); + List<User> friendsUser = new ArrayList<>(); + + for (Friend friend : friendsFriend) { + if (friend.getId().getUser().getId() != userId) { + friendsUser.add(friend.getId().getUser()); + } + else { + friendsUser.add(friend.getId().getFriend()); + } + } + return friendsUser; + } + + /** + * Retrieves a list of User entities based on a search term and a specified filter. + * @param userId The ID of the user. Used to exclude that user and all of its friends + * from the result. + * @param searchTerm The search term used to filter user names. + * @param filter A filter that is used to filter based on a category. + * @return A list of User objects that match the search criteria and filter. + */ + @Override + public List<User> getUsersByNameAndFilter(Long userId, String searchTerm, SearchFilter filter) { + List<User> users = userRepository.findUsersByName(searchTerm); + users.removeIf(user -> user.getId().equals(userId)); + List<User> friends = new ArrayList<>(); + switch (filter) { + case NON_FRIENDS: + friends = getFriends(userId); + users.removeAll(friends); + break; + case FRIENDS: + friends = getFriends(userId); + Iterator<User> iterator = users.iterator(); + while (iterator.hasNext()) { + User user = iterator.next(); + if (!friends.contains(user)) { + iterator.remove(); + } + } + break; + } + return users; + } + + /** + * Retrieves a list of randomly selected {@link User} objects based on the specified + * filter. + * @param userId The ID of the user. Used to exclude that user and all of its friends + * from the result depending on filter. + * @param amount The number of random users to retrieve. + * @param filter A filter that is used to filter based on a category. + * @return A list of randomly selected {@link User} objects. + */ + @Override + public List<User> getRandomUsers(Long userId, int amount, SearchFilter filter) { + List<User> users = userRepository.findAll(); + users.removeIf(user -> user.getId().equals(userId)); + switch (filter) { + case NON_FRIENDS: + List<User> friends = getFriends(userId); + users.removeAll(friends); + break; + } + + Collections.shuffle(users); + while (users.size() > amount) { + users.remove(users.get(users.size() - 1)); + } + return users; + } + + /** + * Updates the subscription level of a specified user. + * @param userId The ID of the user whose subscription level is to be updated. + * @param subscriptionLevel The new SubscriptionLevel to assign to the user. + */ + @Override + public void updateSubscriptionLevel(Long userId, SubscriptionLevel subscriptionLevel) { + userRepository.updateSubscriptionLevel(userId, subscriptionLevel); + } + + /** + * Sends feedback from an email. + * @param email The email. + * @param message The message. + */ + @Override + public void sendFeedback(String email, String message) { + Feedback feedback = Feedback.builder() + .email(email) + .message(message) + .createdAt(Timestamp.from(Instant.now())) + .build(); + feedbackRepository.save(feedback); + } + + /** + * Get all feedback. + * @return A list containing all feedback. + */ + @Override + public List<Feedback> getFeedback() { + return feedbackRepository.findAll(); + } + + /** + * Check if the user has more than or equal to amount of current points as points + * @param user the user + * @param points the amount of points to compare with + * @return true or false + */ + @Override + public Boolean hasMorePoints(User user, int points) { + return user.getPoint().getCurrentPoints() >= points; + } + + /** + * Deduct a number of current points from the user + * @param userId The user + * @param points The amount of current points to deduct + */ + @Override + public void deductPoints(Long userId, int points) { + userRepository.deductPoints(userId, points); + } + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/utils/TokenUtils.java b/src/main/java/no/ntnu/idi/stud/savingsapp/utils/TokenUtils.java index bc74e206f53abb69dc958944df3699133c9d4eb0..88e1e12b5ee025fc8ad643d6e4862639f927fa95 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/utils/TokenUtils.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/utils/TokenUtils.java @@ -15,21 +15,21 @@ import java.time.Instant; @Component public final class TokenUtils { - /** - * Generates a JWT (JSON Web Token) for the given user. - * - * @param user The user for whom the token is generated. - * @return The generated JWT token as a string. - */ - public static String generateToken(final User user) { - final Instant now = Instant.now(); - final Algorithm hmac512 = Algorithm.HMAC512(TokenProperties.SECRET); - return JWT.create() - .withSubject(String.valueOf(user.getId())) - .withClaim("user_role", user.getRole().name()) - .withIssuer("sparesti") - .withIssuedAt(now) - .withExpiresAt(now.plusMillis(Duration.ofMinutes(TokenProperties.DURATION).toMillis())) - .sign(hmac512); - } + /** + * Generates a JWT (JSON Web Token) for the given user. + * @param user The user for whom the token is generated. + * @return The generated JWT token as a string. + */ + public static String generateToken(final User user) { + final Instant now = Instant.now(); + final Algorithm hmac512 = Algorithm.HMAC512(TokenProperties.SECRET); + return JWT.create() + .withSubject(String.valueOf(user.getId())) + .withClaim("user_role", user.getRole().name()) + .withIssuer("sparesti") + .withIssuedAt(now) + .withExpiresAt(now.plusMillis(Duration.ofMinutes(TokenProperties.DURATION).toMillis())) + .sign(hmac512); + } + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/validation/Enumerator.java b/src/main/java/no/ntnu/idi/stud/savingsapp/validation/Enumerator.java index 5a5068a235d159c62a32d564be2f7d2661229f22..2738dfab9c25ca07d429551650ef9ea942eee758 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/validation/Enumerator.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/validation/Enumerator.java @@ -7,47 +7,45 @@ import no.ntnu.idi.stud.savingsapp.validation.impl.EnumeratorValidator; import java.lang.annotation.*; /** - * Annotation for validating enum values. - * This annotation is used to mark fields or parameters that represent enums, - * ensuring that they meet specific validation criteria defined by the associated validator. + * Annotation for validating enum values. This annotation is used to mark fields or + * parameters that represent enums, ensuring that they meet specific validation criteria + * defined by the associated validator. */ @Documented @Constraint(validatedBy = EnumeratorValidator.class) -@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE_USE}) +@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE_USE }) @Retention(RetentionPolicy.RUNTIME) public @interface Enumerator { - /** - * Specifies the enum class that represents the valid values for the annotated element. - * @return The enum class representing valid values. - */ - Class<? extends Enum<?>> value(); - - /** - * Specifies whether the annotated element is allowed to be null. - * @return True if the annotated element can be null, false otherwise. - */ - boolean nullable() default true; - - /** - * Specifies the default error message that will be used when the validation fails. - * - * @return The default error message. - */ - String message() default "Invalid enum value"; - - /** - * Specifies the groups to which this constraint belongs. - * - * @return An array of group classes. - */ - Class<?>[] groups() default {}; - - /** - * Specifies additional metadata about the annotation. - * - * @return An array of payload classes. - */ - Class<? extends Payload>[] payload() default {}; + /** + * Specifies the enum class that represents the valid values for the annotated + * element. + * @return The enum class representing valid values. + */ + Class<? extends Enum<?>> value(); + + /** + * Specifies whether the annotated element is allowed to be null. + * @return True if the annotated element can be null, false otherwise. + */ + boolean nullable() default true; + + /** + * Specifies the default error message that will be used when the validation fails. + * @return The default error message. + */ + String message() default "Invalid enum value"; + + /** + * Specifies the groups to which this constraint belongs. + * @return An array of group classes. + */ + Class<?>[] groups() default {}; + + /** + * Specifies additional metadata about the annotation. + * @return An array of payload classes. + */ + Class<? extends Payload>[] payload() default {}; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/validation/Name.java b/src/main/java/no/ntnu/idi/stud/savingsapp/validation/Name.java index 323093fd6a3da8701ca61c44d0d0dadb50f49add..fda13f8f956f03c2917012d4c2fd0714a8fa4df7 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/validation/Name.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/validation/Name.java @@ -7,41 +7,38 @@ import no.ntnu.idi.stud.savingsapp.validation.impl.NameValidator; import java.lang.annotation.*; /** - * Annotation for validating names. - * This annotation is used to mark fields or parameters that represent names, - * ensuring that they meet specific validation criteria defined by the associated validator. + * Annotation for validating names. This annotation is used to mark fields or parameters + * that represent names, ensuring that they meet specific validation criteria defined by + * the associated validator. */ @Documented @Constraint(validatedBy = NameValidator.class) -@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE_USE}) +@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE_USE }) @Retention(RetentionPolicy.RUNTIME) public @interface Name { - /** - * Specifies whether the annotated element is allowed to be null. - * @return True if the annotated element can be null, false otherwise. - */ - boolean nullable() default false; - - /** - * Specifies the default error message that will be used when the validation fails. - * - * @return The default error message. - */ - String message() default "Invalid name"; - - /** - * Specifies the groups to which this constraint belongs. - * - * @return An array of group classes. - */ - Class<?>[] groups() default {}; - - /** - * Specifies additional metadata about the annotation. - * - * @return An array of payload classes. - */ - Class<? extends Payload>[] payload() default {}; + /** + * Specifies whether the annotated element is allowed to be null. + * @return True if the annotated element can be null, false otherwise. + */ + boolean nullable() default false; + + /** + * Specifies the default error message that will be used when the validation fails. + * @return The default error message. + */ + String message() default "Invalid name"; + + /** + * Specifies the groups to which this constraint belongs. + * @return An array of group classes. + */ + Class<?>[] groups() default {}; + + /** + * Specifies additional metadata about the annotation. + * @return An array of payload classes. + */ + Class<? extends Payload>[] payload() default {}; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/validation/Password.java b/src/main/java/no/ntnu/idi/stud/savingsapp/validation/Password.java index dbb7dc4151f900537e413d7f956453511c3d7945..0459b9c8df606c68f8ec4ca20c3052989a94c698 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/validation/Password.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/validation/Password.java @@ -7,41 +7,38 @@ import no.ntnu.idi.stud.savingsapp.validation.impl.PasswordValidator; import java.lang.annotation.*; /** - * Annotation for validating passwords. - * This annotation is used to mark fields or parameters that represent passwords, - * ensuring that they meet specific validation criteria defined by the associated validator. + * Annotation for validating passwords. This annotation is used to mark fields or + * parameters that represent passwords, ensuring that they meet specific validation + * criteria defined by the associated validator. */ @Documented @Constraint(validatedBy = PasswordValidator.class) -@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER}) +@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER }) @Retention(RetentionPolicy.RUNTIME) public @interface Password { - /** - * Specifies whether the annotated element is allowed to be null. - * @return True if the annotated element can be null, false otherwise. - */ - boolean nullable() default false; - - /** - * Specifies the default error message that will be used when the validation fails. - * - * @return The default error message. - */ - String message() default "Invalid password"; - - /** - * Specifies the groups to which this constraint belongs. - * - * @return An array of group classes. - */ - Class<?>[] groups() default {}; - - /** - * Specifies additional metadata about the annotation. - * - * @return An array of payload classes. - */ - Class<? extends Payload>[] payload() default {}; + /** + * Specifies whether the annotated element is allowed to be null. + * @return True if the annotated element can be null, false otherwise. + */ + boolean nullable() default false; + + /** + * Specifies the default error message that will be used when the validation fails. + * @return The default error message. + */ + String message() default "Invalid password"; + + /** + * Specifies the groups to which this constraint belongs. + * @return An array of group classes. + */ + Class<?>[] groups() default {}; + + /** + * Specifies additional metadata about the annotation. + * @return An array of payload classes. + */ + Class<? extends Payload>[] payload() default {}; } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/validation/impl/EnumeratorValidator.java b/src/main/java/no/ntnu/idi/stud/savingsapp/validation/impl/EnumeratorValidator.java index 5511201d70581bf797a46cdc68dbab264e04e4c5..8881c41bfd2dbc506f7205a49ad6ccbab0214811 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/validation/impl/EnumeratorValidator.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/validation/impl/EnumeratorValidator.java @@ -9,48 +9,49 @@ import java.util.Set; import java.util.stream.Collectors; /** - * Validator for the Enumerator constraint. - * This validator ensures that an enumerator meets the specified - * criteria defined in the application properties. + * Validator for the Enumerator constraint. This validator ensures that an enumerator + * meets the specified criteria defined in the application properties. */ public final class EnumeratorValidator implements ConstraintValidator<Enumerator, String> { - private Enumerator enumerator; - private Set<String> types; - - /** - * Initializes the validator. - * - * @param enumerator The Enumerator annotation. - */ - @Override - public void initialize(Enumerator enumerator) { - this.enumerator = enumerator; - this.types = Arrays.stream(enumerator.value().getEnumConstants()).map(Enum::name).collect(Collectors.toSet());; - } - - /** - * Validates an enumerator. - * - * @param value The value to validate. - * @param context The constraint validator context. - * @return true if the value is valid, false otherwise. - */ - @Override - public boolean isValid(String value, ConstraintValidatorContext context) { - String message = null; - if (value == null && !enumerator.nullable()) { - message = enumerator.value().getSimpleName() + " value is required"; - } else if (value != null && !types.contains(value)) { - message = "Invalid enum value '" + value + "' for " + enumerator.value().getSimpleName(); - } - - if (message != null) { - context.disableDefaultConstraintViolation(); - context.buildConstraintViolationWithTemplate(message).addConstraintViolation(); - return false; - } - - return true; - } + private Enumerator enumerator; + + private Set<String> types; + + /** + * Initializes the validator. + * @param enumerator The Enumerator annotation. + */ + @Override + public void initialize(Enumerator enumerator) { + this.enumerator = enumerator; + this.types = Arrays.stream(enumerator.value().getEnumConstants()).map(Enum::name).collect(Collectors.toSet()); + ; + } + + /** + * Validates an enumerator. + * @param value The value to validate. + * @param context The constraint validator context. + * @return true if the value is valid, false otherwise. + */ + @Override + public boolean isValid(String value, ConstraintValidatorContext context) { + String message = null; + if (value == null && !enumerator.nullable()) { + message = enumerator.value().getSimpleName() + " value is required"; + } + else if (value != null && !types.contains(value)) { + message = "Invalid enum value '" + value + "' for " + enumerator.value().getSimpleName(); + } + + if (message != null) { + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate(message).addConstraintViolation(); + return false; + } + + return true; + } + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/validation/impl/NameValidator.java b/src/main/java/no/ntnu/idi/stud/savingsapp/validation/impl/NameValidator.java index ce98cbffc9f3d750f8c00db0c1355327af665c7b..d06d1bc86ec6e6edda54ad18a0b292863e9234a7 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/validation/impl/NameValidator.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/validation/impl/NameValidator.java @@ -8,52 +8,54 @@ import no.ntnu.idi.stud.savingsapp.validation.Name; import java.util.regex.Pattern; /** - * Validator for the Name constraint. - * This validator ensures that a name meets the specified - * criteria defined in the application properties. + * Validator for the Name constraint. This validator ensures that a name meets the + * specified criteria defined in the application properties. */ public final class NameValidator implements ConstraintValidator<Name, String> { - private Name nameConstraint; - private Pattern pattern; - - /** - * Initializes the validator. - * - * @param name The Name annotation. - */ - @Override - public void initialize(Name name) { - this.nameConstraint = name; - if (pattern == null) { - pattern = Pattern.compile(UserProperties.NAME_REGEX); - } - } - - /** - * Validates a name. - * - * @param username The name to validate. - * @param context The constraint validator context. - * @return true if the name is valid, false otherwise. - */ - @Override - public boolean isValid(String name, ConstraintValidatorContext context) { - String message = null; - if (name == null && !this.nameConstraint.nullable()) { - message = UserProperties.NAME_EMPTY; - } else if (name != null && (name.length() < UserProperties.NAME_LEN_MIN || name.length() > UserProperties.NAME_LEN_MAX)) { - message = UserProperties.NAME_LEN_MSG; - } else if (name != null && !pattern.matcher(name).matches()) { - message = UserProperties.NAME_REGEX_MSG; - } - - if (message != null) { - context.disableDefaultConstraintViolation(); - context.buildConstraintViolationWithTemplate(message).addConstraintViolation(); - return false; - } - - return true; - } + private Name nameConstraint; + + private Pattern pattern; + + /** + * Initializes the validator. + * @param name The Name annotation. + */ + @Override + public void initialize(Name name) { + this.nameConstraint = name; + if (pattern == null) { + pattern = Pattern.compile(UserProperties.NAME_REGEX); + } + } + + /** + * Validates a name. + * @param username The name to validate. + * @param context The constraint validator context. + * @return true if the name is valid, false otherwise. + */ + @Override + public boolean isValid(String name, ConstraintValidatorContext context) { + String message = null; + if (name == null && !this.nameConstraint.nullable()) { + message = UserProperties.NAME_EMPTY; + } + else if (name != null + && (name.length() < UserProperties.NAME_LEN_MIN || name.length() > UserProperties.NAME_LEN_MAX)) { + message = UserProperties.NAME_LEN_MSG; + } + else if (name != null && !pattern.matcher(name).matches()) { + message = UserProperties.NAME_REGEX_MSG; + } + + if (message != null) { + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate(message).addConstraintViolation(); + return false; + } + + return true; + } + } diff --git a/src/main/java/no/ntnu/idi/stud/savingsapp/validation/impl/PasswordValidator.java b/src/main/java/no/ntnu/idi/stud/savingsapp/validation/impl/PasswordValidator.java index 205bde4a9a6411bd9c44d51379b2a18648ba49e2..72a961557e1f8205a3ab4fbe0a5f9f24cc7823ca 100644 --- a/src/main/java/no/ntnu/idi/stud/savingsapp/validation/impl/PasswordValidator.java +++ b/src/main/java/no/ntnu/idi/stud/savingsapp/validation/impl/PasswordValidator.java @@ -8,52 +8,54 @@ import no.ntnu.idi.stud.savingsapp.validation.Password; import java.util.regex.Pattern; /** - * Validator for the Password constraint. - * This validator ensures that a password meets the specified - * criteria defined in the application properties. + * Validator for the Password constraint. This validator ensures that a password meets the + * specified criteria defined in the application properties. */ public final class PasswordValidator implements ConstraintValidator<Password, String> { - private Password passwordConstraint; - public Pattern pattern; - - /** - * Initializes the validator. - * - * @param password The Password annotation. - */ - @Override - public void initialize(Password password) { - passwordConstraint = password; - if (pattern == null) { - pattern = Pattern.compile(UserProperties.PASS_REGEX); - } - } - - /** - * Validates a password. - * - * @param password The password to validate. - * @param context The constraint validator context. - * @return true if the password is valid, false otherwise. - */ - @Override - public boolean isValid(String password, ConstraintValidatorContext context) { - String message = null; - if (password == null && !passwordConstraint.nullable()) { - message = UserProperties.PASS_EMPTY; - } else if (password != null && (password.length() < UserProperties.PASS_LEN_MIN || password.length() > UserProperties.PASS_LEN_MAX)) { - message = UserProperties.PASS_LEN_MSG; - } else if (password != null && !pattern.matcher(password).matches()) { - message = UserProperties.PASS_REGEX_MSG; - } - - if (message != null) { - context.disableDefaultConstraintViolation(); - context.buildConstraintViolationWithTemplate(message).addConstraintViolation(); - return false; - } - - return true; - } + private Password passwordConstraint; + + public Pattern pattern; + + /** + * Initializes the validator. + * @param password The Password annotation. + */ + @Override + public void initialize(Password password) { + passwordConstraint = password; + if (pattern == null) { + pattern = Pattern.compile(UserProperties.PASS_REGEX); + } + } + + /** + * Validates a password. + * @param password The password to validate. + * @param context The constraint validator context. + * @return true if the password is valid, false otherwise. + */ + @Override + public boolean isValid(String password, ConstraintValidatorContext context) { + String message = null; + if (password == null && !passwordConstraint.nullable()) { + message = UserProperties.PASS_EMPTY; + } + else if (password != null && (password.length() < UserProperties.PASS_LEN_MIN + || password.length() > UserProperties.PASS_LEN_MAX)) { + message = UserProperties.PASS_LEN_MSG; + } + else if (password != null && !pattern.matcher(password).matches()) { + message = UserProperties.PASS_REGEX_MSG; + } + + if (message != null) { + context.disableDefaultConstraintViolation(); + context.buildConstraintViolationWithTemplate(message).addConstraintViolation(); + return false; + } + + return true; + } + } diff --git a/src/test/java/no/ntnu/idi/stud/savingsapp/JsonUtil.java b/src/test/java/no/ntnu/idi/stud/savingsapp/JsonUtil.java index 8a0e761dce9136d2cb74308805b5381ffa486eab..22ce01d842ab66e6d2483d936e61368e8921f736 100644 --- a/src/test/java/no/ntnu/idi/stud/savingsapp/JsonUtil.java +++ b/src/test/java/no/ntnu/idi/stud/savingsapp/JsonUtil.java @@ -7,9 +7,10 @@ import java.io.IOException; public class JsonUtil { - public static byte[] toJson(Object object) throws IOException { - ObjectMapper mapper = new ObjectMapper(); - mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); - return mapper.writeValueAsBytes(object); - } + public static byte[] toJson(Object object) throws IOException { + ObjectMapper mapper = new ObjectMapper(); + mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); + return mapper.writeValueAsBytes(object); + } + } diff --git a/src/test/java/no/ntnu/idi/stud/savingsapp/SparestiApplicationTests.java b/src/test/java/no/ntnu/idi/stud/savingsapp/SparestiApplicationTests.java index 4c0f1177e7b2b64689d8e9a3bd46a19bc992ff02..475e6f75ddf913130da780acd2298bdf0506dac5 100644 --- a/src/test/java/no/ntnu/idi/stud/savingsapp/SparestiApplicationTests.java +++ b/src/test/java/no/ntnu/idi/stud/savingsapp/SparestiApplicationTests.java @@ -10,4 +10,5 @@ class SparestiApplicationTests { @Test void contextLoads() { } + } diff --git a/src/test/java/no/ntnu/idi/stud/savingsapp/UserUtil.java b/src/test/java/no/ntnu/idi/stud/savingsapp/UserUtil.java index d933c78ad34088980037efe28e06e314a544bcd0..8c536cfddee3905999fa29a1cfc9a1e2e4ee0856 100644 --- a/src/test/java/no/ntnu/idi/stud/savingsapp/UserUtil.java +++ b/src/test/java/no/ntnu/idi/stud/savingsapp/UserUtil.java @@ -9,13 +9,13 @@ import org.springframework.security.core.authority.SimpleGrantedAuthority; public class UserUtil { - public static Authentication getAuthentication(User user) { - return getAuthentication(user.getId(), user.getRole().name()); - } + public static Authentication getAuthentication(User user) { + return getAuthentication(user.getId(), user.getRole().name()); + } - public static Authentication getAuthentication(long userId, String role) { - return new UsernamePasswordAuthenticationToken(new AuthIdentity(userId, role), null, - Collections.singletonList(new SimpleGrantedAuthority(role))); - } + public static Authentication getAuthentication(long userId, String role) { + return new UsernamePasswordAuthenticationToken(new AuthIdentity(userId, role), null, + Collections.singletonList(new SimpleGrantedAuthority(role))); + } } diff --git a/src/test/java/no/ntnu/idi/stud/savingsapp/bank/controller/AccountTest.java b/src/test/java/no/ntnu/idi/stud/savingsapp/bank/controller/AccountTest.java index 015841547ef2a31ddb7034760dfcfab4527c4994..26877ba7c94ffb1462b456546dbb4492e472b691 100644 --- a/src/test/java/no/ntnu/idi/stud/savingsapp/bank/controller/AccountTest.java +++ b/src/test/java/no/ntnu/idi/stud/savingsapp/bank/controller/AccountTest.java @@ -15,40 +15,41 @@ import org.springframework.transaction.annotation.Transactional; @Transactional public class AccountTest { - @Autowired - private MockMvc mvc; - - @Test - @WithMockUser - void shouldGetAccountsWithSsn() throws Exception { - mvc.perform(MockMvcRequestBuilders.get("/bank/v1/account/accounts/ssn/31125451740")) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$").isArray()) - .andExpect(MockMvcResultMatchers.jsonPath("$[0].bban").isNumber()) - .andExpect(MockMvcResultMatchers.jsonPath("$[0].balance").isNumber()); - } - - @Test - @WithMockUser - void shouldNotGetAccountsWithWrongSsn() throws Exception { - mvc.perform(MockMvcRequestBuilders.get("/bank/v1/account/accounts/ssn/0")) - .andExpect(MockMvcResultMatchers.status().isNotFound()); - } - - @Test - @WithMockUser - void shouldGetAccountsWithBankProfileId() throws Exception { - mvc.perform(MockMvcRequestBuilders.get("/bank/v1/account/accounts/profile/2")) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$").isArray()) - .andExpect(MockMvcResultMatchers.jsonPath("$[0].bban").isNumber()) - .andExpect(MockMvcResultMatchers.jsonPath("$[0].balance").isNumber()); - } - - @Test - @WithMockUser - void shouldNotGetAccountsWithWrongBankProfileId() throws Exception { - mvc.perform(MockMvcRequestBuilders.get("/bank/v1/account/accounts/profile/0")) - .andExpect(MockMvcResultMatchers.status().isNotFound()); - } + @Autowired + private MockMvc mvc; + + @Test + @WithMockUser + void shouldGetAccountsWithSsn() throws Exception { + mvc.perform(MockMvcRequestBuilders.get("/bank/v1/account/accounts/ssn/31125451740")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$").isArray()) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].bban").isNumber()) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].balance").isNumber()); + } + + @Test + @WithMockUser + void shouldNotGetAccountsWithWrongSsn() throws Exception { + mvc.perform(MockMvcRequestBuilders.get("/bank/v1/account/accounts/ssn/0")) + .andExpect(MockMvcResultMatchers.status().isNotFound()); + } + + @Test + @WithMockUser + void shouldGetAccountsWithBankProfileId() throws Exception { + mvc.perform(MockMvcRequestBuilders.get("/bank/v1/account/accounts/profile/2")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$").isArray()) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].bban").isNumber()) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].balance").isNumber()); + } + + @Test + @WithMockUser + void shouldNotGetAccountsWithWrongBankProfileId() throws Exception { + mvc.perform(MockMvcRequestBuilders.get("/bank/v1/account/accounts/profile/0")) + .andExpect(MockMvcResultMatchers.status().isNotFound()); + } + } diff --git a/src/test/java/no/ntnu/idi/stud/savingsapp/bank/controller/BankProfileTest.java b/src/test/java/no/ntnu/idi/stud/savingsapp/bank/controller/BankProfileTest.java index 739bc950dee409bf06124bc50ff86f0bd8107a85..16df6e0c49e01720159240895143fb59abc3e263 100644 --- a/src/test/java/no/ntnu/idi/stud/savingsapp/bank/controller/BankProfileTest.java +++ b/src/test/java/no/ntnu/idi/stud/savingsapp/bank/controller/BankProfileTest.java @@ -18,30 +18,30 @@ import org.springframework.transaction.annotation.Transactional; @Transactional public class BankProfileTest { - @Autowired - private MockMvc mvc; + @Autowired + private MockMvc mvc; - @Test - @WithMockUser - void shouldRegisterBankProfile() throws Exception{ - BankProfileDTO bankProfileDTO = new BankProfileDTO(); - bankProfileDTO.setSsn(31125452887L); - mvc.perform(MockMvcRequestBuilders.post("/bank/v1/profile/create-profile") - .contentType(MediaType.APPLICATION_JSON) - .content(JsonUtil.toJson(bankProfileDTO))) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$.ssn").exists()) - .andExpect(MockMvcResultMatchers.jsonPath("$.accounts").exists()); - } + @Test + @WithMockUser + void shouldRegisterBankProfile() throws Exception { + BankProfileDTO bankProfileDTO = new BankProfileDTO(); + bankProfileDTO.setSsn(31125452887L); + mvc.perform(MockMvcRequestBuilders.post("/bank/v1/profile/create-profile") + .contentType(MediaType.APPLICATION_JSON) + .content(JsonUtil.toJson(bankProfileDTO))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.ssn").exists()) + .andExpect(MockMvcResultMatchers.jsonPath("$.accounts").exists()); + } + + @Test + @WithMockUser + void shouldNotRegisterBankProfileWithNegativeSsn() throws Exception { + BankProfileDTO bankProfileDTO = new BankProfileDTO(); + bankProfileDTO.setSsn(-31125452887L); + mvc.perform(MockMvcRequestBuilders.post("/bank/v1/profile/create-profile") + .contentType(MediaType.APPLICATION_JSON) + .content(JsonUtil.toJson(bankProfileDTO))).andExpect(MockMvcResultMatchers.status().isBadRequest()); + } - @Test - @WithMockUser - void shouldNotRegisterBankProfileWithNegativeSsn() throws Exception{ - BankProfileDTO bankProfileDTO = new BankProfileDTO(); - bankProfileDTO.setSsn(-31125452887L); - mvc.perform(MockMvcRequestBuilders.post("/bank/v1/profile/create-profile") - .contentType(MediaType.APPLICATION_JSON) - .content(JsonUtil.toJson(bankProfileDTO))) - .andExpect(MockMvcResultMatchers.status().isBadRequest()); - } } diff --git a/src/test/java/no/ntnu/idi/stud/savingsapp/bank/controller/TransactionTest.java b/src/test/java/no/ntnu/idi/stud/savingsapp/bank/controller/TransactionTest.java index df172f7da3959d6cb9598137b31ac26e5b641e2b..03fbfa2692783927f87213e781cbc413cc5fe834 100644 --- a/src/test/java/no/ntnu/idi/stud/savingsapp/bank/controller/TransactionTest.java +++ b/src/test/java/no/ntnu/idi/stud/savingsapp/bank/controller/TransactionTest.java @@ -19,61 +19,60 @@ import org.springframework.transaction.annotation.Transactional; @Transactional public class TransactionTest { - @Autowired - private MockMvc mvc; + @Autowired + private MockMvc mvc; - @Test - @WithMockUser - void shouldTransferMoneyBetweenAccounts() throws Exception { - TransactionDTO transactionRequestDTO = new TransactionDTO(); - transactionRequestDTO.setAmount(BigDecimal.valueOf(50)); - transactionRequestDTO.setDebtorBBAN(12073650567L); - transactionRequestDTO.setCreditorBBAN(12097256355L); - mvc.perform(MockMvcRequestBuilders.post("/bank/v1/transaction/norwegian-domestic-payment-to-self") - .contentType(MediaType.APPLICATION_JSON) - .content(JsonUtil.toJson(transactionRequestDTO))) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$.amount").isNumber()) - .andExpect(MockMvcResultMatchers.jsonPath("$.debtorBBAN").isNumber()) - .andExpect(MockMvcResultMatchers.jsonPath("$.creditorBBAN").isNumber()); - } + @Test + @WithMockUser + void shouldTransferMoneyBetweenAccounts() throws Exception { + TransactionDTO transactionRequestDTO = new TransactionDTO(); + transactionRequestDTO.setAmount(BigDecimal.valueOf(50)); + transactionRequestDTO.setDebtorBBAN(12073650567L); + transactionRequestDTO.setCreditorBBAN(12097256355L); + mvc.perform(MockMvcRequestBuilders.post("/bank/v1/transaction/norwegian-domestic-payment-to-self") + .contentType(MediaType.APPLICATION_JSON) + .content(JsonUtil.toJson(transactionRequestDTO))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.amount").isNumber()) + .andExpect(MockMvcResultMatchers.jsonPath("$.debtorBBAN").isNumber()) + .andExpect(MockMvcResultMatchers.jsonPath("$.creditorBBAN").isNumber()); + } - @Test - @WithMockUser - void shouldNotTransferMoneyBetweenWrongAccounts() throws Exception { - TransactionDTO transactionRequestDTO = new TransactionDTO(); - transactionRequestDTO.setAmount(BigDecimal.valueOf(50)); - transactionRequestDTO.setDebtorBBAN(0L); - transactionRequestDTO.setCreditorBBAN(12097256355L); - mvc.perform(MockMvcRequestBuilders.post("/bank/v1/transaction/norwegian-domestic-payment-to-self") - .contentType(MediaType.APPLICATION_JSON) - .content(JsonUtil.toJson(transactionRequestDTO))) - .andExpect(MockMvcResultMatchers.status().isNotFound()); - } + @Test + @WithMockUser + void shouldNotTransferMoneyBetweenWrongAccounts() throws Exception { + TransactionDTO transactionRequestDTO = new TransactionDTO(); + transactionRequestDTO.setAmount(BigDecimal.valueOf(50)); + transactionRequestDTO.setDebtorBBAN(0L); + transactionRequestDTO.setCreditorBBAN(12097256355L); + mvc.perform(MockMvcRequestBuilders.post("/bank/v1/transaction/norwegian-domestic-payment-to-self") + .contentType(MediaType.APPLICATION_JSON) + .content(JsonUtil.toJson(transactionRequestDTO))).andExpect(MockMvcResultMatchers.status().isNotFound()); + } - @Test - @WithMockUser - void shouldNotTransferMoneyWithNegativeTransferAmount() throws Exception { - TransactionDTO transactionRequestDTO = new TransactionDTO(); - transactionRequestDTO.setAmount(BigDecimal.valueOf(-50)); - transactionRequestDTO.setDebtorBBAN(12073650567L); - transactionRequestDTO.setCreditorBBAN(12097256355L); - mvc.perform(MockMvcRequestBuilders.post("/bank/v1/transaction/norwegian-domestic-payment-to-self") - .contentType(MediaType.APPLICATION_JSON) - .content(JsonUtil.toJson(transactionRequestDTO))) - .andExpect(MockMvcResultMatchers.status().isBadRequest()); - } + @Test + @WithMockUser + void shouldNotTransferMoneyWithNegativeTransferAmount() throws Exception { + TransactionDTO transactionRequestDTO = new TransactionDTO(); + transactionRequestDTO.setAmount(BigDecimal.valueOf(-50)); + transactionRequestDTO.setDebtorBBAN(12073650567L); + transactionRequestDTO.setCreditorBBAN(12097256355L); + mvc.perform(MockMvcRequestBuilders.post("/bank/v1/transaction/norwegian-domestic-payment-to-self") + .contentType(MediaType.APPLICATION_JSON) + .content(JsonUtil.toJson(transactionRequestDTO))).andExpect(MockMvcResultMatchers.status().isBadRequest()); + } + + @Test + @WithMockUser + void shouldNotTransferMoneyWithInsufficientFunds() throws Exception { + TransactionDTO transactionRequestDTO = new TransactionDTO(); + transactionRequestDTO.setAmount(BigDecimal.valueOf(10000000)); + transactionRequestDTO.setDebtorBBAN(12073650567L); + transactionRequestDTO.setCreditorBBAN(12097256355L); + mvc.perform(MockMvcRequestBuilders.post("/bank/v1/transaction/norwegian-domestic-payment-to-self") + .contentType(MediaType.APPLICATION_JSON) + .content(JsonUtil.toJson(transactionRequestDTO))) + .andExpect(MockMvcResultMatchers.status().isPaymentRequired()); + } - @Test - @WithMockUser - void shouldNotTransferMoneyWithInsufficientFunds() throws Exception { - TransactionDTO transactionRequestDTO = new TransactionDTO(); - transactionRequestDTO.setAmount(BigDecimal.valueOf(10000000)); - transactionRequestDTO.setDebtorBBAN(12073650567L); - transactionRequestDTO.setCreditorBBAN(12097256355L); - mvc.perform(MockMvcRequestBuilders.post("/bank/v1/transaction/norwegian-domestic-payment-to-self") - .contentType(MediaType.APPLICATION_JSON) - .content(JsonUtil.toJson(transactionRequestDTO))) - .andExpect(MockMvcResultMatchers.status().isPaymentRequired()); - } } diff --git a/src/test/java/no/ntnu/idi/stud/savingsapp/controller/authentication/AuthenticationControllerTest.java b/src/test/java/no/ntnu/idi/stud/savingsapp/controller/authentication/AuthenticationControllerTest.java index d3c803c860763f977d9495a3b4a971a2cc0dd603..1ff08d6c1e5409e16614201a00838359d9c1e425 100644 --- a/src/test/java/no/ntnu/idi/stud/savingsapp/controller/authentication/AuthenticationControllerTest.java +++ b/src/test/java/no/ntnu/idi/stud/savingsapp/controller/authentication/AuthenticationControllerTest.java @@ -31,113 +31,106 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @AutoConfigureMockMvc public class AuthenticationControllerTest { - @Autowired - private MockMvc mvc; - - @MockBean - private UserService userService; - - private User user; - - @BeforeEach - public void setup() { - user = new User(); - user.setId(1L); - user.setEmail("test@example.com"); - user.setPassword("securePassword1"); - user.setFirstName("John"); - user.setLastName("Doe"); - user.setRole(Role.USER); - } - - @Test - void login_Success() throws Exception { - LoginRequest loginRequest = new LoginRequest(); - loginRequest.setEmail(user.getEmail()); - loginRequest.setPassword(user.getPassword()); - - when(userService.login(user.getEmail(), user.getPassword())).thenReturn(user); - - mvc.perform(post("/api/auth/login") - .contentType(MediaType.APPLICATION_JSON) - .content(JsonUtil.toJson(loginRequest))) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.token").exists()); - } - - @Test - void login_InvalidCredentials() throws Exception { - LoginRequest loginRequest = new LoginRequest(); - loginRequest.setEmail(user.getEmail()); - loginRequest.setPassword("wrongPassword1"); - - when(userService.login(user.getEmail(), "wrongPassword1")) - .thenThrow(new InvalidCredentialsException()); - - mvc.perform(post("/api/auth/login") - .contentType(MediaType.APPLICATION_JSON) - .content(JsonUtil.toJson(loginRequest))) - .andExpect(status().isUnauthorized()); - } - - @Test - void signup_Success() throws Exception { - SignUpRequest signUpRequest = new SignUpRequest(); - signUpRequest.setEmail(user.getEmail()); - signUpRequest.setPassword(user.getPassword()); - signUpRequest.setFirstName(user.getFirstName()); - signUpRequest.setLastName(user.getLastName()); - ConfigurationDTO configurationDTO = new ConfigurationDTO(); - configurationDTO.setCommitment("MUCH"); - configurationDTO.setExperience("EXPERT"); - configurationDTO.setChallengeTypes(Arrays.asList("NO_COFFEE")); - signUpRequest.setConfiguration(configurationDTO); - - when(userService.register(any())).thenReturn(user); - - mvc.perform(post("/api/auth/signup") - .contentType(MediaType.APPLICATION_JSON) - .content(JsonUtil.toJson(signUpRequest))) - .andExpect(status().isCreated()) - .andExpect(jsonPath("$.token").exists()); - } - - @Test - void signup_EmailExists() throws Exception { - SignUpRequest signUpRequest = new SignUpRequest(); - signUpRequest.setEmail(user.getEmail()); - signUpRequest.setPassword(user.getPassword()); - signUpRequest.setFirstName(user.getFirstName()); - signUpRequest.setLastName(user.getLastName()); - ConfigurationDTO configurationDTO = new ConfigurationDTO(); - configurationDTO.setCommitment("MUCH"); - configurationDTO.setExperience("EXPERT"); - configurationDTO.setChallengeTypes(Arrays.asList("NO_COFFEE")); - signUpRequest.setConfiguration(configurationDTO); - - when(userService.register(any())).thenThrow(new EmailAlreadyExistsException()); - - mvc.perform(post("/api/auth/signup") - .contentType(MediaType.APPLICATION_JSON) - .content(JsonUtil.toJson(signUpRequest))) - .andExpect(status().isConflict()); - } - - @Test - void validateEmail_EmailExists() throws Exception { - String email = "existing@example.com"; - when(userService.findByEmail(email)).thenThrow(new EmailAlreadyExistsException()); - - mvc.perform(post("/api/auth/valid-email/{email}", email)) - .andExpect(status().isConflict()); - } - - @Test - void validateEmail_EmailValid() throws Exception { - String email = "new@example.com"; - when(userService.findByEmail(email)).thenThrow(new UserNotFoundException()); - - mvc.perform(post("/api/auth/valid-email/{email}", email)) - .andExpect(status().isOk()); - } + @Autowired + private MockMvc mvc; + + @MockBean + private UserService userService; + + private User user; + + @BeforeEach + public void setup() { + user = new User(); + user.setId(1L); + user.setEmail("test@example.com"); + user.setPassword("securePassword1"); + user.setFirstName("John"); + user.setLastName("Doe"); + user.setRole(Role.USER); + } + + @Test + void login_Success() throws Exception { + LoginRequest loginRequest = new LoginRequest(); + loginRequest.setEmail(user.getEmail()); + loginRequest.setPassword(user.getPassword()); + + when(userService.login(user.getEmail(), user.getPassword())).thenReturn(user); + + mvc.perform( + post("/api/auth/login").contentType(MediaType.APPLICATION_JSON).content(JsonUtil.toJson(loginRequest))) + .andExpect(status().isOk()) + .andExpect(jsonPath("$.token").exists()); + } + + @Test + void login_InvalidCredentials() throws Exception { + LoginRequest loginRequest = new LoginRequest(); + loginRequest.setEmail(user.getEmail()); + loginRequest.setPassword("wrongPassword1"); + + when(userService.login(user.getEmail(), "wrongPassword1")).thenThrow(new InvalidCredentialsException()); + + mvc.perform( + post("/api/auth/login").contentType(MediaType.APPLICATION_JSON).content(JsonUtil.toJson(loginRequest))) + .andExpect(status().isUnauthorized()); + } + + @Test + void signup_Success() throws Exception { + SignUpRequest signUpRequest = new SignUpRequest(); + signUpRequest.setEmail(user.getEmail()); + signUpRequest.setPassword(user.getPassword()); + signUpRequest.setFirstName(user.getFirstName()); + signUpRequest.setLastName(user.getLastName()); + ConfigurationDTO configurationDTO = new ConfigurationDTO(); + configurationDTO.setCommitment("MUCH"); + configurationDTO.setExperience("EXPERT"); + configurationDTO.setChallengeTypes(Arrays.asList("NO_COFFEE")); + signUpRequest.setConfiguration(configurationDTO); + + when(userService.register(any())).thenReturn(user); + + mvc.perform(post("/api/auth/signup").contentType(MediaType.APPLICATION_JSON) + .content(JsonUtil.toJson(signUpRequest))) + .andExpect(status().isCreated()) + .andExpect(jsonPath("$.token").exists()); + } + + @Test + void signup_EmailExists() throws Exception { + SignUpRequest signUpRequest = new SignUpRequest(); + signUpRequest.setEmail(user.getEmail()); + signUpRequest.setPassword(user.getPassword()); + signUpRequest.setFirstName(user.getFirstName()); + signUpRequest.setLastName(user.getLastName()); + ConfigurationDTO configurationDTO = new ConfigurationDTO(); + configurationDTO.setCommitment("MUCH"); + configurationDTO.setExperience("EXPERT"); + configurationDTO.setChallengeTypes(Arrays.asList("NO_COFFEE")); + signUpRequest.setConfiguration(configurationDTO); + + when(userService.register(any())).thenThrow(new EmailAlreadyExistsException()); + + mvc.perform(post("/api/auth/signup").contentType(MediaType.APPLICATION_JSON) + .content(JsonUtil.toJson(signUpRequest))).andExpect(status().isConflict()); + } + + @Test + void validateEmail_EmailExists() throws Exception { + String email = "existing@example.com"; + when(userService.findByEmail(email)).thenThrow(new EmailAlreadyExistsException()); + + mvc.perform(post("/api/auth/valid-email/{email}", email)).andExpect(status().isConflict()); + } + + @Test + void validateEmail_EmailValid() throws Exception { + String email = "new@example.com"; + when(userService.findByEmail(email)).thenThrow(new UserNotFoundException()); + + mvc.perform(post("/api/auth/valid-email/{email}", email)).andExpect(status().isOk()); + } + } diff --git a/src/test/java/no/ntnu/idi/stud/savingsapp/controller/badge/BadgeControllerTest.java b/src/test/java/no/ntnu/idi/stud/savingsapp/controller/badge/BadgeControllerTest.java index fbd1f78f3b4c64bc220f44aecc7fb5d716a0deb6..81fed5e4cf4e7e04ede49976b9e2476d0a40c027 100644 --- a/src/test/java/no/ntnu/idi/stud/savingsapp/controller/badge/BadgeControllerTest.java +++ b/src/test/java/no/ntnu/idi/stud/savingsapp/controller/badge/BadgeControllerTest.java @@ -21,77 +21,79 @@ import org.springframework.transaction.annotation.Transactional; @Transactional public class BadgeControllerTest { - @Autowired - private MockMvc mvc; - private User user; + @Autowired + private MockMvc mvc; - @BeforeEach - public void setup() { - user = new User(); - user.setId(1L); - user.setRole(Role.USER); - user.setEmail("testuser1@example.com"); - } + private User user; - @Test - @WithMockUser - void getBadgeShouldReturnSuccess() throws Exception { - mvc.perform(MockMvcRequestBuilders.get("/api/badge/1") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$.badgeName").value("Saving Champ")); - } + @BeforeEach + public void setup() { + user = new User(); + user.setId(1L); + user.setRole(Role.USER); + user.setEmail("testuser1@example.com"); + } - @Test - @WithMockUser - void getBadgeShouldReturnError() throws Exception { - mvc.perform(MockMvcRequestBuilders.get("/api/badge/4") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.status().isInternalServerError()); - } + @Test + @WithMockUser + void getBadgeShouldReturnSuccess() throws Exception { + mvc.perform(MockMvcRequestBuilders.get("/api/badge/1") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.badgeName").value("Saving Champ")); + } - @Test - @WithMockUser - void getBadgesShouldReturnListOf3() throws Exception { - mvc.perform(MockMvcRequestBuilders.get("/api/badge") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(3))); - } + @Test + @WithMockUser + void getBadgeShouldReturnError() throws Exception { + mvc.perform(MockMvcRequestBuilders.get("/api/badge/4") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.status().isInternalServerError()); + } - @Test - @WithMockUser - void getUnlockedBadgesByActiveUserShouldReturnListOf2() throws Exception { - mvc.perform(MockMvcRequestBuilders.get("/api/badge/unlocked") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(2))); - } + @Test + @WithMockUser + void getBadgesShouldReturnListOf3() throws Exception { + mvc.perform(MockMvcRequestBuilders.get("/api/badge") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(3))); + } - @Test - @WithMockUser - void getUnlockedBadgesByUserShouldReturnListOf1() throws Exception { - mvc.perform(MockMvcRequestBuilders.get("/api/badge/unlocked/2") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(1))); - } + @Test + @WithMockUser + void getUnlockedBadgesByActiveUserShouldReturnListOf2() throws Exception { + mvc.perform(MockMvcRequestBuilders.get("/api/badge/unlocked") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(2))); + } - @Test - @WithMockUser - void getNotUnlockedBadgesByActiveUserShouldReturnListOf1() throws Exception { - mvc.perform(MockMvcRequestBuilders.get("/api/badge/locked") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(1))); - } + @Test + @WithMockUser + void getUnlockedBadgesByUserShouldReturnListOf1() throws Exception { + mvc.perform(MockMvcRequestBuilders.get("/api/badge/unlocked/2") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(1))); + } + + @Test + @WithMockUser + void getNotUnlockedBadgesByActiveUserShouldReturnListOf1() throws Exception { + mvc.perform(MockMvcRequestBuilders.get("/api/badge/locked") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(1))); + } + + @Test + @WithMockUser + void updateUnlockedBadgesShouldReturnListOf1() throws Exception { + mvc.perform(MockMvcRequestBuilders.get("/api/badge/update") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(1))); + } - @Test - @WithMockUser - void updateUnlockedBadgesShouldReturnListOf1() throws Exception { - mvc.perform(MockMvcRequestBuilders.get("/api/badge/update") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(1))); - } } \ No newline at end of file diff --git a/src/test/java/no/ntnu/idi/stud/savingsapp/controller/budget/BudgetControllerTest.java b/src/test/java/no/ntnu/idi/stud/savingsapp/controller/budget/BudgetControllerTest.java index f167c7477f76e54498e1a8d806f1b195a48ce0ff..35c4a8b85566f06e56f81a5f972a5f99ddfb08ba 100644 --- a/src/test/java/no/ntnu/idi/stud/savingsapp/controller/budget/BudgetControllerTest.java +++ b/src/test/java/no/ntnu/idi/stud/savingsapp/controller/budget/BudgetControllerTest.java @@ -25,169 +25,162 @@ import org.springframework.transaction.annotation.Transactional; @Transactional public class BudgetControllerTest { - @Autowired - private MockMvc mvc; - - private User user; - - - @BeforeEach - public void setup() { - user = new User(); - user.setId(1L); - user.setRole(Role.USER); - user.setEmail("user@example.com"); - user.setFirstName("User"); - user.setLastName("User"); - } - - - @Test - void shouldGetAllBudgetsByUserId() throws Exception { - mvc.perform(MockMvcRequestBuilders.get("/api/budget") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$").isArray()) - // test first budget in list - .andExpect(MockMvcResultMatchers.jsonPath("$[0].id").value(2)) - .andExpect(MockMvcResultMatchers.jsonPath("$[0].budgetName").value("March 2024")) - .andExpect(MockMvcResultMatchers.jsonPath("$[0].budgetAmount").value(20000.00)) - .andExpect(MockMvcResultMatchers.jsonPath("$[0].expenseAmount").value(5000.00)) - // test second budget in list - .andExpect(MockMvcResultMatchers.jsonPath("$[1].id").value(1)) - .andExpect(MockMvcResultMatchers.jsonPath("$[1].budgetName").value("April 2024")) - .andExpect(MockMvcResultMatchers.jsonPath("$[1].budgetAmount").value(10000.00)) - .andExpect(MockMvcResultMatchers.jsonPath("$[1].expenseAmount").value(5000.00)); - } - - @Test - @WithMockUser - void shouldGetBudgetByBudgetId() throws Exception { - mvc.perform(MockMvcRequestBuilders.get("/api/budget/1")) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(1)) - .andExpect(MockMvcResultMatchers.jsonPath("$.budgetName").value("April 2024")) - .andExpect(MockMvcResultMatchers.jsonPath("$.budgetAmount").value(10000.00)) - .andExpect(MockMvcResultMatchers.jsonPath("$.expenseAmount").value(5000.00)); - } - - @Test - void shouldCreateBudget() throws Exception { - BudgetRequestDTO budgetRequestDTO = new BudgetRequestDTO(); - budgetRequestDTO.setBudgetName("Test Budget"); - budgetRequestDTO.setBudgetAmount(new BigDecimal(200)); - budgetRequestDTO.setExpenseAmount(new BigDecimal(100)); - - mvc.perform(MockMvcRequestBuilders - .post("/api/budget/create") - .with(SecurityMockMvcRequestPostProcessors - .authentication(UserUtil.getAuthentication(user))) - .content(JsonUtil.toJson(budgetRequestDTO)) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.status().isOk()); - } - - @Test - @WithMockUser - void shouldUpdateBudgetGivenBudgetId() throws Exception { - BudgetRequestDTO updatedBudget = new BudgetRequestDTO(); - updatedBudget.setBudgetName("Update test"); - updatedBudget.setBudgetAmount(new BigDecimal(20)); - updatedBudget.setExpenseAmount(new BigDecimal(10)); - - mvc.perform(MockMvcRequestBuilders.get("/api/budget/1")) - .andExpect(MockMvcResultMatchers.jsonPath("$.budgetName").value("April 2024")) - .andExpect(MockMvcResultMatchers.jsonPath("$.budgetAmount").value(10000.00)) - .andExpect(MockMvcResultMatchers.jsonPath("$.expenseAmount").value(5000.00)); - - mvc.perform(MockMvcRequestBuilders.post("/api/budget/update/1") - .content(JsonUtil.toJson(updatedBudget)) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.status().isOk()); - - mvc.perform(MockMvcRequestBuilders.get("/api/budget/1")) - .andExpect(MockMvcResultMatchers.jsonPath("$.budgetName").value("Update test")) - .andExpect(MockMvcResultMatchers.jsonPath("$.expenseAmount").value(10.00)) - .andExpect(MockMvcResultMatchers.jsonPath("$.budgetAmount").value(20.00)); - } - - @Test - @WithMockUser - void shouldDeleteBudgetByBudgetId() throws Exception { - - mvc.perform(MockMvcRequestBuilders.get("/api/budget/1")) - .andExpect(MockMvcResultMatchers.status().isOk()); - - mvc.perform(MockMvcRequestBuilders.get("/api/budget/delete/1")) - .andExpect(MockMvcResultMatchers.status().isOk()); - - mvc.perform(MockMvcRequestBuilders.get("/api/budget/1")) - .andExpect(MockMvcResultMatchers.status().isInternalServerError()); - - } - - @Test - @WithMockUser - void shouldUpdateExpenseByBudgetId() throws Exception { - ExpenseRequestDTO expenseRequestDTO = new ExpenseRequestDTO(); - expenseRequestDTO.setExpenseId(1L); - expenseRequestDTO.setAmount(new BigDecimal(10)); - expenseRequestDTO.setDescription("Updated description"); - - mvc.perform(MockMvcRequestBuilders.get("/api/budget/expense/1")) - .andExpect(MockMvcResultMatchers.jsonPath("$.description").value("Rent")) - .andExpect(MockMvcResultMatchers.jsonPath("$.amount").value("8000.00")); - - mvc.perform(MockMvcRequestBuilders.post("/api/budget/update/expense/1") - .contentType(MediaType.APPLICATION_JSON) - .content(JsonUtil.toJson(expenseRequestDTO))) - .andExpect(MockMvcResultMatchers.status().isOk()); - - mvc.perform(MockMvcRequestBuilders.get("/api/budget/expense/1")) - .andExpect(MockMvcResultMatchers.jsonPath("$.description").value("Updated description")) - .andExpect(MockMvcResultMatchers.jsonPath("$.amount").value("10")); - } - - @Test - @WithMockUser - void shouldGetExpenseByExpenseId() throws Exception{ - mvc.perform(MockMvcRequestBuilders.get("/api/budget/expense/1")) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$.description").value("Rent")) - .andExpect(MockMvcResultMatchers.jsonPath("$.amount").value("8000.00")); - } - - @Test - @WithMockUser - void shouldGetAllExpensesByBugetId() throws Exception{ - mvc.perform(MockMvcRequestBuilders.get("/api/budget/expenses/1")) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$").isArray()) - // check first expense - .andExpect(MockMvcResultMatchers.jsonPath("$[2].description").value("Rent")) - .andExpect(MockMvcResultMatchers.jsonPath("$[2].amount").value("8000.00")) - .andExpect(MockMvcResultMatchers.jsonPath("$[2].budgetId").value(1)) - // check second expense - .andExpect(MockMvcResultMatchers.jsonPath("$[1].description").value("Cheese")) - .andExpect(MockMvcResultMatchers.jsonPath("$[1].amount").value("1000.00")) - .andExpect(MockMvcResultMatchers.jsonPath("$[1].budgetId").value(1)) - // check third expense - .andExpect(MockMvcResultMatchers.jsonPath("$[0].description").value("Milk")) - .andExpect(MockMvcResultMatchers.jsonPath("$[0].amount").value("1000.00")) - .andExpect(MockMvcResultMatchers.jsonPath("$[0].budgetId").value(1)); - } - - @Test - @WithMockUser - void shouldDeleteExpenseByExpenseId() throws Exception{ - - mvc.perform(MockMvcRequestBuilders.get("/api/budget/expense/1")) - .andExpect(MockMvcResultMatchers.status().isOk()); - - mvc.perform(MockMvcRequestBuilders.get("/api/budget/delete/expense/1")) - .andExpect(MockMvcResultMatchers.status().isOk()); - - mvc.perform(MockMvcRequestBuilders.get("/api/budget/expense/1")) - .andExpect(MockMvcResultMatchers.status().isInternalServerError()); - } + @Autowired + private MockMvc mvc; + + private User user; + + @BeforeEach + public void setup() { + user = new User(); + user.setId(1L); + user.setRole(Role.USER); + user.setEmail("user@example.com"); + user.setFirstName("User"); + user.setLastName("User"); + } + + @Test + void shouldGetAllBudgetsByUserId() throws Exception { + mvc.perform(MockMvcRequestBuilders.get("/api/budget") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$").isArray()) + // test first budget in list + .andExpect(MockMvcResultMatchers.jsonPath("$[0].id").value(2)) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].budgetName").value("March 2024")) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].budgetAmount").value(20000.00)) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].expenseAmount").value(5000.00)) + // test second budget in list + .andExpect(MockMvcResultMatchers.jsonPath("$[1].id").value(1)) + .andExpect(MockMvcResultMatchers.jsonPath("$[1].budgetName").value("April 2024")) + .andExpect(MockMvcResultMatchers.jsonPath("$[1].budgetAmount").value(10000.00)) + .andExpect(MockMvcResultMatchers.jsonPath("$[1].expenseAmount").value(5000.00)); + } + + @Test + @WithMockUser + void shouldGetBudgetByBudgetId() throws Exception { + mvc.perform(MockMvcRequestBuilders.get("/api/budget/1")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(1)) + .andExpect(MockMvcResultMatchers.jsonPath("$.budgetName").value("April 2024")) + .andExpect(MockMvcResultMatchers.jsonPath("$.budgetAmount").value(10000.00)) + .andExpect(MockMvcResultMatchers.jsonPath("$.expenseAmount").value(5000.00)); + } + + @Test + void shouldCreateBudget() throws Exception { + BudgetRequestDTO budgetRequestDTO = new BudgetRequestDTO(); + budgetRequestDTO.setBudgetName("Test Budget"); + budgetRequestDTO.setBudgetAmount(new BigDecimal(200)); + budgetRequestDTO.setExpenseAmount(new BigDecimal(100)); + + mvc.perform(MockMvcRequestBuilders.post("/api/budget/create") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user))) + .content(JsonUtil.toJson(budgetRequestDTO)) + .contentType(MediaType.APPLICATION_JSON)).andExpect(MockMvcResultMatchers.status().isOk()); + } + + @Test + @WithMockUser + void shouldUpdateBudgetGivenBudgetId() throws Exception { + BudgetRequestDTO updatedBudget = new BudgetRequestDTO(); + updatedBudget.setBudgetName("Update test"); + updatedBudget.setBudgetAmount(new BigDecimal(20)); + updatedBudget.setExpenseAmount(new BigDecimal(10)); + + mvc.perform(MockMvcRequestBuilders.get("/api/budget/1")) + .andExpect(MockMvcResultMatchers.jsonPath("$.budgetName").value("April 2024")) + .andExpect(MockMvcResultMatchers.jsonPath("$.budgetAmount").value(10000.00)) + .andExpect(MockMvcResultMatchers.jsonPath("$.expenseAmount").value(5000.00)); + + mvc.perform(MockMvcRequestBuilders.post("/api/budget/update/1") + .content(JsonUtil.toJson(updatedBudget)) + .contentType(MediaType.APPLICATION_JSON)).andExpect(MockMvcResultMatchers.status().isOk()); + + mvc.perform(MockMvcRequestBuilders.get("/api/budget/1")) + .andExpect(MockMvcResultMatchers.jsonPath("$.budgetName").value("Update test")) + .andExpect(MockMvcResultMatchers.jsonPath("$.expenseAmount").value(10.00)) + .andExpect(MockMvcResultMatchers.jsonPath("$.budgetAmount").value(20.00)); + } + + @Test + @WithMockUser + void shouldDeleteBudgetByBudgetId() throws Exception { + + mvc.perform(MockMvcRequestBuilders.get("/api/budget/1")).andExpect(MockMvcResultMatchers.status().isOk()); + + mvc.perform(MockMvcRequestBuilders.get("/api/budget/delete/1")) + .andExpect(MockMvcResultMatchers.status().isOk()); + + mvc.perform(MockMvcRequestBuilders.get("/api/budget/1")) + .andExpect(MockMvcResultMatchers.status().isInternalServerError()); + + } + + @Test + @WithMockUser + void shouldUpdateExpenseByBudgetId() throws Exception { + ExpenseRequestDTO expenseRequestDTO = new ExpenseRequestDTO(); + expenseRequestDTO.setExpenseId(1L); + expenseRequestDTO.setAmount(new BigDecimal(10)); + expenseRequestDTO.setDescription("Updated description"); + + mvc.perform(MockMvcRequestBuilders.get("/api/budget/expense/1")) + .andExpect(MockMvcResultMatchers.jsonPath("$.description").value("Rent")) + .andExpect(MockMvcResultMatchers.jsonPath("$.amount").value("8000.00")); + + mvc.perform(MockMvcRequestBuilders.post("/api/budget/update/expense/1") + .contentType(MediaType.APPLICATION_JSON) + .content(JsonUtil.toJson(expenseRequestDTO))).andExpect(MockMvcResultMatchers.status().isOk()); + + mvc.perform(MockMvcRequestBuilders.get("/api/budget/expense/1")) + .andExpect(MockMvcResultMatchers.jsonPath("$.description").value("Updated description")) + .andExpect(MockMvcResultMatchers.jsonPath("$.amount").value("10")); + } + + @Test + @WithMockUser + void shouldGetExpenseByExpenseId() throws Exception { + mvc.perform(MockMvcRequestBuilders.get("/api/budget/expense/1")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.description").value("Rent")) + .andExpect(MockMvcResultMatchers.jsonPath("$.amount").value("8000.00")); + } + + @Test + @WithMockUser + void shouldGetAllExpensesByBugetId() throws Exception { + mvc.perform(MockMvcRequestBuilders.get("/api/budget/expenses/1")) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$").isArray()) + // check first expense + .andExpect(MockMvcResultMatchers.jsonPath("$[2].description").value("Rent")) + .andExpect(MockMvcResultMatchers.jsonPath("$[2].amount").value("8000.00")) + .andExpect(MockMvcResultMatchers.jsonPath("$[2].budgetId").value(1)) + // check second expense + .andExpect(MockMvcResultMatchers.jsonPath("$[1].description").value("Cheese")) + .andExpect(MockMvcResultMatchers.jsonPath("$[1].amount").value("1000.00")) + .andExpect(MockMvcResultMatchers.jsonPath("$[1].budgetId").value(1)) + // check third expense + .andExpect(MockMvcResultMatchers.jsonPath("$[0].description").value("Milk")) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].amount").value("1000.00")) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].budgetId").value(1)); + } + + @Test + @WithMockUser + void shouldDeleteExpenseByExpenseId() throws Exception { + + mvc.perform(MockMvcRequestBuilders.get("/api/budget/expense/1")) + .andExpect(MockMvcResultMatchers.status().isOk()); + + mvc.perform(MockMvcRequestBuilders.get("/api/budget/delete/expense/1")) + .andExpect(MockMvcResultMatchers.status().isOk()); + + mvc.perform(MockMvcRequestBuilders.get("/api/budget/expense/1")) + .andExpect(MockMvcResultMatchers.status().isInternalServerError()); + } + } diff --git a/src/test/java/no/ntnu/idi/stud/savingsapp/controller/feedback/FeedbackControllerTest.java b/src/test/java/no/ntnu/idi/stud/savingsapp/controller/feedback/FeedbackControllerTest.java index e4922c92fb4fe5cb048e4f7b86b6ba3941423ce1..6366015c7297350c3b03d6dbb6837a6ab9d19d22 100644 --- a/src/test/java/no/ntnu/idi/stud/savingsapp/controller/feedback/FeedbackControllerTest.java +++ b/src/test/java/no/ntnu/idi/stud/savingsapp/controller/feedback/FeedbackControllerTest.java @@ -24,68 +24,68 @@ import org.springframework.transaction.annotation.Transactional; @Transactional public class FeedbackControllerTest { - @Autowired - private MockMvc mvc; + @Autowired + private MockMvc mvc; - @Autowired - private ObjectMapper objectMapper; + @Autowired + private ObjectMapper objectMapper; - private User user; + private User user; - @BeforeEach - public void setup() { - user = new User(); - user.setId(3L); - user.setRole(Role.ADMIN); - user.setEmail("testuser1@example.com"); - } + @BeforeEach + public void setup() { + user = new User(); + user.setId(3L); + user.setRole(Role.ADMIN); + user.setEmail("testuser1@example.com"); + } + @Test + @WithMockUser + void postFeedBackShouldReturnSuccess() throws Exception { + FeedbackRequestDTO feedbackRequestDTO = new FeedbackRequestDTO(); + feedbackRequestDTO.setEmail("user@example.com"); + feedbackRequestDTO.setMessage("I didn't like this app"); + mvc.perform(MockMvcRequestBuilders.post("/api/users/send-feedback") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(feedbackRequestDTO))) + .andExpect(MockMvcResultMatchers.status().isOk()); + } - @Test - @WithMockUser - void postFeedBackShouldReturnSuccess() throws Exception { - FeedbackRequestDTO feedbackRequestDTO = new FeedbackRequestDTO(); - feedbackRequestDTO.setEmail("user@example.com"); - feedbackRequestDTO.setMessage("I didn't like this app"); - mvc.perform(MockMvcRequestBuilders.post("/api/users/send-feedback") - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(feedbackRequestDTO))) - .andExpect(MockMvcResultMatchers.status().isOk()); - } + @Test + @WithMockUser + void postFeedBackShouldReturnError() throws Exception { + FeedbackRequestDTO feedbackRequestDTO = new FeedbackRequestDTO(); + mvc.perform(MockMvcRequestBuilders.post("/api/users/send-feedback") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(feedbackRequestDTO))) + .andExpect(MockMvcResultMatchers.status().isInternalServerError()); + } - @Test - @WithMockUser - void postFeedBackShouldReturnError() throws Exception { - FeedbackRequestDTO feedbackRequestDTO = new FeedbackRequestDTO(); - mvc.perform(MockMvcRequestBuilders.post("/api/users/send-feedback") - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(feedbackRequestDTO))) - .andExpect(MockMvcResultMatchers.status().isInternalServerError()); - } + @Test + @WithMockUser + void getFeedBackShouldReturnListWithLength3() throws Exception { + mvc.perform(MockMvcRequestBuilders.get("/api/users/get-feedback") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(3))); + } - @Test - @WithMockUser - void getFeedBackShouldReturnListWithLength3() throws Exception { - mvc.perform(MockMvcRequestBuilders.get("/api/users/get-feedback") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(3))); - } + @Test + @WithMockUser + void getFeedBackShouldReturnListWithLength4() throws Exception { + FeedbackRequestDTO feedbackRequestDTO = new FeedbackRequestDTO(); + feedbackRequestDTO.setEmail("user@example.com"); + feedbackRequestDTO.setMessage("I didn't like this app"); + mvc.perform(MockMvcRequestBuilders.post("/api/users/send-feedback") + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(feedbackRequestDTO))) + .andExpect(MockMvcResultMatchers.status().isOk()); - @Test - @WithMockUser - void getFeedBackShouldReturnListWithLength4() throws Exception { - FeedbackRequestDTO feedbackRequestDTO = new FeedbackRequestDTO(); - feedbackRequestDTO.setEmail("user@example.com"); - feedbackRequestDTO.setMessage("I didn't like this app"); - mvc.perform(MockMvcRequestBuilders.post("/api/users/send-feedback") - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(feedbackRequestDTO))) - .andExpect(MockMvcResultMatchers.status().isOk()); + mvc.perform(MockMvcRequestBuilders.get("/api/users/get-feedback") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(4))); + } - mvc.perform(MockMvcRequestBuilders.get("/api/users/get-feedback") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(4))); - } } diff --git a/src/test/java/no/ntnu/idi/stud/savingsapp/controller/friend/FriendControllerTest.java b/src/test/java/no/ntnu/idi/stud/savingsapp/controller/friend/FriendControllerTest.java index a6568956e52ea04c63742bccddf6bd38516c555b..bb395f3104aa621dc8061b265f61053f132eabec 100644 --- a/src/test/java/no/ntnu/idi/stud/savingsapp/controller/friend/FriendControllerTest.java +++ b/src/test/java/no/ntnu/idi/stud/savingsapp/controller/friend/FriendControllerTest.java @@ -24,125 +24,125 @@ import static org.hamcrest.Matchers.*; @Transactional public class FriendControllerTest { - @Autowired - private MockMvc mvc; - - private User user; - - @BeforeEach - public void setup() { - user = new User(); - user.setId(3L); - user.setRole(Role.USER); - user.setEmail("testuser1@example.com"); - } - - - @Test - void getFriendsShouldReturnAllFriends() throws Exception { - mvc.perform(MockMvcRequestBuilders.get("/api/friends") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(1))) - .andExpect(MockMvcResultMatchers.jsonPath("$[0].id").value(7)); - } - - @Test - @WithMockUser - void getFriendRequestsShouldReturnAllFriendRequests() throws Exception { - mvc.perform(MockMvcRequestBuilders.get("/api/friends/requests") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(1))) - .andExpect(MockMvcResultMatchers.jsonPath("$[0].id").value(14)); - } - - @Test - @WithMockUser - void putAcceptFriendRequestShouldAddFriend() throws Exception { - mvc.perform(MockMvcRequestBuilders.put("/api/friends/14") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.status().isOk()); - - mvc.perform(MockMvcRequestBuilders.get("/api/friends") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(2))) - .andExpect(MockMvcResultMatchers.jsonPath("$[0].id").value(14)) - .andExpect(MockMvcResultMatchers.jsonPath("$[1].id").value(7)); - } - - @Test - @WithMockUser - void postAddFriendRequestShouldAddFriendRequest() throws Exception { - mvc.perform(MockMvcRequestBuilders.post("/api/friends/3") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.status().isCreated()); - - mvc.perform(MockMvcRequestBuilders.get("/api/friends/requests") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(2))); - } - - @Test - @WithMockUser - void deleteFriendShouldDeleteFriend() throws Exception { - mvc.perform(MockMvcRequestBuilders.delete("/api/friends/7") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.status().isOk()); - - mvc.perform(MockMvcRequestBuilders.get("/api/friends") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(0))); - } - - @Test - @WithMockUser - void getUsersByNameAndFilterNonFriendsShouldNotReturnYourself() throws Exception { - mvc.perform(MockMvcRequestBuilders.get("/api/users/search/ /NON_FRIENDS") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$[*].id", not(contains(3)))); - } - - @Test - @WithMockUser - void getUsersByNameAndFilterNonFriendsShouldNotReturnFriends() throws Exception { - mvc.perform(MockMvcRequestBuilders.get("/api/users/search/ /NON_FRIENDS") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$[*].id", not(contains(5)))) - .andExpect(MockMvcResultMatchers.jsonPath("$[*].id", not(contains(12)))); - } - - @Test - @WithMockUser - void getUsersByNameAdminAndFilterNonFriendsShouldReturnOnlyAdmin() throws Exception { - mvc.perform(MockMvcRequestBuilders.get("/api/users/search/admin/NON_FRIENDS") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(1))) - .andExpect(MockMvcResultMatchers.jsonPath("$[0].id").value(2)) - .andExpect(MockMvcResultMatchers.jsonPath("$[0].firstName").value("Admin")); - } - - @Test - @WithMockUser - void getSevenRandomUsersShouldReturnSevenRandomUsers() throws Exception { - mvc.perform(MockMvcRequestBuilders.get("/api/users/search/random/7/NON_FRIENDS") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(7))); - } - - @Test - @WithMockUser - void getRandomUsersShouldNotIncludeYourself() throws Exception { - mvc.perform(MockMvcRequestBuilders.get("/api/users/search/random/100/NON_FRIENDS") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$[*].id", not(contains(3)))); - } + @Autowired + private MockMvc mvc; + + private User user; + + @BeforeEach + public void setup() { + user = new User(); + user.setId(3L); + user.setRole(Role.USER); + user.setEmail("testuser1@example.com"); + } + + @Test + void getFriendsShouldReturnAllFriends() throws Exception { + mvc.perform(MockMvcRequestBuilders.get("/api/friends") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(1))) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].id").value(7)); + } + + @Test + @WithMockUser + void getFriendRequestsShouldReturnAllFriendRequests() throws Exception { + mvc.perform(MockMvcRequestBuilders.get("/api/friends/requests") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(1))) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].id").value(14)); + } + + @Test + @WithMockUser + void putAcceptFriendRequestShouldAddFriend() throws Exception { + mvc.perform(MockMvcRequestBuilders.put("/api/friends/14") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.status().isOk()); + + mvc.perform(MockMvcRequestBuilders.get("/api/friends") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(2))) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].id").value(14)) + .andExpect(MockMvcResultMatchers.jsonPath("$[1].id").value(7)); + } + + @Test + @WithMockUser + void postAddFriendRequestShouldAddFriendRequest() throws Exception { + mvc.perform(MockMvcRequestBuilders.post("/api/friends/3") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.status().isCreated()); + + mvc.perform(MockMvcRequestBuilders.get("/api/friends/requests") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(2))); + } + + @Test + @WithMockUser + void deleteFriendShouldDeleteFriend() throws Exception { + mvc.perform(MockMvcRequestBuilders.delete("/api/friends/7") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.status().isOk()); + + mvc.perform(MockMvcRequestBuilders.get("/api/friends") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(0))); + } + + @Test + @WithMockUser + void getUsersByNameAndFilterNonFriendsShouldNotReturnYourself() throws Exception { + mvc.perform(MockMvcRequestBuilders.get("/api/users/search/ /NON_FRIENDS") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$[*].id", not(contains(3)))); + } + + @Test + @WithMockUser + void getUsersByNameAndFilterNonFriendsShouldNotReturnFriends() throws Exception { + mvc.perform(MockMvcRequestBuilders.get("/api/users/search/ /NON_FRIENDS") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$[*].id", not(contains(5)))) + .andExpect(MockMvcResultMatchers.jsonPath("$[*].id", not(contains(12)))); + } + + @Test + @WithMockUser + void getUsersByNameAdminAndFilterNonFriendsShouldReturnOnlyAdmin() throws Exception { + mvc.perform(MockMvcRequestBuilders.get("/api/users/search/admin/NON_FRIENDS") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(1))) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].id").value(2)) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].firstName").value("Admin")); + } + + @Test + @WithMockUser + void getSevenRandomUsersShouldReturnSevenRandomUsers() throws Exception { + mvc.perform(MockMvcRequestBuilders.get("/api/users/search/random/7/NON_FRIENDS") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(7))); + } + + @Test + @WithMockUser + void getRandomUsersShouldNotIncludeYourself() throws Exception { + mvc.perform(MockMvcRequestBuilders.get("/api/users/search/random/100/NON_FRIENDS") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$[*].id", not(contains(3)))); + } + } diff --git a/src/test/java/no/ntnu/idi/stud/savingsapp/controller/item/ItemControllerTest.java b/src/test/java/no/ntnu/idi/stud/savingsapp/controller/item/ItemControllerTest.java index e0c4d10011599c84f02fd6bac88b581e857cb410..d896143920331660c8973bb9748b215743b02afc 100644 --- a/src/test/java/no/ntnu/idi/stud/savingsapp/controller/item/ItemControllerTest.java +++ b/src/test/java/no/ntnu/idi/stud/savingsapp/controller/item/ItemControllerTest.java @@ -22,95 +22,94 @@ import org.springframework.transaction.annotation.Transactional; @Transactional public class ItemControllerTest { - @Autowired - private MockMvc mvc; - - private User user; - - @BeforeEach - public void setup() { - user = new User(); - user.setId(3L); - user.setRole(Role.USER); - user.setEmail("testuser1@example.com"); - } - - - @Test - void getInventoryShouldReturnItemWithId3() throws Exception { - mvc.perform(MockMvcRequestBuilders.get("/api/item/inventory") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(1))) - .andExpect(MockMvcResultMatchers.jsonPath("$[0].id").value(3)) - .andExpect(MockMvcResultMatchers.jsonPath("$[0].itemName").value("Item 3")); - } - - - @Test - @WithMockUser - void getStoreShouldReturnEntireStore() throws Exception { - mvc.perform(MockMvcRequestBuilders.get("/api/item/store") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(5))); - } - - @Test - @WithMockUser - void getStoreShouldReturnItem3AsAlreadyBought() throws Exception { - mvc.perform(MockMvcRequestBuilders.get("/api/item/store") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.jsonPath("$[2].alreadyBought").value(true)); - } - - @Test - @WithMockUser - void buyItemShouldNotWorkIfUserHasTooFewPoints() throws Exception { - mvc.perform(MockMvcRequestBuilders.post("/api/item/5") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.status().isForbidden()); - } - - @Test - @WithMockUser - void buyItemShouldWorkIfUserHasEnough() throws Exception { - mvc.perform(MockMvcRequestBuilders.post("/api/item/1") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.status().isCreated()); - } - - @Test - @WithMockUser - void buyItemShouldAddItemToInventory() throws Exception { - mvc.perform(MockMvcRequestBuilders.post("/api/item/1") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.status().isCreated()); - - mvc.perform(MockMvcRequestBuilders.get("/api/item/inventory") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(2))) - .andExpect(MockMvcResultMatchers.jsonPath("$[0].id").value(1)) - .andExpect(MockMvcResultMatchers.jsonPath("$[0].itemName").value("Item 1")) - .andExpect(MockMvcResultMatchers.jsonPath("$[1].id").value(3)) - .andExpect(MockMvcResultMatchers.jsonPath("$[1].itemName").value("Item 3")); - } - - @Test - @WithMockUser - void buyItemShouldBeMarkedAsPurchasedInStore() throws Exception { - mvc.perform(MockMvcRequestBuilders.get("/api/item/store") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$[0].alreadyBought").value(false)); - - mvc.perform(MockMvcRequestBuilders.post("/api/item/1") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.status().isCreated()); - - mvc.perform(MockMvcRequestBuilders.get("/api/item/store") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$[0].alreadyBought").value(true)); - } + @Autowired + private MockMvc mvc; + + private User user; + + @BeforeEach + public void setup() { + user = new User(); + user.setId(3L); + user.setRole(Role.USER); + user.setEmail("testuser1@example.com"); + } + + @Test + void getInventoryShouldReturnItemWithId3() throws Exception { + mvc.perform(MockMvcRequestBuilders.get("/api/item/inventory") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(1))) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].id").value(3)) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].itemName").value("Item 3")); + } + + @Test + @WithMockUser + void getStoreShouldReturnEntireStore() throws Exception { + mvc.perform(MockMvcRequestBuilders.get("/api/item/store") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(5))); + } + + @Test + @WithMockUser + void getStoreShouldReturnItem3AsAlreadyBought() throws Exception { + mvc.perform(MockMvcRequestBuilders.get("/api/item/store") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.jsonPath("$[2].alreadyBought").value(true)); + } + + @Test + @WithMockUser + void buyItemShouldNotWorkIfUserHasTooFewPoints() throws Exception { + mvc.perform(MockMvcRequestBuilders.post("/api/item/5") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.status().isForbidden()); + } + + @Test + @WithMockUser + void buyItemShouldWorkIfUserHasEnough() throws Exception { + mvc.perform(MockMvcRequestBuilders.post("/api/item/1") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.status().isCreated()); + } + + @Test + @WithMockUser + void buyItemShouldAddItemToInventory() throws Exception { + mvc.perform(MockMvcRequestBuilders.post("/api/item/1") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.status().isCreated()); + + mvc.perform(MockMvcRequestBuilders.get("/api/item/inventory") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(2))) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].id").value(1)) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].itemName").value("Item 1")) + .andExpect(MockMvcResultMatchers.jsonPath("$[1].id").value(3)) + .andExpect(MockMvcResultMatchers.jsonPath("$[1].itemName").value("Item 3")); + } + + @Test + @WithMockUser + void buyItemShouldBeMarkedAsPurchasedInStore() throws Exception { + mvc.perform(MockMvcRequestBuilders.get("/api/item/store") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].alreadyBought").value(false)); + + mvc.perform(MockMvcRequestBuilders.post("/api/item/1") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.status().isCreated()); + + mvc.perform(MockMvcRequestBuilders.get("/api/item/store") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$[0].alreadyBought").value(true)); + } + } diff --git a/src/test/java/no/ntnu/idi/stud/savingsapp/controller/leaderboard/LeaderboardControllerTest.java b/src/test/java/no/ntnu/idi/stud/savingsapp/controller/leaderboard/LeaderboardControllerTest.java index db3f5b46436fa7984e2526ffb1a567c8d95f98f4..efdfc29f5727d919917ca87df189ae36d99970e7 100644 --- a/src/test/java/no/ntnu/idi/stud/savingsapp/controller/leaderboard/LeaderboardControllerTest.java +++ b/src/test/java/no/ntnu/idi/stud/savingsapp/controller/leaderboard/LeaderboardControllerTest.java @@ -35,267 +35,258 @@ import no.ntnu.idi.stud.savingsapp.UserUtil; @Transactional public class LeaderboardControllerTest { - @Autowired - private MockMvc mvc; - - @MockBean - private LeaderboardService leaderboardService; - - @InjectMocks - private LeaderboardController leaderboardController; - - private User user1; - private User user2; - private User user3; - - - private Leaderboard leaderboard; - private LeaderboardType leaderboardType; - private LeaderboardFilter leaderboardFilter; - private List<LeaderboardEntry> entries; - - @BeforeEach - public void setup() { - user1 = new User(); - user1.setId(1L); - user1.setRole(Role.USER); - user1.setEmail("test@example.com"); - user1.setFirstName("John"); - user1.setLastName("Doe"); - - user2 = new User(); - user2.setId(2L); - user2.setRole(Role.USER); - user2.setEmail("another@example.com"); - user2.setFirstName("Jane"); - user2.setLastName("Smith"); - - user3 = new User(); - user3.setId(3L); - user3.setRole(Role.USER); - user3.setEmail("someone@example.com"); - user3.setFirstName("Alice"); - user3.setLastName("Johnson"); - - entries = new ArrayList<>(); - entries.add(new LeaderboardEntry(user1, 10, 1)); - entries.add(new LeaderboardEntry(user2, 5, 2)); - entries.add(new LeaderboardEntry(user3, 1, 3)); - - leaderboard = new Leaderboard(); - leaderboard.setEntries(entries); - } - - // GET TOP USERS GLOBAL - @Test - void getTopUsersCurrentStreakGlobal_Success() throws Exception { - leaderboardType = LeaderboardType.CURRENT_STREAK; - leaderboardFilter = LeaderboardFilter.GLOBAL; - leaderboard.setType(leaderboardType); - leaderboard.setFilter(leaderboardFilter); - - when(leaderboardService.getTopUsers(leaderboardType, leaderboardFilter, 3, 1L)).thenReturn(leaderboard); - - mvc.perform(get("/api/leaderboard") - .param("type", "CURRENT_STREAK") - .param("filter", "GLOBAL") - .param("entryCount", "3") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user1)))) - .andExpect(status().isOk()); - } - - - @Test - void getTopUsersTopStreakGlobal_Success() throws Exception { - leaderboardType = LeaderboardType.TOP_STREAK; - leaderboardFilter = LeaderboardFilter.GLOBAL; - leaderboard.setType(leaderboardType); - leaderboard.setFilter(leaderboardFilter); - - when(leaderboardService.getTopUsers(leaderboardType, leaderboardFilter, 3, 1L)).thenReturn(leaderboard); - - mvc.perform(get("/api/leaderboard") - .param("type", "TOP_STREAK") - .param("filter", "GLOBAL") - .param("entryCount", "3") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user1)))) - .andExpect(status().isOk()); - } - - @Test - void getTopUsersTotalPointsGlobal_Success() throws Exception { - leaderboardType = LeaderboardType.TOTAL_POINTS; - leaderboardFilter = LeaderboardFilter.GLOBAL; - leaderboard.setType(leaderboardType); - leaderboard.setFilter(leaderboardFilter); - - when(leaderboardService.getTopUsers(leaderboardType, leaderboardFilter, 3, 1L)).thenReturn(leaderboard); - - mvc.perform(get("/api/leaderboard") - .param("type", "TOTAL_POINTS") - .param("filter", "GLOBAL") - .param("entryCount", "3") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user1)))) - .andExpect(status().isOk()); - } - - // GET TOP USERS FRIENDS - @Test - void getTopUsersCurrentStreakFriends_Success() throws Exception { - leaderboardType = LeaderboardType.CURRENT_STREAK; - leaderboardFilter = LeaderboardFilter.FRIENDS; - leaderboard.setType(leaderboardType); - leaderboard.setFilter(leaderboardFilter); - - when(leaderboardService.getTopUsers(leaderboardType, leaderboardFilter, 3, 1L)).thenReturn(leaderboard); - - mvc.perform(get("/api/leaderboard") - .param("type", "CURRENT_STREAK") - .param("filter", "FRIENDS") - .param("entryCount", "3") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user1)))) - .andExpect(status().isOk()); - } - - @Test - void getTopUsersTopStreakFriends_Success() throws Exception { - leaderboardType = LeaderboardType.TOP_STREAK; - leaderboardFilter = LeaderboardFilter.FRIENDS; - leaderboard.setType(leaderboardType); - leaderboard.setFilter(leaderboardFilter); - - when(leaderboardService.getTopUsers(leaderboardType, leaderboardFilter, 3, 1L)).thenReturn(leaderboard); - - mvc.perform(get("/api/leaderboard") - .param("type", "TOP_STREAK") - .param("filter", "FRIENDS") - .param("entryCount", "3") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user1)))) - .andExpect(status().isOk()); - } - - @Test - void getTopUsersTotalPointsFriends_Success() throws Exception { - leaderboardType = LeaderboardType.TOTAL_POINTS; - leaderboardFilter = LeaderboardFilter.FRIENDS; - leaderboard.setType(leaderboardType); - leaderboard.setFilter(leaderboardFilter); - - when(leaderboardService.getTopUsers(leaderboardType, leaderboardFilter, 3, 1L)).thenReturn(leaderboard); - - mvc.perform(get("/api/leaderboard") - .param("type", "TOTAL_POINTS") - .param("filter", "FRIENDS") - .param("entryCount", "3") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user1)))) - .andExpect(status().isOk()); - } - - //GET SURROUNDING GLOBAL - @Test - void getSurroundingCurrentStreakGlobal_Success() throws Exception { - leaderboardType = LeaderboardType.CURRENT_STREAK; - leaderboardFilter = LeaderboardFilter.GLOBAL; - leaderboard.setType(leaderboardType); - leaderboard.setFilter(leaderboardFilter); - - when(leaderboardService.getSurrounding(leaderboardType, leaderboardFilter, 2, 1L)).thenReturn(leaderboard); - - mvc.perform(get("/api/leaderboard/surrounding") - .param("type", "CURRENT_STREAK") - .param("filter", "GLOBAL") - .param("entryCount", "2") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user1)))) - .andExpect(status().isOk()); - } - - @Test - void getSurroundingTopStreakGlobal_Success() throws Exception { - leaderboardType = LeaderboardType.TOP_STREAK; - leaderboardFilter = LeaderboardFilter.GLOBAL; - leaderboard.setType(leaderboardType); - leaderboard.setFilter(leaderboardFilter); - - when(leaderboardService.getSurrounding(leaderboardType, leaderboardFilter, 2, 1L)).thenReturn(leaderboard); - - mvc.perform(get("/api/leaderboard/surrounding") - .param("type", "TOP_STREAK") - .param("filter", "GLOBAL") - .param("entryCount", "2") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user1)))) - .andExpect(status().isOk()); - } - - @Test - void getSurroundingTotalPointsGlobal_Success() throws Exception { - leaderboardType = LeaderboardType.TOTAL_POINTS; - leaderboardFilter = LeaderboardFilter.GLOBAL; - leaderboard.setType(leaderboardType); - leaderboard.setFilter(leaderboardFilter); - - when(leaderboardService.getSurrounding(leaderboardType, leaderboardFilter, 2, 1L)).thenReturn(leaderboard); - - mvc.perform(get("/api/leaderboard/surrounding") - .param("type", "TOTAL_POINTS") - .param("filter", "GLOBAL") - .param("entryCount", "2") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user1)))) - .andExpect(status().isOk()); - } - - //GET SURROUNDING FRIENDS - @Test - void getSurroundingCurrentStreakFriends_Success() throws Exception { - leaderboardType = LeaderboardType.CURRENT_STREAK; - leaderboardFilter = LeaderboardFilter.FRIENDS; - leaderboard.setType(leaderboardType); - leaderboard.setFilter(leaderboardFilter); - - when(leaderboardService.getSurrounding(leaderboardType, leaderboardFilter, 2, 1L)).thenReturn(leaderboard); - - mvc.perform(get("/api/leaderboard/surrounding") - .param("type", "CURRENT_STREAK") - .param("filter", "FRIENDS") - .param("entryCount", "2") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user1)))) - .andExpect(status().isOk()); - } - - @Test - void getSurroundingTopStreakFriends_Success() throws Exception { - leaderboardType = LeaderboardType.TOP_STREAK; - leaderboardFilter = LeaderboardFilter.FRIENDS; - leaderboard.setType(leaderboardType); - leaderboard.setFilter(leaderboardFilter); - - when(leaderboardService.getSurrounding(leaderboardType, leaderboardFilter, 2, 1L)).thenReturn(leaderboard); - - mvc.perform(get("/api/leaderboard/surrounding") - .param("type", "TOP_STREAK") - .param("filter", "FRIENDS") - .param("entryCount", "2") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user1)))) - .andExpect(status().isOk()); - } - - @Test - void getSurroundingTotalPointsFriends_Success() throws Exception { - leaderboardType = LeaderboardType.TOTAL_POINTS; - leaderboardFilter = LeaderboardFilter.FRIENDS; - leaderboard.setType(leaderboardType); - leaderboard.setFilter(leaderboardFilter); - - when(leaderboardService.getSurrounding(leaderboardType, leaderboardFilter, 2, 1L)).thenReturn(leaderboard); - - mvc.perform(get("/api/leaderboard/surrounding") - .param("type", "TOTAL_POINTS") - .param("filter", "FRIENDS") - .param("entryCount", "2") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user1)))) - .andExpect(status().isOk()); - } - - @Test + @Autowired + private MockMvc mvc; + + @MockBean + private LeaderboardService leaderboardService; + + @InjectMocks + private LeaderboardController leaderboardController; + + private User user1; + + private User user2; + + private User user3; + + private Leaderboard leaderboard; + + private LeaderboardType leaderboardType; + + private LeaderboardFilter leaderboardFilter; + + private List<LeaderboardEntry> entries; + + @BeforeEach + public void setup() { + user1 = new User(); + user1.setId(1L); + user1.setRole(Role.USER); + user1.setEmail("test@example.com"); + user1.setFirstName("John"); + user1.setLastName("Doe"); + + user2 = new User(); + user2.setId(2L); + user2.setRole(Role.USER); + user2.setEmail("another@example.com"); + user2.setFirstName("Jane"); + user2.setLastName("Smith"); + + user3 = new User(); + user3.setId(3L); + user3.setRole(Role.USER); + user3.setEmail("someone@example.com"); + user3.setFirstName("Alice"); + user3.setLastName("Johnson"); + + entries = new ArrayList<>(); + entries.add(new LeaderboardEntry(user1, 10, 1)); + entries.add(new LeaderboardEntry(user2, 5, 2)); + entries.add(new LeaderboardEntry(user3, 1, 3)); + + leaderboard = new Leaderboard(); + leaderboard.setEntries(entries); + } + + // GET TOP USERS GLOBAL + @Test + void getTopUsersCurrentStreakGlobal_Success() throws Exception { + leaderboardType = LeaderboardType.CURRENT_STREAK; + leaderboardFilter = LeaderboardFilter.GLOBAL; + leaderboard.setType(leaderboardType); + leaderboard.setFilter(leaderboardFilter); + + when(leaderboardService.getTopUsers(leaderboardType, leaderboardFilter, 3, 1L)).thenReturn(leaderboard); + + mvc.perform(get("/api/leaderboard").param("type", "CURRENT_STREAK") + .param("filter", "GLOBAL") + .param("entryCount", "3") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user1)))) + .andExpect(status().isOk()); + } + + @Test + void getTopUsersTopStreakGlobal_Success() throws Exception { + leaderboardType = LeaderboardType.TOP_STREAK; + leaderboardFilter = LeaderboardFilter.GLOBAL; + leaderboard.setType(leaderboardType); + leaderboard.setFilter(leaderboardFilter); + + when(leaderboardService.getTopUsers(leaderboardType, leaderboardFilter, 3, 1L)).thenReturn(leaderboard); + + mvc.perform(get("/api/leaderboard").param("type", "TOP_STREAK") + .param("filter", "GLOBAL") + .param("entryCount", "3") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user1)))) + .andExpect(status().isOk()); + } + + @Test + void getTopUsersTotalPointsGlobal_Success() throws Exception { + leaderboardType = LeaderboardType.TOTAL_POINTS; + leaderboardFilter = LeaderboardFilter.GLOBAL; + leaderboard.setType(leaderboardType); + leaderboard.setFilter(leaderboardFilter); + + when(leaderboardService.getTopUsers(leaderboardType, leaderboardFilter, 3, 1L)).thenReturn(leaderboard); + + mvc.perform(get("/api/leaderboard").param("type", "TOTAL_POINTS") + .param("filter", "GLOBAL") + .param("entryCount", "3") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user1)))) + .andExpect(status().isOk()); + } + + // GET TOP USERS FRIENDS + @Test + void getTopUsersCurrentStreakFriends_Success() throws Exception { + leaderboardType = LeaderboardType.CURRENT_STREAK; + leaderboardFilter = LeaderboardFilter.FRIENDS; + leaderboard.setType(leaderboardType); + leaderboard.setFilter(leaderboardFilter); + + when(leaderboardService.getTopUsers(leaderboardType, leaderboardFilter, 3, 1L)).thenReturn(leaderboard); + + mvc.perform(get("/api/leaderboard").param("type", "CURRENT_STREAK") + .param("filter", "FRIENDS") + .param("entryCount", "3") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user1)))) + .andExpect(status().isOk()); + } + + @Test + void getTopUsersTopStreakFriends_Success() throws Exception { + leaderboardType = LeaderboardType.TOP_STREAK; + leaderboardFilter = LeaderboardFilter.FRIENDS; + leaderboard.setType(leaderboardType); + leaderboard.setFilter(leaderboardFilter); + + when(leaderboardService.getTopUsers(leaderboardType, leaderboardFilter, 3, 1L)).thenReturn(leaderboard); + + mvc.perform(get("/api/leaderboard").param("type", "TOP_STREAK") + .param("filter", "FRIENDS") + .param("entryCount", "3") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user1)))) + .andExpect(status().isOk()); + } + + @Test + void getTopUsersTotalPointsFriends_Success() throws Exception { + leaderboardType = LeaderboardType.TOTAL_POINTS; + leaderboardFilter = LeaderboardFilter.FRIENDS; + leaderboard.setType(leaderboardType); + leaderboard.setFilter(leaderboardFilter); + + when(leaderboardService.getTopUsers(leaderboardType, leaderboardFilter, 3, 1L)).thenReturn(leaderboard); + + mvc.perform(get("/api/leaderboard").param("type", "TOTAL_POINTS") + .param("filter", "FRIENDS") + .param("entryCount", "3") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user1)))) + .andExpect(status().isOk()); + } + + // GET SURROUNDING GLOBAL + @Test + void getSurroundingCurrentStreakGlobal_Success() throws Exception { + leaderboardType = LeaderboardType.CURRENT_STREAK; + leaderboardFilter = LeaderboardFilter.GLOBAL; + leaderboard.setType(leaderboardType); + leaderboard.setFilter(leaderboardFilter); + + when(leaderboardService.getSurrounding(leaderboardType, leaderboardFilter, 2, 1L)).thenReturn(leaderboard); + + mvc.perform(get("/api/leaderboard/surrounding").param("type", "CURRENT_STREAK") + .param("filter", "GLOBAL") + .param("entryCount", "2") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user1)))) + .andExpect(status().isOk()); + } + + @Test + void getSurroundingTopStreakGlobal_Success() throws Exception { + leaderboardType = LeaderboardType.TOP_STREAK; + leaderboardFilter = LeaderboardFilter.GLOBAL; + leaderboard.setType(leaderboardType); + leaderboard.setFilter(leaderboardFilter); + + when(leaderboardService.getSurrounding(leaderboardType, leaderboardFilter, 2, 1L)).thenReturn(leaderboard); + + mvc.perform(get("/api/leaderboard/surrounding").param("type", "TOP_STREAK") + .param("filter", "GLOBAL") + .param("entryCount", "2") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user1)))) + .andExpect(status().isOk()); + } + + @Test + void getSurroundingTotalPointsGlobal_Success() throws Exception { + leaderboardType = LeaderboardType.TOTAL_POINTS; + leaderboardFilter = LeaderboardFilter.GLOBAL; + leaderboard.setType(leaderboardType); + leaderboard.setFilter(leaderboardFilter); + + when(leaderboardService.getSurrounding(leaderboardType, leaderboardFilter, 2, 1L)).thenReturn(leaderboard); + + mvc.perform(get("/api/leaderboard/surrounding").param("type", "TOTAL_POINTS") + .param("filter", "GLOBAL") + .param("entryCount", "2") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user1)))) + .andExpect(status().isOk()); + } + + // GET SURROUNDING FRIENDS + @Test + void getSurroundingCurrentStreakFriends_Success() throws Exception { + leaderboardType = LeaderboardType.CURRENT_STREAK; + leaderboardFilter = LeaderboardFilter.FRIENDS; + leaderboard.setType(leaderboardType); + leaderboard.setFilter(leaderboardFilter); + + when(leaderboardService.getSurrounding(leaderboardType, leaderboardFilter, 2, 1L)).thenReturn(leaderboard); + + mvc.perform(get("/api/leaderboard/surrounding").param("type", "CURRENT_STREAK") + .param("filter", "FRIENDS") + .param("entryCount", "2") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user1)))) + .andExpect(status().isOk()); + } + + @Test + void getSurroundingTopStreakFriends_Success() throws Exception { + leaderboardType = LeaderboardType.TOP_STREAK; + leaderboardFilter = LeaderboardFilter.FRIENDS; + leaderboard.setType(leaderboardType); + leaderboard.setFilter(leaderboardFilter); + + when(leaderboardService.getSurrounding(leaderboardType, leaderboardFilter, 2, 1L)).thenReturn(leaderboard); + + mvc.perform(get("/api/leaderboard/surrounding").param("type", "TOP_STREAK") + .param("filter", "FRIENDS") + .param("entryCount", "2") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user1)))) + .andExpect(status().isOk()); + } + + @Test + void getSurroundingTotalPointsFriends_Success() throws Exception { + leaderboardType = LeaderboardType.TOTAL_POINTS; + leaderboardFilter = LeaderboardFilter.FRIENDS; + leaderboard.setType(leaderboardType); + leaderboard.setFilter(leaderboardFilter); + + when(leaderboardService.getSurrounding(leaderboardType, leaderboardFilter, 2, 1L)).thenReturn(leaderboard); + + mvc.perform(get("/api/leaderboard/surrounding").param("type", "TOTAL_POINTS") + .param("filter", "FRIENDS") + .param("entryCount", "2") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user1)))) + .andExpect(status().isOk()); + } + + @Test void getTotalEarnedPointsReturns5000() throws Exception { when(leaderboardService.getSumTotalEarnedPoints()).thenReturn(5000L); @@ -304,4 +295,5 @@ public class LeaderboardControllerTest { .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.content().string("5000")); } + } diff --git a/src/test/java/no/ntnu/idi/stud/savingsapp/controller/notification/NotificationControllerTest.java b/src/test/java/no/ntnu/idi/stud/savingsapp/controller/notification/NotificationControllerTest.java index b502599dad1b1ed109a6f982e8216b4c88e15c30..6a6de78fe9ecf6e6c285b6e58a0e5d5cb47fd95d 100644 --- a/src/test/java/no/ntnu/idi/stud/savingsapp/controller/notification/NotificationControllerTest.java +++ b/src/test/java/no/ntnu/idi/stud/savingsapp/controller/notification/NotificationControllerTest.java @@ -25,69 +25,70 @@ import org.springframework.transaction.annotation.Transactional; @Transactional public class NotificationControllerTest { - @Autowired - private MockMvc mvc; + @Autowired + private MockMvc mvc; - @Autowired - private ObjectMapper objectMapper; + @Autowired + private ObjectMapper objectMapper; - private User user; + private User user; - @BeforeEach - public void setup() { - user = new User(); - user.setId(1L); - user.setRole(Role.USER); - user.setEmail("testuser1@example.com"); - } + @BeforeEach + public void setup() { + user = new User(); + user.setId(1L); + user.setRole(Role.USER); + user.setEmail("testuser1@example.com"); + } - @Test - @WithMockUser - void getNotificationByIDShouldReturnSuccess() throws Exception { - mvc.perform(MockMvcRequestBuilders.get("/api/notification/1") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$.message").value("You have received a new friend request")) - .andExpect(MockMvcResultMatchers.jsonPath("$.notificationType").value("FRIEND_REQUEST")) - .andExpect(MockMvcResultMatchers.jsonPath("$.unread").value(true)); - } + @Test + @WithMockUser + void getNotificationByIDShouldReturnSuccess() throws Exception { + mvc.perform(MockMvcRequestBuilders.get("/api/notification/1") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.message").value("You have received a new friend request")) + .andExpect(MockMvcResultMatchers.jsonPath("$.notificationType").value("FRIEND_REQUEST")) + .andExpect(MockMvcResultMatchers.jsonPath("$.unread").value(true)); + } - @Test - @WithMockUser - void getNotificationsByUserShouldReturnListOf3() throws Exception { - mvc.perform(MockMvcRequestBuilders.get("/api/notification") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(3))); - } + @Test + @WithMockUser + void getNotificationsByUserShouldReturnListOf3() throws Exception { + mvc.perform(MockMvcRequestBuilders.get("/api/notification") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(3))); + } - @Test - @WithMockUser - void getUnreadNotificationsByUserShouldReturnListOf2() throws Exception { - mvc.perform(MockMvcRequestBuilders.get("/api/notification/unread") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(2))); - } + @Test + @WithMockUser + void getUnreadNotificationsByUserShouldReturnListOf2() throws Exception { + mvc.perform(MockMvcRequestBuilders.get("/api/notification/unread") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$", Matchers.hasSize(2))); + } - @Test - @WithMockUser - void updateNotificationsByUserShouldReturnSuccess() throws Exception { - NotificationDTO notificationDTO = new NotificationDTO(); - notificationDTO.setId(1); - notificationDTO.setNotificationType(NotificationType.FRIEND_REQUEST); - notificationDTO.setMessage("You have got a new friend request"); - notificationDTO.setUnread(false); + @Test + @WithMockUser + void updateNotificationsByUserShouldReturnSuccess() throws Exception { + NotificationDTO notificationDTO = new NotificationDTO(); + notificationDTO.setId(1); + notificationDTO.setNotificationType(NotificationType.FRIEND_REQUEST); + notificationDTO.setMessage("You have got a new friend request"); + notificationDTO.setUnread(false); - mvc.perform(MockMvcRequestBuilders.post("/api/notification/update") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user))) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(notificationDTO))) - .andExpect(MockMvcResultMatchers.status().isOk()); + mvc.perform(MockMvcRequestBuilders.post("/api/notification/update") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user))) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(notificationDTO))) + .andExpect(MockMvcResultMatchers.status().isOk()); + + mvc.perform(MockMvcRequestBuilders.get("/api/notification/1") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(MockMvcResultMatchers.status().isOk()) + .andExpect(MockMvcResultMatchers.jsonPath("$.unread").value(false)); + } - mvc.perform(MockMvcRequestBuilders.get("/api/notification/1") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(MockMvcResultMatchers.status().isOk()) - .andExpect(MockMvcResultMatchers.jsonPath("$.unread").value(false)); - } } diff --git a/src/test/java/no/ntnu/idi/stud/savingsapp/controller/user/UserControllerTest.java b/src/test/java/no/ntnu/idi/stud/savingsapp/controller/user/UserControllerTest.java index f8fc59b0717fc84654221d2643b70fee5211699c..38d1637b26215701c1ec5e71f68d2e6aa12e0983 100644 --- a/src/test/java/no/ntnu/idi/stud/savingsapp/controller/user/UserControllerTest.java +++ b/src/test/java/no/ntnu/idi/stud/savingsapp/controller/user/UserControllerTest.java @@ -30,25 +30,25 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @AutoConfigureMockMvc public class UserControllerTest { - @Autowired - private MockMvc mvc; - - @MockBean - private UserService userService; - - private User user; - - @BeforeEach - public void setup() { - user = new User(); - user.setId(1L); - user.setRole(Role.USER); - user.setEmail("test@example.com"); - user.setFirstName("John"); - user.setLastName("Doe"); - } + @Autowired + private MockMvc mvc; + + @MockBean + private UserService userService; + + private User user; + + @BeforeEach + public void setup() { + user = new User(); + user.setId(1L); + user.setRole(Role.USER); + user.setEmail("test@example.com"); + user.setFirstName("John"); + user.setLastName("Doe"); + } - @Test + @Test void getUser_Success() throws Exception { when(userService.findById(user.getId())).thenReturn(user); @@ -57,7 +57,7 @@ public class UserControllerTest { .andExpect(status().isOk()); } - @Test + @Test void getUser_NotFound() throws Exception { when(userService.findById(anyLong())).thenThrow(UserNotFoundException.class); @@ -66,7 +66,7 @@ public class UserControllerTest { .andExpect(status().isNotFound()); } - @Test + @Test void getProfile_Success() throws Exception { when(userService.findById(anyLong())).thenReturn(user); @@ -76,65 +76,60 @@ public class UserControllerTest { .andExpect(status().isOk()); } - @Test - void updateProfile_Success() throws Exception { - UserUpdateDTO updateDTO = new UserUpdateDTO(); - updateDTO.setFirstName("Jane"); - updateDTO.setLastName("Test"); - updateDTO.setEmail("new@email.com"); - - User updatedUser = user; - updatedUser.setFirstName("Jane"); - updatedUser.setLastName("Test"); - updatedUser.setEmail("new@email.com"); - - when(userService.findById(anyLong())).thenReturn(user); - when(userService.update(any(User.class))).thenReturn(updatedUser); + @Test + void updateProfile_Success() throws Exception { + UserUpdateDTO updateDTO = new UserUpdateDTO(); + updateDTO.setFirstName("Jane"); + updateDTO.setLastName("Test"); + updateDTO.setEmail("new@email.com"); + + User updatedUser = user; + updatedUser.setFirstName("Jane"); + updatedUser.setLastName("Test"); + updatedUser.setEmail("new@email.com"); + + when(userService.findById(anyLong())).thenReturn(user); + when(userService.update(any(User.class))).thenReturn(updatedUser); + + mvc.perform(patch("/api/users").contentType(MediaType.APPLICATION_JSON) + .content(JsonUtil.toJson(updateDTO)) + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) + .andExpect(status().isOk()); + } + + @Test + void resetPassword_ValidEmail_ReturnsAccepted() throws Exception { + doNothing().when(userService).initiatePasswordReset("user@example.com"); + + mvc.perform( + post("/api/users/reset-password").contentType(MediaType.TEXT_PLAIN_VALUE).content("user@example.com")) + .andExpect(status().isAccepted()); + } + + @Test + void confirmPassword_ValidToken_ReturnsNoContent() throws Exception { + PasswordResetDTO resetDTO = new PasswordResetDTO(); + resetDTO.setToken("valid-token"); + resetDTO.setPassword("NewPassword123"); + + doNothing().when(userService).confirmPasswordReset(resetDTO.getToken(), resetDTO.getPassword()); + + mvc.perform(post("/api/users/confirm-password").contentType(MediaType.APPLICATION_JSON) + .content(JsonUtil.toJson(resetDTO))).andExpect(status().isNoContent()); + } + + @Test + void updateSubscriptionLevelWillFailIfEnumIsInvalid() throws Exception { + mvc.perform(put("/api/users/subscription/INVALID_ENUM") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user))) + .contentType(MediaType.APPLICATION_JSON)).andExpect(status().isBadRequest()); + } + + @Test + void updateSubscriptionLevelWillWorkIfEnumIsValid() throws Exception { + mvc.perform(put("/api/users/subscription/PREMIUM") + .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user))) + .contentType(MediaType.APPLICATION_JSON)).andExpect(status().isOk()); + } - mvc.perform(patch("/api/users") - .contentType(MediaType.APPLICATION_JSON) - .content(JsonUtil.toJson(updateDTO)) - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user)))) - .andExpect(status().isOk()); - } - - @Test - void resetPassword_ValidEmail_ReturnsAccepted() throws Exception { - doNothing().when(userService).initiatePasswordReset("user@example.com"); - - mvc.perform(post("/api/users/reset-password") - .contentType(MediaType.TEXT_PLAIN_VALUE) - .content("user@example.com")) - .andExpect(status().isAccepted()); - } - - @Test - void confirmPassword_ValidToken_ReturnsNoContent() throws Exception { - PasswordResetDTO resetDTO = new PasswordResetDTO(); - resetDTO.setToken("valid-token"); - resetDTO.setPassword("NewPassword123"); - - doNothing().when(userService).confirmPasswordReset(resetDTO.getToken(), resetDTO.getPassword()); - - mvc.perform(post("/api/users/confirm-password") - .contentType(MediaType.APPLICATION_JSON) - .content(JsonUtil.toJson(resetDTO))) - .andExpect(status().isNoContent()); - } - - @Test - void updateSubscriptionLevelWillFailIfEnumIsInvalid() throws Exception { - mvc.perform(put("/api/users/subscription/INVALID_ENUM") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user))) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isBadRequest()); - } - - @Test - void updateSubscriptionLevelWillWorkIfEnumIsValid() throws Exception { - mvc.perform(put("/api/users/subscription/PREMIUM") - .with(SecurityMockMvcRequestPostProcessors.authentication(UserUtil.getAuthentication(user))) - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(status().isOk()); - } } diff --git a/src/test/java/no/ntnu/idi/stud/savingsapp/repository/BudgetRepositoryTest.java b/src/test/java/no/ntnu/idi/stud/savingsapp/repository/BudgetRepositoryTest.java index 0f2d4b063e09ad11f2cd5cb17623785c4fc87af9..47234df8b36a12c3efb897b4eddf51680fb13315 100644 --- a/src/test/java/no/ntnu/idi/stud/savingsapp/repository/BudgetRepositoryTest.java +++ b/src/test/java/no/ntnu/idi/stud/savingsapp/repository/BudgetRepositoryTest.java @@ -21,83 +21,82 @@ import static org.assertj.core.api.Assertions.assertThat; @TestPropertySource(locations = "classpath:application-h2.yml") public class BudgetRepositoryTest { - @Autowired - private TestEntityManager entityManager; - - @Autowired - private BudgetRepository budgetRepository; - - private Budget expectedBudget; - - private Budget expectedBudget2; - - private User user; - - @BeforeEach - void init() { - - user = new User(); - user.setFirstName("User"); - user.setLastName("User"); - user.setEmail("user@example.com"); - user.setPassword("SomeEncryptedPassword1"); - user.setCreatedAt(new Timestamp(System.currentTimeMillis())); - user.setRole(Role.USER); - - expectedBudget = new Budget(); - expectedBudget.setBudgetName("TestBudget1"); - expectedBudget.setUser(user); - expectedBudget.setBudgetAmount(new BigDecimal(1000)); - expectedBudget.setExpenseAmount(new BigDecimal(200)); - expectedBudget.setCreatedAt(new Timestamp(System.currentTimeMillis())); - - expectedBudget2 = new Budget(); - expectedBudget2.setBudgetName("TestBudget2"); - expectedBudget2.setUser(user); - expectedBudget2.setBudgetAmount(new BigDecimal(50)); - expectedBudget2.setExpenseAmount(new BigDecimal(10)); - expectedBudget2.setCreatedAt(new Timestamp(System.currentTimeMillis())); - - // Persist all users - entityManager.persist(user); - entityManager.persist(expectedBudget); - entityManager.persist(expectedBudget2); - - entityManager.flush(); - } - - @AfterEach - void tearDown() { - entityManager.clear(); - } - - @Test - void shouldGetBudgetById() { - Optional<Budget> budgetResult = budgetRepository.findBudgetById(expectedBudget.getId()); - assertThat(budgetResult.isPresent()); - assertThat(budgetResult.get().getBudgetAmount()).isSameAs(expectedBudget.getBudgetAmount()); - assertThat(budgetResult.get().getBudgetName()).isEqualTo(expectedBudget.getBudgetName()); - assertThat(budgetResult.get().getUser()).isSameAs(expectedBudget.getUser()); - assertThat(budgetResult.get().getExpenseAmount()).isSameAs(expectedBudget.getExpenseAmount()); - assertThat(budgetResult.get().getCreatedAt()).isSameAs(expectedBudget.getCreatedAt()); - assertThat(budgetResult.get().getId()).isEqualTo(expectedBudget.getId()); - } - - @Test - void shouldDeleteBudgetById() { - budgetRepository.deleteBudgetById(expectedBudget.getId()); - assertThat(budgetRepository.findBudgetById(expectedBudget.getId())).isEmpty(); - } - - @Test - void shouldGetAllBudgetsByUserId() { - - - - List<Budget> budgetList = budgetRepository.findBudgetsByUserId(user.getId()); - - assertThat(budgetList).hasSize(2); - assertThat(budgetList.get(0).getBudgetName()).isEqualTo(expectedBudget.getBudgetName()); - assertThat(budgetList.get(1).getBudgetName()).isEqualTo(expectedBudget2.getBudgetName()); - } + @Autowired + private TestEntityManager entityManager; + + @Autowired + private BudgetRepository budgetRepository; + + private Budget expectedBudget; + + private Budget expectedBudget2; + + private User user; + + @BeforeEach + void init() { + + user = new User(); + user.setFirstName("User"); + user.setLastName("User"); + user.setEmail("user@example.com"); + user.setPassword("SomeEncryptedPassword1"); + user.setCreatedAt(new Timestamp(System.currentTimeMillis())); + user.setRole(Role.USER); + + expectedBudget = new Budget(); + expectedBudget.setBudgetName("TestBudget1"); + expectedBudget.setUser(user); + expectedBudget.setBudgetAmount(new BigDecimal(1000)); + expectedBudget.setExpenseAmount(new BigDecimal(200)); + expectedBudget.setCreatedAt(new Timestamp(System.currentTimeMillis())); + + expectedBudget2 = new Budget(); + expectedBudget2.setBudgetName("TestBudget2"); + expectedBudget2.setUser(user); + expectedBudget2.setBudgetAmount(new BigDecimal(50)); + expectedBudget2.setExpenseAmount(new BigDecimal(10)); + expectedBudget2.setCreatedAt(new Timestamp(System.currentTimeMillis())); + + // Persist all users + entityManager.persist(user); + entityManager.persist(expectedBudget); + entityManager.persist(expectedBudget2); + + entityManager.flush(); + } + + @AfterEach + void tearDown() { + entityManager.clear(); + } + + @Test + void shouldGetBudgetById() { + Optional<Budget> budgetResult = budgetRepository.findBudgetById(expectedBudget.getId()); + assertThat(budgetResult.isPresent()); + assertThat(budgetResult.get().getBudgetAmount()).isSameAs(expectedBudget.getBudgetAmount()); + assertThat(budgetResult.get().getBudgetName()).isEqualTo(expectedBudget.getBudgetName()); + assertThat(budgetResult.get().getUser()).isSameAs(expectedBudget.getUser()); + assertThat(budgetResult.get().getExpenseAmount()).isSameAs(expectedBudget.getExpenseAmount()); + assertThat(budgetResult.get().getCreatedAt()).isSameAs(expectedBudget.getCreatedAt()); + assertThat(budgetResult.get().getId()).isEqualTo(expectedBudget.getId()); + } + + @Test + void shouldDeleteBudgetById() { + budgetRepository.deleteBudgetById(expectedBudget.getId()); + assertThat(budgetRepository.findBudgetById(expectedBudget.getId())).isEmpty(); + } + + @Test + void shouldGetAllBudgetsByUserId() { + + List<Budget> budgetList = budgetRepository.findBudgetsByUserId(user.getId()); + + assertThat(budgetList).hasSize(2); + assertThat(budgetList.get(0).getBudgetName()).isEqualTo(expectedBudget.getBudgetName()); + assertThat(budgetList.get(1).getBudgetName()).isEqualTo(expectedBudget2.getBudgetName()); + } + } diff --git a/src/test/java/no/ntnu/idi/stud/savingsapp/repository/FriendRepositoryTest.java b/src/test/java/no/ntnu/idi/stud/savingsapp/repository/FriendRepositoryTest.java index 149e1a69521eb4a60046ebd1750ddba245969bb0..ca6379e37db0f1793e17774d22ad3f547cc3f9dc 100644 --- a/src/test/java/no/ntnu/idi/stud/savingsapp/repository/FriendRepositoryTest.java +++ b/src/test/java/no/ntnu/idi/stud/savingsapp/repository/FriendRepositoryTest.java @@ -19,91 +19,95 @@ import static org.assertj.core.api.Assertions.assertThat; @DataJpaTest @TestPropertySource(locations = "classpath:application-h2.yml") public class FriendRepositoryTest { - @Autowired - private TestEntityManager entityManager; - - @Autowired - private FriendRepository friendRepository; - - private User user1; - private User user2; - private User user3; - - @BeforeEach - void init() { - user1 = new User(); - user1.setFirstName("User"); - user1.setLastName("User"); - user1.setEmail("user@example.com"); - user1.setPassword("SomeEncryptedPassword1"); - user1.setCreatedAt(new Timestamp(System.currentTimeMillis())); - user1.setRole(Role.USER); - - user2 = new User(); - user2.setFirstName("User2"); - user2.setLastName("Five"); - user2.setEmail("user5@example.com"); - user2.setPassword("SomeEncryptedPassword2"); - user2.setCreatedAt(new Timestamp(System.currentTimeMillis())); - user2.setRole(Role.USER); - - user3 = new User(); - user3.setFirstName("User3"); - user3.setLastName("Three"); - user3.setEmail("user3@example.com"); - user3.setPassword("SomeEncryptedPassword3"); - user3.setCreatedAt(new Timestamp(System.currentTimeMillis())); - user3.setRole(Role.USER); - - // Persist all users - entityManager.persist(user1); - entityManager.persist(user2); - entityManager.persist(user3); - - // user1 is friends with user2 - Friend friend12 = new Friend(new FriendId(user1, user2), false, new Timestamp(System.currentTimeMillis())); - // user1 has sent a friend request to user3 - Friend friend13 = new Friend(new FriendId(user1, user3), true, new Timestamp(System.currentTimeMillis())); - - entityManager.persist(friend12); - entityManager.persist(friend13); - entityManager.flush(); - } - - @AfterEach - void tearDown() { - entityManager.clear(); - } - - @Test - @DisplayName("Test testGetFriends") - public void testGetFriends() { - List<Friend> friends = friendRepository.findAllById_UserOrId_FriendAndPendingFalse(user1.getId()); - assertThat(friends).hasSize(1); - assertThat(friends.get(0).getId().getUser().getId()).isEqualTo(user1.getId()); - assertThat(!friends.get(0).isPending()); - assertThat(friends.get(0).getId().getFriend().getId()).isEqualTo(user2.getId()); - } - - @Test - @DisplayName("Test testGetFriendRequests") - public void testGetFriendRequests() { - List<Friend> friends = friendRepository.findAllById_FriendAndPendingTrue(user3.getId()); - assertThat(friends).hasSize(1); - assertThat(friends.get(0).getId().getUser().getId()).isEqualTo(user1.getId()); - assertThat(friends.get(0).isPending()); - assertThat(friends.get(0).getId().getFriend().getId()).isEqualTo(user3.getId()); - } - - @Test - @DisplayName("Test acceptFriendRequest") - public void testAcceptFriendRequest() { - FriendId friendId = new FriendId(user1, user3); - friendRepository.acceptFriendRequest(friendId); - - List<Friend> friends = friendRepository.findAllById_UserOrId_FriendAndPendingFalse(user1.getId()); - assertThat(friends).hasSize(2); - assertThat(!friends.get(0).isPending()); - assertThat(!friends.get(1).isPending()); - } + + @Autowired + private TestEntityManager entityManager; + + @Autowired + private FriendRepository friendRepository; + + private User user1; + + private User user2; + + private User user3; + + @BeforeEach + void init() { + user1 = new User(); + user1.setFirstName("User"); + user1.setLastName("User"); + user1.setEmail("user@example.com"); + user1.setPassword("SomeEncryptedPassword1"); + user1.setCreatedAt(new Timestamp(System.currentTimeMillis())); + user1.setRole(Role.USER); + + user2 = new User(); + user2.setFirstName("User2"); + user2.setLastName("Five"); + user2.setEmail("user5@example.com"); + user2.setPassword("SomeEncryptedPassword2"); + user2.setCreatedAt(new Timestamp(System.currentTimeMillis())); + user2.setRole(Role.USER); + + user3 = new User(); + user3.setFirstName("User3"); + user3.setLastName("Three"); + user3.setEmail("user3@example.com"); + user3.setPassword("SomeEncryptedPassword3"); + user3.setCreatedAt(new Timestamp(System.currentTimeMillis())); + user3.setRole(Role.USER); + + // Persist all users + entityManager.persist(user1); + entityManager.persist(user2); + entityManager.persist(user3); + + // user1 is friends with user2 + Friend friend12 = new Friend(new FriendId(user1, user2), false, new Timestamp(System.currentTimeMillis())); + // user1 has sent a friend request to user3 + Friend friend13 = new Friend(new FriendId(user1, user3), true, new Timestamp(System.currentTimeMillis())); + + entityManager.persist(friend12); + entityManager.persist(friend13); + entityManager.flush(); + } + + @AfterEach + void tearDown() { + entityManager.clear(); + } + + @Test + @DisplayName("Test testGetFriends") + public void testGetFriends() { + List<Friend> friends = friendRepository.findAllById_UserOrId_FriendAndPendingFalse(user1.getId()); + assertThat(friends).hasSize(1); + assertThat(friends.get(0).getId().getUser().getId()).isEqualTo(user1.getId()); + assertThat(!friends.get(0).isPending()); + assertThat(friends.get(0).getId().getFriend().getId()).isEqualTo(user2.getId()); + } + + @Test + @DisplayName("Test testGetFriendRequests") + public void testGetFriendRequests() { + List<Friend> friends = friendRepository.findAllById_FriendAndPendingTrue(user3.getId()); + assertThat(friends).hasSize(1); + assertThat(friends.get(0).getId().getUser().getId()).isEqualTo(user1.getId()); + assertThat(friends.get(0).isPending()); + assertThat(friends.get(0).getId().getFriend().getId()).isEqualTo(user3.getId()); + } + + @Test + @DisplayName("Test acceptFriendRequest") + public void testAcceptFriendRequest() { + FriendId friendId = new FriendId(user1, user3); + friendRepository.acceptFriendRequest(friendId); + + List<Friend> friends = friendRepository.findAllById_UserOrId_FriendAndPendingFalse(user1.getId()); + assertThat(friends).hasSize(2); + assertThat(!friends.get(0).isPending()); + assertThat(!friends.get(1).isPending()); + } + } diff --git a/src/test/java/no/ntnu/idi/stud/savingsapp/service/BudgetServiceTest.java b/src/test/java/no/ntnu/idi/stud/savingsapp/service/BudgetServiceTest.java index 631c270893d29aeac276b168b33303d0906f22dc..b23213d3b7f7fa7863dec96f42900671e175021d 100644 --- a/src/test/java/no/ntnu/idi/stud/savingsapp/service/BudgetServiceTest.java +++ b/src/test/java/no/ntnu/idi/stud/savingsapp/service/BudgetServiceTest.java @@ -20,47 +20,47 @@ import org.springframework.transaction.annotation.Transactional; @SpringBootTest public class BudgetServiceTest { - @Autowired - private BudgetServiceImpl budgetService; + @Autowired + private BudgetServiceImpl budgetService; - private User user; + private User user; - private Budget expectedBudget; + private Budget expectedBudget; - private Budget expectedBudget2; + private Budget expectedBudget2; - @BeforeEach - void init() { + @BeforeEach + void init() { - user = new User(); - user.setFirstName("User"); - user.setLastName("User"); - user.setEmail("user@example.com"); - user.setPassword("SomeEncryptedPassword1"); - user.setCreatedAt(new Timestamp(System.currentTimeMillis())); - user.setRole(Role.USER); + user = new User(); + user.setFirstName("User"); + user.setLastName("User"); + user.setEmail("user@example.com"); + user.setPassword("SomeEncryptedPassword1"); + user.setCreatedAt(new Timestamp(System.currentTimeMillis())); + user.setRole(Role.USER); - expectedBudget = new Budget(); - expectedBudget.setBudgetName("TestBudget1"); - expectedBudget.setUser(user); - expectedBudget.setBudgetAmount(new BigDecimal(1000)); - expectedBudget.setExpenseAmount(new BigDecimal(200)); - expectedBudget.setCreatedAt(new Timestamp(System.currentTimeMillis())); + expectedBudget = new Budget(); + expectedBudget.setBudgetName("TestBudget1"); + expectedBudget.setUser(user); + expectedBudget.setBudgetAmount(new BigDecimal(1000)); + expectedBudget.setExpenseAmount(new BigDecimal(200)); + expectedBudget.setCreatedAt(new Timestamp(System.currentTimeMillis())); - expectedBudget2 = new Budget(); - expectedBudget2.setBudgetName("TestBudget2"); - expectedBudget2.setUser(user); - expectedBudget2.setBudgetAmount(new BigDecimal(50)); - expectedBudget2.setExpenseAmount(new BigDecimal(10)); - expectedBudget2.setCreatedAt(new Timestamp(System.currentTimeMillis())); - } + expectedBudget2 = new Budget(); + expectedBudget2.setBudgetName("TestBudget2"); + expectedBudget2.setUser(user); + expectedBudget2.setBudgetAmount(new BigDecimal(50)); + expectedBudget2.setExpenseAmount(new BigDecimal(10)); + expectedBudget2.setCreatedAt(new Timestamp(System.currentTimeMillis())); + } - @Test - void shouldCreateBudget() { - Budget createdBudget = budgetService.createBudget(expectedBudget2); + @Test + void shouldCreateBudget() { + Budget createdBudget = budgetService.createBudget(expectedBudget2); - assertThat(createdBudget).isNotNull(); - assertThat(createdBudget.getBudgetName()).isEqualTo(expectedBudget2.getBudgetName()); - } + assertThat(createdBudget).isNotNull(); + assertThat(createdBudget.getBudgetName()).isEqualTo(expectedBudget2.getBudgetName()); + } } diff --git a/src/test/java/no/ntnu/idi/stud/savingsapp/service/FriendServiceTest.java b/src/test/java/no/ntnu/idi/stud/savingsapp/service/FriendServiceTest.java index d91308bb65caeef3504fbf8aceda332e191001f4..39bd9b8b2542fb473e40d86a3503533565bdaf48 100644 --- a/src/test/java/no/ntnu/idi/stud/savingsapp/service/FriendServiceTest.java +++ b/src/test/java/no/ntnu/idi/stud/savingsapp/service/FriendServiceTest.java @@ -25,31 +25,35 @@ import org.springframework.transaction.annotation.Transactional; @AutoConfigureMockMvc @Transactional public class FriendServiceTest { - @Mock - private FriendRepository friendRepository; - @InjectMocks - private FriendServiceImpl friendService; + @Mock + private FriendRepository friendRepository; - private User user; - private User friend; - private Friend friendEntity; - private FriendId friendId; + @InjectMocks + private FriendServiceImpl friendService; - @BeforeEach - public void setUp() { - MockitoAnnotations.openMocks(this); + private User user; - user = new User(); - friend = new User(); - user.setId(1L); - friend.setId(2L); + private User friend; - friendId = new FriendId(user, friend); - friendEntity = new Friend(friendId, false, null); - } + private Friend friendEntity; + + private FriendId friendId; + + @BeforeEach + public void setUp() { + MockitoAnnotations.openMocks(this); - @Test + user = new User(); + friend = new User(); + user.setId(1L); + friend.setId(2L); + + friendId = new FriendId(user, friend); + friendEntity = new Friend(friendId, false, null); + } + + @Test public void testGetFriends() { when(friendRepository.findAllById_UserOrId_FriendAndPendingFalse(user.getId())).thenReturn(Arrays.asList(friendEntity)); List<Friend> result = friendService.getFriends(user.getId()); @@ -57,4 +61,5 @@ public class FriendServiceTest { assertEquals(1, result.size()); assertEquals(friendEntity, result.get(0)); } + } diff --git a/src/test/java/no/ntnu/idi/stud/savingsapp/service/LeaderboardServiceTest.java b/src/test/java/no/ntnu/idi/stud/savingsapp/service/LeaderboardServiceTest.java index 85fa50d54d49246e10d93b749382298a32b8a6ab..48870ef84d7f5b095014973e483f65484cc8e4d3 100644 --- a/src/test/java/no/ntnu/idi/stud/savingsapp/service/LeaderboardServiceTest.java +++ b/src/test/java/no/ntnu/idi/stud/savingsapp/service/LeaderboardServiceTest.java @@ -16,127 +16,123 @@ import static org.assertj.core.api.Assertions.assertThat; @TestPropertySource(locations = "classpath:application-h2.yml") public class LeaderboardServiceTest { - @Autowired - private LeaderboardServiceImpl leaderboardService; - - // Top leaderboard - @Test - void shouldGetTopGlobalUsersFiltredByTotalPoints() { - Leaderboard leaderboard = leaderboardService.getTopUsers(LeaderboardType.TOTAL_POINTS, - LeaderboardFilter.GLOBAL, 3, - 1L); - - assertThat(leaderboard.getEntries()).hasSize(3); - assertThat(leaderboard.getType()).isEqualTo(LeaderboardType.TOTAL_POINTS); - assertThat(leaderboard.getEntries().get(0).getScore()).isEqualTo(1050); - } - - @Test - void shouldGetTopGlobalUsersFiltredByCurrentStreak() { - Leaderboard leaderboard = leaderboardService.getTopUsers(LeaderboardType.CURRENT_STREAK, - LeaderboardFilter.GLOBAL, 3, 1L); - - assertThat(leaderboard.getEntries()).hasSize(3); - assertThat(leaderboard.getType()).isEqualTo(LeaderboardType.CURRENT_STREAK); - assertThat(leaderboard.getEntries().get(0).getScore()).isEqualTo(12); - } - - @Test - void shouldGetTopGlobalUsersFiltredByTopStreak() { - Leaderboard leaderboard = leaderboardService.getTopUsers(LeaderboardType.TOP_STREAK, - LeaderboardFilter.GLOBAL, 3, 1L); - - assertThat(leaderboard.getEntries()).hasSize(3); - assertThat(leaderboard.getType()).isEqualTo(LeaderboardType.TOP_STREAK); - assertThat(leaderboard.getEntries().get(0).getScore()).isEqualTo(20); - } - - @Test - void shouldGetTopFriendsUsersFiltredByTotalPoints() { - Leaderboard leaderboard = leaderboardService.getTopUsers(LeaderboardType.TOTAL_POINTS, - LeaderboardFilter.FRIENDS, 3, - 1L); - - assertThat(leaderboard.getEntries()).hasSize(3); - assertThat(leaderboard.getType()).isEqualTo(LeaderboardType.TOTAL_POINTS); - assertThat(leaderboard.getEntries().get(0).getScore()).isEqualTo(1000); - } - - @Test - void shouldGetTopFriendsUsersFiltredByCurrentStreak() { - Leaderboard leaderboard = leaderboardService.getTopUsers(LeaderboardType.CURRENT_STREAK, - LeaderboardFilter.FRIENDS, 3, 1L); - - assertThat(leaderboard.getEntries()).hasSize(3); - assertThat(leaderboard.getType()).isEqualTo(LeaderboardType.CURRENT_STREAK); - assertThat(leaderboard.getEntries().get(0).getScore()).isEqualTo(10); - } - - @Test - void shouldGetTopFriendsUsersFiltredByTopStreak() { - Leaderboard leaderboard = leaderboardService.getTopUsers(LeaderboardType.TOP_STREAK, - LeaderboardFilter.FRIENDS, 3, 1L); - - assertThat(leaderboard.getEntries()).hasSize(3); - assertThat(leaderboard.getType()).isEqualTo(LeaderboardType.TOP_STREAK); - assertThat(leaderboard.getEntries().get(0).getScore()).isEqualTo(15); - } - - // Surrounding leaderboard - @Test - void shouldGetSurroundingGlobalUsersFiltredByTotalPoints() { - Leaderboard leaderboard = leaderboardService.getSurrounding(LeaderboardType.TOTAL_POINTS, - LeaderboardFilter.GLOBAL, 3, - 1L); - - assertThat(leaderboard.getEntries()).hasSize(5); - assertThat(leaderboard.getType()).isEqualTo(LeaderboardType.TOTAL_POINTS); - } - - @Test - void shouldGetSurroundingGlobalUsersFiltredByCurrentStreak() { - Leaderboard leaderboard = leaderboardService.getSurrounding(LeaderboardType.CURRENT_STREAK, - LeaderboardFilter.GLOBAL, 3, 1L); - - assertThat(leaderboard.getEntries()).hasSize(8); - assertThat(leaderboard.getType()).isEqualTo(LeaderboardType.CURRENT_STREAK); - } - - @Test - void shouldGetSurroundingGlobalUsersFiltredByTopStreak() { - Leaderboard leaderboard = leaderboardService.getSurrounding(LeaderboardType.TOP_STREAK, - LeaderboardFilter.GLOBAL, 3, 1L); - - assertThat(leaderboard.getEntries()).hasSize(5); - assertThat(leaderboard.getType()).isEqualTo(LeaderboardType.TOP_STREAK); - } - - @Test - void shouldGetSurroundingFriendsUsersFiltredByTotalPoints() { - Leaderboard leaderboard = leaderboardService.getSurrounding(LeaderboardType.TOTAL_POINTS, - LeaderboardFilter.FRIENDS, 3, - 1L); - - assertThat(leaderboard.getEntries()).hasSize(3); - assertThat(leaderboard.getType()).isEqualTo(LeaderboardType.TOTAL_POINTS); - } - - @Test - void shouldGetSurroundingFriendsUsersFiltredByCurrentStreak() { - Leaderboard leaderboard = leaderboardService.getSurrounding(LeaderboardType.CURRENT_STREAK, - LeaderboardFilter.FRIENDS, 3, 1L); - - assertThat(leaderboard.getEntries()).hasSize(3); - assertThat(leaderboard.getType()).isEqualTo(LeaderboardType.CURRENT_STREAK); - } - - @Test - void shouldGetSurroundingFriendsUsersFiltredByTopStreak() { - Leaderboard leaderboard = leaderboardService.getSurrounding(LeaderboardType.TOP_STREAK, - LeaderboardFilter.FRIENDS, 3, 1L); - - assertThat(leaderboard.getEntries()).hasSize(3); - assertThat(leaderboard.getType()).isEqualTo(LeaderboardType.TOP_STREAK); - } + @Autowired + private LeaderboardServiceImpl leaderboardService; + + // Top leaderboard + @Test + void shouldGetTopGlobalUsersFiltredByTotalPoints() { + Leaderboard leaderboard = leaderboardService.getTopUsers(LeaderboardType.TOTAL_POINTS, LeaderboardFilter.GLOBAL, + 3, 1L); + + assertThat(leaderboard.getEntries()).hasSize(3); + assertThat(leaderboard.getType()).isEqualTo(LeaderboardType.TOTAL_POINTS); + assertThat(leaderboard.getEntries().get(0).getScore()).isEqualTo(1050); + } + + @Test + void shouldGetTopGlobalUsersFiltredByCurrentStreak() { + Leaderboard leaderboard = leaderboardService.getTopUsers(LeaderboardType.CURRENT_STREAK, + LeaderboardFilter.GLOBAL, 3, 1L); + + assertThat(leaderboard.getEntries()).hasSize(3); + assertThat(leaderboard.getType()).isEqualTo(LeaderboardType.CURRENT_STREAK); + assertThat(leaderboard.getEntries().get(0).getScore()).isEqualTo(12); + } + + @Test + void shouldGetTopGlobalUsersFiltredByTopStreak() { + Leaderboard leaderboard = leaderboardService.getTopUsers(LeaderboardType.TOP_STREAK, LeaderboardFilter.GLOBAL, + 3, 1L); + + assertThat(leaderboard.getEntries()).hasSize(3); + assertThat(leaderboard.getType()).isEqualTo(LeaderboardType.TOP_STREAK); + assertThat(leaderboard.getEntries().get(0).getScore()).isEqualTo(20); + } + + @Test + void shouldGetTopFriendsUsersFiltredByTotalPoints() { + Leaderboard leaderboard = leaderboardService.getTopUsers(LeaderboardType.TOTAL_POINTS, + LeaderboardFilter.FRIENDS, 3, 1L); + + assertThat(leaderboard.getEntries()).hasSize(3); + assertThat(leaderboard.getType()).isEqualTo(LeaderboardType.TOTAL_POINTS); + assertThat(leaderboard.getEntries().get(0).getScore()).isEqualTo(1000); + } + + @Test + void shouldGetTopFriendsUsersFiltredByCurrentStreak() { + Leaderboard leaderboard = leaderboardService.getTopUsers(LeaderboardType.CURRENT_STREAK, + LeaderboardFilter.FRIENDS, 3, 1L); + + assertThat(leaderboard.getEntries()).hasSize(3); + assertThat(leaderboard.getType()).isEqualTo(LeaderboardType.CURRENT_STREAK); + assertThat(leaderboard.getEntries().get(0).getScore()).isEqualTo(10); + } + + @Test + void shouldGetTopFriendsUsersFiltredByTopStreak() { + Leaderboard leaderboard = leaderboardService.getTopUsers(LeaderboardType.TOP_STREAK, LeaderboardFilter.FRIENDS, + 3, 1L); + + assertThat(leaderboard.getEntries()).hasSize(3); + assertThat(leaderboard.getType()).isEqualTo(LeaderboardType.TOP_STREAK); + assertThat(leaderboard.getEntries().get(0).getScore()).isEqualTo(15); + } + + // Surrounding leaderboard + @Test + void shouldGetSurroundingGlobalUsersFiltredByTotalPoints() { + Leaderboard leaderboard = leaderboardService.getSurrounding(LeaderboardType.TOTAL_POINTS, + LeaderboardFilter.GLOBAL, 3, 1L); + + assertThat(leaderboard.getEntries()).hasSize(5); + assertThat(leaderboard.getType()).isEqualTo(LeaderboardType.TOTAL_POINTS); + } + + @Test + void shouldGetSurroundingGlobalUsersFiltredByCurrentStreak() { + Leaderboard leaderboard = leaderboardService.getSurrounding(LeaderboardType.CURRENT_STREAK, + LeaderboardFilter.GLOBAL, 3, 1L); + + assertThat(leaderboard.getEntries()).hasSize(8); + assertThat(leaderboard.getType()).isEqualTo(LeaderboardType.CURRENT_STREAK); + } + + @Test + void shouldGetSurroundingGlobalUsersFiltredByTopStreak() { + Leaderboard leaderboard = leaderboardService.getSurrounding(LeaderboardType.TOP_STREAK, + LeaderboardFilter.GLOBAL, 3, 1L); + + assertThat(leaderboard.getEntries()).hasSize(5); + assertThat(leaderboard.getType()).isEqualTo(LeaderboardType.TOP_STREAK); + } + + @Test + void shouldGetSurroundingFriendsUsersFiltredByTotalPoints() { + Leaderboard leaderboard = leaderboardService.getSurrounding(LeaderboardType.TOTAL_POINTS, + LeaderboardFilter.FRIENDS, 3, 1L); + + assertThat(leaderboard.getEntries()).hasSize(3); + assertThat(leaderboard.getType()).isEqualTo(LeaderboardType.TOTAL_POINTS); + } + + @Test + void shouldGetSurroundingFriendsUsersFiltredByCurrentStreak() { + Leaderboard leaderboard = leaderboardService.getSurrounding(LeaderboardType.CURRENT_STREAK, + LeaderboardFilter.FRIENDS, 3, 1L); + + assertThat(leaderboard.getEntries()).hasSize(3); + assertThat(leaderboard.getType()).isEqualTo(LeaderboardType.CURRENT_STREAK); + } + + @Test + void shouldGetSurroundingFriendsUsersFiltredByTopStreak() { + Leaderboard leaderboard = leaderboardService.getSurrounding(LeaderboardType.TOP_STREAK, + LeaderboardFilter.FRIENDS, 3, 1L); + + assertThat(leaderboard.getEntries()).hasSize(3); + assertThat(leaderboard.getType()).isEqualTo(LeaderboardType.TOP_STREAK); + } }