Skip to content
Snippets Groups Projects
Commit cf3be58d authored by xsedlac9's avatar xsedlac9
Browse files

init

parent 95451004
No related branches found
No related tags found
No related merge requests found
Showing
with 250 additions and 225 deletions
CREATE SCHEMA IF NOT EXISTS bank_user;
CREATE USER "ACC_USER" WITH PASSWORD 'userAccPasswd';
ALTER ROLE "ACC_USER" SET SEARCH_PATH TO bank_user;
GRANT ALL PRIVILEGES ON SCHEMA bank_user TO "ACC_USER";
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA bank_user TO "ACC_USER";
CREATE SCHEMA IF NOT EXISTS bank_account;
CREATE USER "ACC_ACCOUNT" WITH PASSWORD 'accountAccPasswd';
ALTER ROLE "ACC_ACCOUNT" SET SEARCH_PATH TO bank_account;
GRANT ALL PRIVILEGES ON SCHEMA bank_account TO "ACC_ACCOUNT";
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA bank_account TO "ACC_ACCOUNT";
CREATE SCHEMA IF NOT EXISTS bank_transaction;
CREATE USER "ACC_TRANSACTION" WITH PASSWORD 'transactionAccPasswd';
......
......@@ -3,24 +3,12 @@ SET SEARCH_PATH TO bank_account;
-- CREATE TABLES
CREATE TABLE IF NOT EXISTS bal_transaction
CREATE TABLE IF NOT EXISTS accounts
(
amount NUMERIC(38, 2),
type SMALLINT,
date TIMESTAMP(6) WITH TIME ZONE,
id BIGINT PRIMARY KEY,
process_id UUID,
balance_id CHARACTER VARYING(255)
);
CREATE TABLE IF NOT EXISTS balance
(
amount NUMERIC(38, 2),
balance_id CHARACTER VARYING(255) PRIMARY KEY
);
CREATE SEQUENCE bal_transaction_seq START WITH 1 INCREMENT BY 50;
ALTER TABLE bal_transaction ADD CONSTRAINT CONSTRAINT_FF CHECK(TYPE BETWEEN 0 AND 4);
ALTER TABLE bal_transaction ADD CONSTRAINT CONSTRAINT_F CHECK(TYPE BETWEEN 0 AND 4);
ALTER TABLE bal_transaction ADD CONSTRAINT FKICJDGHKQ3OQKDCDC6KKUJD6O3 FOREIGN KEY(BALANCE_ID) REFERENCES balance(BALANCE_ID);
\ No newline at end of file
id DECIMAL PRIMARY KEY,
number VARCHAR(50),
user_id DECIMAL,
max_spending_limit DECIMAL,
type VARCHAR(50),
currency VARCHAR(50)
);
SET ROLE "ACC_SCHEDULED_PAYMENTS";
SET SEARCH_PATH TO scheduled_payment;
-- CREATE TABLES
CREATE TABLE IF NOT EXISTS scheduled_payments
(
id DECIMAL PRIMARY KEY,
sender_account_id DECIMAL,
receiver_account_id DECIMAL,
amount DECIMAL
);
......@@ -2,3 +2,13 @@ SET ROLE "ACC_USER";
SET SEARCH_PATH TO bank_user;
-- CREATE TABLES
CREATE TABLE IF NOT EXISTS users
(
id DECIMAL PRIMARY KEY,
email VARCHAR(50),
password VARCHAR(50),
first_name VARCHAR(50),
last_name VARCHAR(50),
user_type VARCHAR(50)
);
SET SEARCH_PATH TO bank_account;
-- INSERT starting data
INSERT INTO balance VALUES
(90.00, 'id1'),
(118.00, 'id2'),
(243.00, 'id3'),
(-243.00, 'id4');
INSERT INTO bal_transaction VALUES
(90.00, 1, TIMESTAMP WITH TIME ZONE '2024-04-15 14:11:00.288446+02', 1, UUID 'b775b79f-52a9-45c4-8ab3-bdb9f0f3d4ae', 'id1'),
(94.00, 2, TIMESTAMP WITH TIME ZONE '2024-04-15 14:11:42.919109+02', 2, UUID 'c91b6ef6-32ac-4160-bf7f-97979ca84606', 'id2'),
(24.00, 1, TIMESTAMP WITH TIME ZONE '2024-04-15 14:11:57.480291+02', 3, UUID '6a1fa40e-3ba8-46a8-b005-8bcd63ae44de', 'id2'),
(243.00, 3, TIMESTAMP WITH TIME ZONE '2024-04-15 14:12:14.949613+02', 4, UUID 'd9974137-7000-4f34-8c64-1d35b0534e31', 'id3'),
(-243.00, 3, TIMESTAMP WITH TIME ZONE '2024-04-15 14:12:23.109443+02', 5, UUID 'd9974137-7000-4f34-8c64-1d35b0534e31', 'id4');
\ No newline at end of file
INSERT INTO accounts (acc_id, acc_number, user_id, max_spending_limit, acc_type)
VALUES
(1, '111111111', 1, 5000.00, 'SPENDING'),
(2, '222222222', 1, 10000.00, 'SAVING'),
(3, '333333333', 2, 2000.00, 'CREDIT'),
(4, '444444444', 5, 7000.00, 'SPENDING'),
(5, '555555555', 5, 15000.00, 'SAVING'),
(6, '666666666', 6, 3000.00, 'CREDIT'),
(7, '777777777', 3, 13000.00, 'CREDIT'),
(8, '888888888', 7, 20000.00, 'CREDIT'),
(9, '999999999', 8, 1000.00, 'CREDIT');
SET SEARCH_PATH TO scheduled_payment;
-- INSERT starting data
INSERT INTO scheduled_payments (id, sender_account_id, receiver_account_id, amount)
VALUES
(1, 8, 9, 100.00),
(2, 8, 3, 100.00),
(3, 5, 6, 500.00),
(4, 2, 1, 200.00),
(5, 2, 5, 150.00);
SET SEARCH_PATH TO bank_user;
-- INSERT starting data
\ No newline at end of file
-- INSERT starting data
INSERT INTO users (user_id, email, password, first_name, last_name, user_type)
VALUES
(1, 'regular1@example.com', 'password1', 'John', 'Doe', 'REGULAR'),
(2, 'regular2@example.com', 'password2', 'Jane', 'Smith', 'REGULAR'),
(3, 'employee1@example.com', 'password3', 'David', 'Johnson', 'EMPLOYEE'),
(4, 'employee2@example.com', 'password4', 'Emily', 'Brown', 'EMPLOYEE', '{}'),
(5, 'regular3@example.com', 'password5', 'Michael', 'Williams', 'REGULAR'),
(6, 'regular4@example.com', 'password6', 'Emma', 'Wilson', 'REGULAR'),
(7, 'employee3@example.com', 'password7', 'Daniel', 'Martinez', 'EMPLOYEE'),
(8, 'employee4@example.com', 'password8', 'Olivia', 'Garcia', 'EMPLOYEE');
FROM eclipse-temurin:21.0.2_13-jdk-alpine
WORKDIR /app
COPY target/*.jar /account-management.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "-Ddb.hostname=banking-db", "/account-management.jar"]
......@@ -20,71 +20,18 @@
<maven.compiler.target>21</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<account-management-api.version>1.0-SNAPSHOT</account-management-api.version>
<!-- External project artifact versions -->
<banking-infrastructure.version>1.0-SNAPSHOT</banking-infrastructure.version>
<spring.version>3.2.4</spring.version>
<org.mapstruct.version>1.5.5.Final</org.mapstruct.version>
<swagger-ui.version>2.3.0</swagger-ui.version>
<jdbc-postgres.version>42.7.3</jdbc-postgres.version>
</properties>
<dependencies>
<dependency>
<groupId>cz.muni.pa165.banking</groupId>
<artifactId>account-management-api</artifactId>
<version>${account-management-api.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>${swagger-ui.version}</version>
</dependency>
</dependencies>
<build>
<finalName>server_generated</finalName>
<plugins>
<!-- Copy OpenApi resources -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>${maven-dependency-plugin.version}</version>
<executions>
<execution>
<id>unpack</id>
<phase>validate</phase>
<goals>
<goal>unpack-dependencies</goal>
</goals>
<configuration>
<includeArtifactIds>account-management-api</includeArtifactIds>
<includes>**/openapi.yaml</includes>
<outputDirectory>${project.build.directory}/account-management-api</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
......@@ -96,7 +43,7 @@
<goal>generate</goal>
</goals>
<configuration>
<inputSpec>${project.build.directory}/account-management-api/openapi.yaml</inputSpec>
<inputSpec>${project.basedir}/src/main/resources/openapi.yaml</inputSpec>
<generatorName>spring</generatorName>
<apiPackage>cz.muni.pa165.banking.account.management</apiPackage>
<modelPackage>cz.muni.pa165.banking.account.management.dto</modelPackage>
......@@ -113,7 +60,11 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-maven-plugin</artifactId>
<version>1.4</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
......@@ -134,7 +85,76 @@
</compilerArgs>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
</configuration>
</plugin>
<!-- run integration tests in "mvn verify" phase -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>cz.muni.pa165.banking</groupId>
<artifactId>infrastructure</artifactId>
<version>${banking-infrastructure.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- DB -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>${jdbc-postgres.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>org.openapitools</groupId>
<artifactId>jackson-databind-nullable</artifactId>
<version>0.2.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>6.1.5</version>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package cz.muni.pa165.banking.application.configuration;
import cz.muni.pa165.banking.exception.CustomExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@Component
public class BeanRegistry {
@Bean
public CustomExceptionHandler exceptionHandler() {
return new CustomExceptionHandler();
}
}
package cz.muni.pa165.banking.application.api;
package cz.muni.pa165.banking.application.controller;
import cz.muni.pa165.banking.account.management.AccountApi;
import cz.muni.pa165.banking.account.management.dto.*;
......@@ -22,13 +22,27 @@ public class AccountController implements AccountApi {
}
@Override
public ResponseEntity<AccountDto> getAccount(String accountNumber) {
return ResponseEntity.ok(accountFacade.getAccount(accountNumber));
public ResponseEntity<AccountDto> findAccountById (Long accountId) {
AccountDto account;
try{
account = accountFacade.findById(accountId);
}
catch (Exception e){
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
return ResponseEntity.ok(account);
}
@Override
public ResponseEntity<ScheduledPaymentsDto> getScheduledPayments(String accountNumber) {
return ResponseEntity.ok(accountFacade.getScheduledPaymentsOfAccount(accountNumber));
ScheduledPaymentsDto payments;
try{
payments = accountFacade.findScheduledPaymentsByNumber(accountNumber);
}
catch (Exception e){
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
return ResponseEntity.ok(payments);
}
@Override
......
package cz.muni.pa165.banking.application.api;
package cz.muni.pa165.banking.application.controller;
import cz.muni.pa165.banking.account.management.UserApi;
import cz.muni.pa165.banking.account.management.dto.NewUserDto;
......@@ -23,8 +23,15 @@ public class UserController implements UserApi{
}
@Override
public ResponseEntity<UserDto> getUser(Long userId) {
return ResponseEntity.ok(userFacade.getUser(userId));
public ResponseEntity<UserDto> findUserById(Long userId) {
UserDto user;
try{
user = userFacade.findById(userId);
}
catch (Exception e){
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
return ResponseEntity.ok(user);
}
}
......@@ -24,20 +24,17 @@ public class AccountFacade {
return mapper.map(accountService.createAccount(account));
}
public AccountDto getAccount(String accountNumber){
return mapper.map(accountService.getAccountByNumber(accountNumber));
public AccountDto findById(Long accountId) throws Exception{
return mapper.map(accountService.findById(accountId));
}
public ScheduledPaymentDto schedulePayment(ScheduledPaymentDto scheduledPaymentDto){
ScheduledPayment newScheduledPayment = mapper.map(scheduledPaymentDto);
return mapper.map(accountService.schedulePayment(newScheduledPayment));
}
public ScheduledPaymentsDto getScheduledPaymentsOfAccount(String accountNumber){
Account account = accountService.getAccountByNumber(accountNumber);
if (account == null) {
throw new RuntimeException(String.format("Account with account number {%s} not found", accountNumber));
}
return mapper.map(accountService.getScheduledPaymentsOfAccount(account.getId()));
public ScheduledPaymentsDto findScheduledPaymentsByNumber(String accountNumber) throws Exception{
Account account = accountService.findByNumber(accountNumber);
return mapper.map(accountService.findScheduledPaymentsById(account.getId()));
}
}
......@@ -23,8 +23,8 @@ public class UserFacade {
return mapper.map(newUser);
}
public UserDto getUser(Long userId){
return mapper.map(userService.getUser(userId));
public UserDto findById(Long userId) throws Exception{
return mapper.map(userService.findById(userId));
}
}
......@@ -11,7 +11,9 @@ import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.MappingConstants;
import java.util.Currency;
import java.util.List;
import java.util.UUID;
@Mapper(componentModel = MappingConstants.ComponentModel.SPRING, injectionStrategy = InjectionStrategy.CONSTRUCTOR)
public interface DtoMapper {
......@@ -32,13 +34,27 @@ public interface DtoMapper {
AccountType map(AccountTypeDto accountTypeDto);
@Mapping(target = "id", ignore = true)
@Mapping(target = "scheduledPayments", ignore = true)
@Mapping(target = "accountNumber", ignore = true)
Account map(NewAccountDto newAccountDto);
default Account map(NewAccountDto newAccountDto){
Account account = new Account();
account.setId(Math.abs(UUID.randomUUID().getMostSignificantBits()));
account.setAccountNumber(UUID.randomUUID().toString());
account.setUserId(newAccountDto.getUserId());
account.setMaxSpendingLimit(newAccountDto.getMaxSpendingLimit());
account.setType(map(newAccountDto.getType()));
account.setCurrency(Currency.getInstance(newAccountDto.getCurrency()));
return account;
}
@Mapping(target = "id", ignore = true)
User map(NewUserDto newUserDto);
default User map(NewUserDto newUserDto){
User user = new User();
user.setId(Math.abs(UUID.randomUUID().getMostSignificantBits()));
user.setEmail(newUserDto.getEmail());
user.setPassword(newUserDto.getPassword());
user.setFirstName(newUserDto.getFirstName());
user.setLastName(newUserDto.getLastName());
user.setUserType(map(newUserDto.getUserType()));
return user;
}
default ScheduledPaymentsDto map(List<ScheduledPayment> scheduledPayments){
ScheduledPaymentsDto result = new ScheduledPaymentsDto();
......@@ -50,9 +66,11 @@ public interface DtoMapper {
default Account map(AccountDto accountDto){
Account account = new Account();
account.setId(accountDto.getId());
account.setAccountNumber(UUID.randomUUID().toString());
account.setUserId(accountDto.getUserId());
account.setMaxSpendingLimit(accountDto.getMaxSpendingLimit());
account.setType(map(accountDto.getType()));
account.setCurrency(Currency.getInstance(accountDto.getCurrency()));
return account;
}
......@@ -62,6 +80,7 @@ public interface DtoMapper {
accountDto.setUserId(account.getUserId());
accountDto.setMaxSpendingLimit(account.getMaxSpendingLimit());
accountDto.setType(map(account.getType()));
accountDto.setCurrency(account.getCurrency().getCurrencyCode());
return accountDto;
}
}
package cz.muni.pa165.banking.application.repository;
import cz.muni.pa165.banking.domain.account.Account;
import cz.muni.pa165.banking.domain.account.repository.AccountRepository;
import org.springframework.stereotype.Repository;
import java.util.HashMap;
import java.util.Map;
@Repository
public class AccountRepositoryImpl implements AccountRepository {
private Long sequencer = 1L;
private Map<Long, Account> accounts = new HashMap<>();
@Override
public Account addAccount(Account account) {
account.setId(sequencer);
account.setAccountNumber("CZ00000000000000000000000" + sequencer); // TODO Milestone2 -> generated by DB on create?
accounts.put(sequencer++, account);
return account;
}
@Override
public Account getById(Long id) {
return accounts.get(id);
}
@Override
public Account getByAccountNumber(String accountNumber) {
return accounts.values().stream()
.filter(account -> account.getAccountNumber().equals(accountNumber))
.findFirst()
.orElse(null);
}
}
package cz.muni.pa165.banking.application.repository;
import cz.muni.pa165.banking.domain.scheduled.ScheduledPayment;
import cz.muni.pa165.banking.domain.scheduled.repository.ScheduledPaymentRepository;
import org.springframework.stereotype.Repository;
import java.util.HashMap;
import java.util.Map;
@Repository
public class ScheduledPaymentRepositoryImpl implements ScheduledPaymentRepository {
private Long sequencer = 1L;
private Map<Long, ScheduledPayment> scheduledPayments = new HashMap<>();
@Override
public ScheduledPayment addScheduledPayment(ScheduledPayment scheduledPayment) {
scheduledPayment.setId(sequencer);
scheduledPayments.put(sequencer++, scheduledPayment);
return scheduledPayment;
}
@Override
public ScheduledPayment getById(Long id) {
return scheduledPayments.get(id);
}
@Override
public Map<Long, ScheduledPayment> getAllPayments() {
return scheduledPayments;
}
}
package cz.muni.pa165.banking.application.repository;
import cz.muni.pa165.banking.domain.user.User;
import cz.muni.pa165.banking.domain.user.repository.UserRepository;
import org.springframework.stereotype.Repository;
import java.util.HashMap;
import java.util.Map;
@Repository
public class UserRepositoryImpl implements UserRepository {
private Long sequencer = 1L;
private Map<Long, User> users = new HashMap<>();
public User addUser(User user) {
user.setId(sequencer);
users.put(sequencer++, user);
return user;
}
@Override
public User getById(Long id) {
return users.get(id);
}
}
......@@ -7,6 +7,8 @@ import cz.muni.pa165.banking.domain.scheduled.repository.ScheduledPaymentReposit
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@Service
public class AccountService {
......@@ -24,20 +26,25 @@ public class AccountService {
return accountRepository.addAccount(newAccount);
}
public Account getAccount(Long accountId) {
return accountRepository.getById(accountId);
public Account findById(Long accountId) throws Exception{
return accountRepository.findById(accountId)
.orElseThrow(() -> new Exception("Account with id: " + accountId + " was not found."));
}
public Account getAccountByNumber(String accountNumber) {
return accountRepository.getByAccountNumber(accountNumber);
public Account findByNumber(String accountNumber) throws Exception {
return accountRepository.findByNumber(accountNumber)
.orElseThrow(() -> new Exception("Account with number: " + accountNumber + " was not found."));
}
public ScheduledPayment schedulePayment(ScheduledPayment newScheduledPayment) {
return scheduledPaymentsRepository.addScheduledPayment(newScheduledPayment);
}
public List<ScheduledPayment> getScheduledPaymentsOfAccount(Long accountId) {
Account senderAccount = accountRepository.getById(accountId);
return senderAccount.getScheduledPayments();
public List<ScheduledPayment> findScheduledPaymentsById(Long accountId){
return accountRepository.findScheduledPaymentsById(accountId);
}
public Map<Long, ScheduledPayment> getAllScheduledPayments(){
return scheduledPaymentsRepository.getAllScheduledPayments();
}
}
......@@ -17,7 +17,8 @@ public class UserService {
return userRepository.addUser(user);
}
public User getUser(Long userId){
return userRepository.getById(userId);
public User findById(Long userId) throws Exception{
return userRepository.findById(userId)
.orElseThrow(() -> new Exception("User with id: " + userId + " not found"));
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment