diff --git a/pom.xml b/pom.xml index 8774713..38cdf57 100644 --- a/pom.xml +++ b/pom.xml @@ -10,7 +10,7 @@ nl.andrewl coyotecredit - 1.2.0 + 1.3.0 coyotecredit Banking and stock trading application to teach students. diff --git a/src/main/java/nl/andrewl/coyotecredit/ctl/dto/FullAccountData.java b/src/main/java/nl/andrewl/coyotecredit/ctl/dto/FullAccountData.java index df65b31..37ce7cb 100644 --- a/src/main/java/nl/andrewl/coyotecredit/ctl/dto/FullAccountData.java +++ b/src/main/java/nl/andrewl/coyotecredit/ctl/dto/FullAccountData.java @@ -12,6 +12,8 @@ public record FullAccountData ( String number, String name, boolean admin, + long userId, + String username, boolean userAdmin,// If the current user is an admin of the exchange this account is in. boolean userIsOwner,// If the current user is the owner of this account. ExchangeData exchange, diff --git a/src/main/java/nl/andrewl/coyotecredit/ctl/exchange/ExchangeController.java b/src/main/java/nl/andrewl/coyotecredit/ctl/exchange/ExchangeController.java index a491221..10f10cb 100644 --- a/src/main/java/nl/andrewl/coyotecredit/ctl/exchange/ExchangeController.java +++ b/src/main/java/nl/andrewl/coyotecredit/ctl/exchange/ExchangeController.java @@ -1,6 +1,7 @@ package nl.andrewl.coyotecredit.ctl.exchange; import lombok.RequiredArgsConstructor; +import nl.andrewl.coyotecredit.ctl.exchange.dto.AddAccountPayload; import nl.andrewl.coyotecredit.ctl.exchange.dto.AddSupportedTradeablePayload; import nl.andrewl.coyotecredit.ctl.exchange.dto.EditExchangePayload; import nl.andrewl.coyotecredit.ctl.exchange.dto.InviteUserPayload; @@ -66,6 +67,18 @@ public class ExchangeController { return "redirect:/users/" + user.getId(); } + @GetMapping(path = "/{exchangeId}/createAccount") + public String getCreateAccountPage(@PathVariable long exchangeId, @AuthenticationPrincipal User user) { + exchangeService.ensureAdminAccount(exchangeId, user); + return "exchange/create_account"; + } + + @PostMapping(path = "/{exchangeId}/createAccount") + public String postCreateAccount(@PathVariable long exchangeId, @AuthenticationPrincipal User user, @ModelAttribute AddAccountPayload payload) { + exchangeService.addAccount(exchangeId, user, payload); + return "redirect:/exchanges/" + exchangeId + "/accounts"; + } + @GetMapping(path = "/{exchangeId}/removeAccount/{accountId}") public String getRemoveAccountPage(@PathVariable long exchangeId, @PathVariable long accountId, @AuthenticationPrincipal User user) { exchangeService.ensureAdminAccount(exchangeId, user); diff --git a/src/main/java/nl/andrewl/coyotecredit/ctl/exchange/dto/AddAccountPayload.java b/src/main/java/nl/andrewl/coyotecredit/ctl/exchange/dto/AddAccountPayload.java new file mode 100644 index 0000000..e898c46 --- /dev/null +++ b/src/main/java/nl/andrewl/coyotecredit/ctl/exchange/dto/AddAccountPayload.java @@ -0,0 +1,8 @@ +package nl.andrewl.coyotecredit.ctl.exchange.dto; + +public record AddAccountPayload( + String username, + String password, + String email, + String accountName +) {} diff --git a/src/main/java/nl/andrewl/coyotecredit/dao/UserRepository.java b/src/main/java/nl/andrewl/coyotecredit/dao/UserRepository.java index 0ebe683..4869d0c 100644 --- a/src/main/java/nl/andrewl/coyotecredit/dao/UserRepository.java +++ b/src/main/java/nl/andrewl/coyotecredit/dao/UserRepository.java @@ -12,4 +12,5 @@ public interface UserRepository extends JpaRepository { boolean existsByUsername(String username); Optional findByEmail(String email); + boolean existsByEmail(String email); } diff --git a/src/main/java/nl/andrewl/coyotecredit/model/Account.java b/src/main/java/nl/andrewl/coyotecredit/model/Account.java index d193895..84b21b1 100644 --- a/src/main/java/nl/andrewl/coyotecredit/model/Account.java +++ b/src/main/java/nl/andrewl/coyotecredit/model/Account.java @@ -3,6 +3,7 @@ package nl.andrewl.coyotecredit.model; import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; +import lombok.Setter; import javax.persistence.*; import java.math.BigDecimal; @@ -53,7 +54,7 @@ public class Account { * Administrators have special permissions to add and remove other accounts, * custom tradeables, exchange rates, and more. */ - @Column(nullable = false) + @Column(nullable = false) @Setter private boolean admin; /** diff --git a/src/main/java/nl/andrewl/coyotecredit/service/AccountService.java b/src/main/java/nl/andrewl/coyotecredit/service/AccountService.java index 75f9660..b39fec6 100644 --- a/src/main/java/nl/andrewl/coyotecredit/service/AccountService.java +++ b/src/main/java/nl/andrewl/coyotecredit/service/AccountService.java @@ -115,23 +115,6 @@ public class AccountService { notificationRepository.save(new UserNotification(recipient.getUser(), recipientMessage)); } - public static record AccountData ( - long id, - String accountNumber, - String exchangeName - ) {} - - @Transactional(readOnly = true) - public List getAccountsOverview(User user) { - return accountRepository.findAllByUser(user).stream() - .map(a -> new AccountData( - a.getId(), - a.getNumber(), - a.getExchange().getName() - )) - .toList(); - } - @Transactional(readOnly = true) public FullAccountData getAccountData(User user, long accountId) { Account account = accountRepository.findById(accountId) @@ -149,6 +132,8 @@ public class AccountService { account.getNumber(), account.getName(), account.isAdmin(), + account.getUser().getId(), + account.getUser().getUsername(), userAccount.isAdmin(), account.getUser().getId().equals(user.getId()), new ExchangeData( diff --git a/src/main/java/nl/andrewl/coyotecredit/service/ExchangeService.java b/src/main/java/nl/andrewl/coyotecredit/service/ExchangeService.java index 1597a92..fbd4225 100644 --- a/src/main/java/nl/andrewl/coyotecredit/service/ExchangeService.java +++ b/src/main/java/nl/andrewl/coyotecredit/service/ExchangeService.java @@ -13,6 +13,7 @@ import org.springframework.data.domain.Pageable; import org.springframework.http.HttpStatus; import org.springframework.mail.javamail.JavaMailSender; import org.springframework.mail.javamail.MimeMessageHelper; +import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.server.ResponseStatusException; @@ -41,6 +42,7 @@ public class ExchangeService { private final ExchangeInvitationRepository invitationRepository; private final UserNotificationRepository notificationRepository; private final JavaMailSender mailSender; + private final PasswordEncoder passwordEncoder; @Value("${coyote-credit.base-url}") private String baseUrl; @@ -117,6 +119,23 @@ public class ExchangeService { return exchange; } + @Transactional + public void addAccount(long exchangeId, User user, AddAccountPayload payload) { + Exchange exchange = getExchangeIfAdmin(exchangeId, user); + if (userRepository.existsByUsername(payload.username())) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Username is taken."); + } + if (userRepository.existsByEmail(payload.email())) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "There is already an account with that email."); + } + User newUser = userRepository.save(new User(payload.username(), passwordEncoder.encode(payload.password()), payload.email())); + Account account = accountRepository.save(new Account(AccountNumberUtils.generate(), newUser, payload.accountName(), exchange)); + for (var t : exchange.getAllTradeables()) { + account.getBalances().add(new Balance(account, t, BigDecimal.ZERO)); + } + accountRepository.save(account); + } + @Transactional public void removeAccount(long exchangeId, long accountId, User user) { Exchange exchange = exchangeRepository.findById(exchangeId) diff --git a/src/main/java/nl/andrewl/coyotecredit/service/UserService.java b/src/main/java/nl/andrewl/coyotecredit/service/UserService.java index 6e05891..f754bdf 100644 --- a/src/main/java/nl/andrewl/coyotecredit/service/UserService.java +++ b/src/main/java/nl/andrewl/coyotecredit/service/UserService.java @@ -67,6 +67,9 @@ public class UserService { if (userRepository.existsByUsername(payload.username())) { throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "Username is already taken."); } + if (userRepository.existsByEmail(payload.email())) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "There is already an account with that email."); + } User user = new User(payload.username(), passwordEncoder.encode(payload.password()), payload.email()); user = userRepository.save(user); if (payload.inviteCode() != null) { diff --git a/src/main/resources/templates/account.html b/src/main/resources/templates/account.html index 6c23e5f..bb17e94 100644 --- a/src/main/resources/templates/account.html +++ b/src/main/resources/templates/account.html @@ -25,6 +25,8 @@
 
+
Username
+