Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,17 @@
<artifactId>postgresql</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>

</dependencies>
<dependencyManagement>
<dependencies>
Expand All @@ -72,8 +83,16 @@
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>

</project>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ public AccountDTO depositToAccount(Authentication authentication,

@PostMapping("/withdraw/{id}")
public AccountDTO withdrawFromAccount(Authentication authentication,
@PathVariable("id") Long accountId,
@RequestBody BalanceChangeRequest balanceChangeRequest){
@PathVariable("id") Long accountId,
@RequestBody BalanceChangeRequest balanceChangeRequest){
BankingUserDetails bankingUserDetails = (BankingUserDetails) authentication.getPrincipal();
return accountService.withdrawFromAccount(bankingUserDetails.getId(),accountId, balanceChangeRequest.getAmount());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ public TransferController(TransferService transferService) {

@PostMapping
public void transfer(
Authentication authentication, @RequestBody TransferRequest transferRequest) {
BankingUserDetails bankingUserDetails = (BankingUserDetails) authentication.getPrincipal();
transferService.transfer(bankingUserDetails.getId(), transferRequest);
Authentication authentication, @RequestBody TransferRequest transferRequest) {
BankingUserDetails userDetails = (BankingUserDetails) authentication.getPrincipal();
transferService.transfer(userDetails.getId(), transferRequest);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import javax.validation.Valid;

import com.skypro.simplebanking.service.UserService;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.*;

Expand All @@ -22,8 +23,9 @@ public UserController(UserService userService) {
}

@PostMapping
@PreAuthorize("hasRole('ADMIN')")
public UserDTO createUser(@RequestBody @Valid CreateUserRequest userRequest) {
return userService.createUser(userRequest.getUsername(), userRequest.getPassword());
return userService.createUser(userRequest.getUsername(), userRequest.getPassword(), userRequest.getRole());
}
@GetMapping("/list")
public List<ListUserDTO> getAllUsers(){
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
package com.skypro.simplebanking.dto;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Range;

@NoArgsConstructor
public class BalanceChangeRequest {
@JsonProperty("amount")
private long amount;


public BalanceChangeRequest(long amount) {
this.amount = amount;
}

public long getAmount() {
return amount;
}

public void setAmount(long amount) {
this.amount = amount;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ public BankingUserDetails(long id, String username, String password, boolean isA
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
SimpleGrantedAuthority authority =
isAdmin
? new SimpleGrantedAuthority("ROLE_ADMIN")
: new SimpleGrantedAuthority("ROLE_USER");
isAdmin
? new SimpleGrantedAuthority("ROLE_ADMIN")
: new SimpleGrantedAuthority("ROLE_USER");
return Collections.singleton(authority);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
public class CreateUserRequest {
private String username;
private String password;
private String role;

public String getUsername() {
return username;
Expand All @@ -22,4 +23,12 @@ public String getPassword() {
public void setPassword(String password) {
this.password = password;
}

public String getRole() {
return role;
}

public void setRole(String role) {
this.role = role;
}
}
6 changes: 3 additions & 3 deletions src/main/java/com/skypro/simplebanking/dto/ListUserDTO.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ public List<ListAccountDTO> getAccounts() {

public static ListUserDTO from(User user) {
return new ListUserDTO(
user.getId(),
user.getUsername(),
user.getAccounts().stream().map(ListAccountDTO::from).collect(Collectors.toList()));
user.getId(),
user.getUsername(),
user.getAccounts().stream().map(ListAccountDTO::from).collect(Collectors.toList()));
}
}
16 changes: 16 additions & 0 deletions src/main/java/com/skypro/simplebanking/dto/TransferRequest.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ public class TransferRequest {
private long toAccountId;
private long amount;

public TransferRequest(long fromAccountId, long toAccountId, long amount) {
this.fromAccountId = fromAccountId;
this.toAccountId = toAccountId;
this.amount = amount;
}

public long getToUserId() {
return toUserId;
}
Expand Down Expand Up @@ -37,4 +43,14 @@ public void setFromAccountId(long fromAccountId) {
public void setToAccountId(long toAccountId) {
this.toAccountId = toAccountId;
}

@Override
public String toString() {
return "TransferRequest{" +
"fromAccountId=" + fromAccountId +
", toUserId=" + toUserId +
", toAccountId=" + toAccountId +
", amount=" + amount +
'}';
}
}
8 changes: 4 additions & 4 deletions src/main/java/com/skypro/simplebanking/dto/UserDTO.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ public List<AccountDTO> getAccounts() {

public static UserDTO from(User user) {
return new UserDTO(
user.getId(),
user.getUsername(),
user.getAccounts().stream().map(AccountDTO::from).collect(Collectors.toList()));
user.getId(),
user.getUsername(),
user.getAccounts().stream().map(AccountDTO::from).collect(Collectors.toList()));
}
}
}
2 changes: 1 addition & 1 deletion src/main/java/com/skypro/simplebanking/entity/Account.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,4 @@ public User getUser() {
public void setUser(User user) {
this.user = user;
}
}
}
7 changes: 7 additions & 0 deletions src/main/java/com/skypro/simplebanking/entity/Role.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.skypro.simplebanking.entity;


public enum Role {
ROLE_USER,
ROLE_ADMIN
}
15 changes: 14 additions & 1 deletion src/main/java/com/skypro/simplebanking/entity/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,15 @@ public class User {
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user-generator")
@SequenceGenerator(name = "user-generator", sequenceName = "user_sequence")
private Long id;
@Column(name = "username", unique = true)
private String username;
@Column(name = "password")
private String password;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "user")
private Collection<Account> accounts;
@Column(name = "role")
@Enumerated(EnumType.STRING)
private Role role;

public Long getId() {
return id;
Expand Down Expand Up @@ -48,4 +53,12 @@ public Collection<Account> getAccounts() {
public void setAccounts(Collection<Account> accounts) {
this.accounts = accounts;
}
}

public Role getRole() {
return role;
}

public void setRole(Role role) {
this.role = role;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.skypro.simplebanking.exception;

public class UserNotFoundException extends RuntimeException {
public UserNotFoundException() {
super("User not found");
}

public UserNotFoundException(String message) {
super(message);
}

public UserNotFoundException(String message, Throwable cause) {
super(message, cause);
}
}
89 changes: 69 additions & 20 deletions src/main/java/com/skypro/simplebanking/service/AccountService.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,23 @@
import com.skypro.simplebanking.entity.Account;
import com.skypro.simplebanking.entity.AccountCurrency;
import com.skypro.simplebanking.entity.User;
import com.skypro.simplebanking.exception.AccountNotFoundException;
import com.skypro.simplebanking.exception.InsufficientFundsException;
import com.skypro.simplebanking.exception.InvalidAmountException;
import com.skypro.simplebanking.exception.WrongCurrencyException;
import com.skypro.simplebanking.exception.*;
import com.skypro.simplebanking.repository.AccountRepository;
import java.util.ArrayList;

import com.skypro.simplebanking.repository.UserRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class AccountService {
private final AccountRepository accountRepository;
private final UserRepository userRepository;

public AccountService(AccountRepository accountRepository) {
public AccountService(AccountRepository accountRepository, UserRepository userRepository) {
this.accountRepository = accountRepository;
this.userRepository = userRepository;
}

@Transactional(propagation = Propagation.MANDATORY)
Expand All @@ -30,26 +31,23 @@ public void createDefaultAccounts(User user) {
account.setUser(user);
account.setAccountCurrency(currency);
account.setAmount(1L);
user.getAccounts().add(account);
accountRepository.save(account);
}
}

@Transactional(readOnly = true)
public AccountDTO getAccount(long userId, Long accountId) {
return accountRepository
.getAccountByUser_IdAndId(userId, accountId)
.map(AccountDTO::from)
.orElseThrow(AccountNotFoundException::new);
.getAccountByUser_IdAndId(userId, accountId)
.map(AccountDTO::from)
.orElseThrow(AccountNotFoundException::new);
}

@Transactional
public void validateCurrency(long sourceAccount, long destinationAccount) {
Account acc1 =
accountRepository.findById(sourceAccount).orElseThrow(AccountNotFoundException::new);
Account acc2 =
accountRepository.findById(destinationAccount).orElseThrow(AccountNotFoundException::new);
if (!acc1.getAccountCurrency().equals(acc2.getAccountCurrency())){
Account acc1 = accountRepository.findById(sourceAccount).orElseThrow(AccountNotFoundException::new);
Account acc2 = accountRepository.findById(destinationAccount).orElseThrow(AccountNotFoundException::new);
if (!acc1.getAccountCurrency().equals(acc2.getAccountCurrency())) {
throw new WrongCurrencyException();
}
}
Expand All @@ -59,8 +57,7 @@ public AccountDTO depositToAccount(long userId, Long accountId, long amount) {
if (amount < 0) {
throw new InvalidAmountException();
}
Account account =
accountRepository
Account account = accountRepository
.getAccountByUser_IdAndId(userId, accountId)
.orElseThrow(AccountNotFoundException::new);
account.setAmount(account.getAmount() + amount);
Expand All @@ -72,15 +69,67 @@ public AccountDTO withdrawFromAccount(long id, Long accountId, long amount) {
if (amount < 0) {
throw new InvalidAmountException();
}
Account account =
accountRepository
Account account = accountRepository
.getAccountByUser_IdAndId(id, accountId)
.orElseThrow(AccountNotFoundException::new);
if (account.getAmount() < amount) {
throw new InsufficientFundsException(
"Cannot withdraw " + amount + " " + account.getAccountCurrency().name());
throw new InsufficientFundsException("Cannot withdraw " + amount + " " + account.getAccountCurrency().name());
}
account.setAmount(account.getAmount() - amount);
return AccountDTO.from(account);
}

@Transactional
public void transferBetweenAccounts(long userId, Long sourceAccountId, Long destinationAccountId, long amount) {
if (amount < 0) {
throw new InvalidAmountException();
}
Account sourceAccount = getAccountByUserIdAndAccountId(userId, sourceAccountId);
Account destinationAccount = getAccountByAccountId(destinationAccountId);

if (!sourceAccount.getAccountCurrency().equals(destinationAccount.getAccountCurrency())) {
throw new WrongCurrencyException();
}

if (sourceAccount.getAmount() < amount) {
throw new InsufficientFundsException("Cannot transfer " + amount + " " + sourceAccount.getAccountCurrency().name() + " from account " + sourceAccountId);
}

sourceAccount.setAmount(sourceAccount.getAmount() - amount);
destinationAccount.setAmount(destinationAccount.getAmount() + amount);
}

@Transactional
public AccountDTO createAccount(Long userId, long initialBalance) {
Account account = new Account();
account.setUser(userRepository.findById(userId).orElseThrow(UserNotFoundException::new));
account.setAmount(initialBalance);
account.setAccountCurrency(AccountCurrency.USD);
Account saved = accountRepository.save(account);
return AccountDTO.from(saved);
}

@Transactional
public void changeAccountCurrency(Long accountId, AccountCurrency newCurrency) {
Account account = accountRepository.findById(accountId).orElseThrow(AccountNotFoundException::new);
account.setAccountCurrency(newCurrency);
}
private Account getAccountByUserIdAndAccountId(long userId, Long accountId) {
return accountRepository.getAccountByUser_IdAndId(userId, accountId).orElseThrow(AccountNotFoundException::new);
}

private Account getAccountByAccountId(Long accountId) {
return accountRepository.findById(accountId).orElseThrow(AccountNotFoundException::new);
}
@Transactional
public AccountDTO createTestAccount(Long userId, long initialBalance, Long accountId) {
Account account = new Account();
account.setId(accountId);
account.setUser(userRepository.findById(userId).orElseThrow(UserNotFoundException::new));
account.setAmount(initialBalance);
account.setAccountCurrency(AccountCurrency.USD);
Account saved = accountRepository.save(account);
return AccountDTO.from(saved);
}

}
Loading