diff --git a/.gitignore b/.gitignore index 343d1cc..d41fd5e 100644 --- a/.gitignore +++ b/.gitignore @@ -27,9 +27,14 @@ bin/ /.nb-gradle/ DataAccess.iml Presentation.iml +Application.iml +target ### VS Code ### .vscode/ ### Mac OS ### .DS_Store + +# Environment +.env diff --git a/Application/pom.xml b/Application/pom.xml index bf8075d..0563460 100644 --- a/Application/pom.xml +++ b/Application/pom.xml @@ -8,6 +8,12 @@ Application 1.0-SNAPSHOT + + com.example + lim0sha + 1.0-SNAPSHOT + + 17 17 diff --git a/Application/src/main/java/Application/Managers/IUserManager.java b/Application/src/main/java/Application/Managers/IUserManager.java new file mode 100644 index 0000000..12f95a3 --- /dev/null +++ b/Application/src/main/java/Application/Managers/IUserManager.java @@ -0,0 +1,15 @@ +package Application.Managers; + +import Application.Models.Entities.BankAccount; +import Application.Models.Entities.User; + +public interface IUserManager { + + void AddFriend(User user, User other); + + void RemoveFriend(User user, User other); + + void AddBankAccount(User user, BankAccount bankAccount); + + void RemoveBankAccount(User user, BankAccount bankAccount); +} diff --git a/Application/src/main/java/Application/Managers/UserManager.java b/Application/src/main/java/Application/Managers/UserManager.java index ec4f438..61318fd 100644 --- a/Application/src/main/java/Application/Managers/UserManager.java +++ b/Application/src/main/java/Application/Managers/UserManager.java @@ -1,134 +1,28 @@ package Application.Managers; -import Application.ResultTypes.OperationResult; import Application.Models.Entities.BankAccount; -import Application.Models.Entities.Operation; import Application.Models.Entities.User; +import org.springframework.stereotype.Component; -import java.util.ArrayList; -import java.util.List; +@Component +public class UserManager implements IUserManager { -/** - * Класс-менеджер для управления данными пользователей, их банковскими счетами и друзьями. - * Предоставляет методы для получения информации о пользователе, добавления/удаления друзей, - * управления банковскими счетами и вывода истории операций. - */ -public class UserManager { - - /** - * Выводит информацию о пользователе, включая его данные и банковские счета. - * - * @param user объект пользователя, информацию о котором нужно вывести. - */ - public void GetUserInfo(User user) { - - if (user == null) { - System.out.println("Пользователь с ID " + user.getId() + " не найден."); - return; - } - -// // Инициализация ленивых коллекций -// Hibernate.initialize(user.getBankAccounts()); -// Hibernate.initialize(user.getFriends()); - - System.out.println("ID: " + user.getId()); - System.out.println("Логин: " + user.getLogin()); - System.out.println("Имя: " + user.getName()); - System.out.println("Возраст: " + user.getAge()); - System.out.println("Пол: " + user.getSex()); - System.out.println("Цвет волос: " + user.getHairType()); - - // Вывод банковских счетов - System.out.println("\nБанковские счета:"); - if (user.getBankAccounts().isEmpty()) { - System.out.println("Нет привязанных счетов."); - } else { - for (BankAccount account : user.getBankAccounts()) { - System.out.println("ID счета: " + account.getId() + ", Баланс: " + account.getBalance()); - } - } - - // Вывод друзей - System.out.println("\nДрузья:"); - if (user.getFriends().isEmpty()) { - System.out.println("Нет друзей."); - } else { - for (User friend : user.getFriends()) { - System.out.println("ID друга: " + friend.getId() + ", Имя: " + friend.getName()); - } - } - } - - /** - * Добавляет друга пользователю и другому пользователю. - * - * @param user текущий пользователь, добавляющий друга. - * @param other пользователь, который будет добавлен в друзья. - */ public void AddFriend(User user, User other) { user.getFriends().add(other); other.getFriends().add(user); } - /** - * Удаляет друга у пользователя и другого пользователя. - * - * @param user текущий пользователь, у которого будет удален друг. - * @param other пользователь, который будет удален из друзей. - */ public void RemoveFriend(User user, User other) { user.getFriends().remove(other); other.getFriends().remove(user); } - /** - * Добавляет банковский счет пользователю. - * - * @param user пользователь, которому добавляется банковский счет. - * @param bankAccount банковский счет для добавления. - */ public void AddBankAccount(User user, BankAccount bankAccount) { user.getBankAccounts().add(bankAccount); + bankAccount.setUser(user); } - /** - * Удаляет банковский счет у пользователя. - * - * @param user пользователь, у которого будет удален банковский счет. - * @param bankAccount банковский счет для удаления. - */ public void RemoveBankAccount(User user, BankAccount bankAccount) { user.getBankAccounts().remove(bankAccount.getId()); } - - /** - * Проверяет баланс банковского счета пользователя. - * - * @param user пользователь, чей баланс проверяется. - * @param bankAccount банковский счет для проверки баланса. - */ - public void CheckBalance(User user, BankAccount bankAccount) { - System.out.println("User: " + user.getId()); - System.out.println("BankAccount: " + bankAccount.getId()); - System.out.println("Balance: " + bankAccount.getBalance()); - } - - /** - * Выводит историю операций по банковскому счету. - * - * @param account банковский счет, для которого нужно вывести историю. - * @param operations список операций, связанных с этим счетом. - * @return результат операции (успех или ошибка). - */ - public OperationResult PrintHistory(BankAccount account, List operations) { - if (operations == null) { - return new OperationResult.OperationError("Operations can not be null."); - } else { - System.out.println("Account Id: " + account.getId()); - for (Operation operation : operations) { - System.out.println("Operation: " + operation.getType() + "Amount: " + operation.getAmount()); - } - return new OperationResult.Success(); - } - } } diff --git a/Application/src/main/java/Application/Models/Entities/BankAccount.java b/Application/src/main/java/Application/Models/Entities/BankAccount.java index 7fd15b4..84a2a27 100644 --- a/Application/src/main/java/Application/Models/Entities/BankAccount.java +++ b/Application/src/main/java/Application/Models/Entities/BankAccount.java @@ -3,36 +3,28 @@ import jakarta.persistence.*; import lombok.*; -/** - * Класс, представляющий банковский счет пользователя. - * Хранит информацию о счете, балансе и привязанном пользователе. - */ @Entity -@Table(name = "BankAccounts") @Getter @NoArgsConstructor +@Table(name = "bankaccounts") public class BankAccount { @Id @Setter @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; + @Column(name = "balance", nullable = false) @Setter private Double balance; - @Column(name = "userLogin") + @Column(name = "userlogin", nullable = false) private String userLogin; @ManyToOne - @JoinColumn(name = "userId", nullable = false) + @Setter + @JoinColumn(name = "user_id", nullable = false) private User user; - /** - * Конструктор для создания нового банковского счета. - * Генерирует уникальный идентификатор счета и связывает его с пользователем. - * - * @param user пользователь, к которому будет привязан новый счет. - */ public BankAccount(User user) { this.balance = 0.0; this.userLogin = user.getLogin(); diff --git a/Application/src/main/java/Application/Models/Entities/Operation.java b/Application/src/main/java/Application/Models/Entities/Operation.java index 9a7664e..50aeba4 100644 --- a/Application/src/main/java/Application/Models/Entities/Operation.java +++ b/Application/src/main/java/Application/Models/Entities/Operation.java @@ -4,37 +4,26 @@ import lombok.*; import Application.Models.Enums.OperationType; -/** - * Класс, представляющий операцию с банковским счетом. - * Хранит информацию о типе операции, сумме и счете, на котором она была проведена. - */ @Getter @Setter @NoArgsConstructor @Entity -@Table(name = "Operations") +@Table(name = "operations") public class Operation { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; @ManyToOne - @JoinColumn(name = "accountId", nullable = false) + @JoinColumn(name = "account_id", nullable = false) private BankAccount bankAccount; - @Column(nullable = false) + @Column(name = "amount", nullable = false) private Double amount; - @Column(nullable = false) + @Column(name = "type", nullable = false) private String type; - /** - * Конструктор для создания новой операции. - * - * @param bankAccount банковский счет, на котором выполнена операция. - * @param type тип операции (например, депозит или снятие). - * @param amount сумма, участвующая в операции. - */ public Operation(BankAccount bankAccount, OperationType type, Double amount) { this.bankAccount = bankAccount; this.type = type.toString(); diff --git a/Application/src/main/java/Application/Models/Entities/User.java b/Application/src/main/java/Application/Models/Entities/User.java index dffba50..7d23605 100644 --- a/Application/src/main/java/Application/Models/Entities/User.java +++ b/Application/src/main/java/Application/Models/Entities/User.java @@ -4,66 +4,59 @@ import lombok.*; import Application.Models.Enums.HairColor; import Application.Models.Enums.Sex; + import java.util.*; -/** - * Класс, представляющий пользователя системы. - * Хранит информацию о пользователе, включая личные данные, список банковских счетов и друзей. - */ @Entity @Getter -@Table(name = "Users") @NoArgsConstructor +@Table(name = "users") public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; - @Column(nullable = false, unique = true) + @Column(name = "login", nullable = false, unique = true) private String login; - @Column(nullable = false) + @Column(name = "name", nullable = false) private String name; - @Column(nullable = false) + @Column(name = "age", nullable = false) private Integer age; @Enumerated(EnumType.STRING) + @Column(name = "sex", nullable = false) private Sex sex; @Enumerated(EnumType.STRING) - @Column(name = "hairColor") + @Column(name = "haircolor") private HairColor hairType; - @OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER) - private List bankAccounts; + @OneToMany(mappedBy = "user", cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE} + , orphanRemoval = true, fetch = FetchType.EAGER) + private List bankAccounts = new ArrayList<>(); - @ManyToMany(fetch = FetchType.LAZY) + @ManyToMany(fetch = FetchType.EAGER) @JoinTable( - name = "Friends", - joinColumns = @JoinColumn(name = "userId"), - inverseJoinColumns = @JoinColumn(name = "friendId") + name = "friends", + joinColumns = @JoinColumn(name = "user_id"), + inverseJoinColumns = @JoinColumn(name = "friend_id") ) - private List friends; + private List friends = new ArrayList<>(); - /** - * Конструктор для создания нового пользователя. - * Генерирует уникальный идентификатор для пользователя и инициализирует его данные. - * - * @param login логин пользователя. - * @param name имя пользователя. - * @param age возраст пользователя. - * @param sex пол пользователя. - * @param hairType цвет волос пользователя. - */ public User(String login, String name, Integer age, Sex sex, HairColor hairType) { this.login = login; this.name = name; this.age = age; this.sex = sex; this.hairType = hairType; - this.bankAccounts = new ArrayList<>(); - this.friends = new ArrayList<>(); } -} + public void addBankAccount(BankAccount bankAccount) { + if (!bankAccounts.contains(bankAccount)) { + bankAccounts.add(bankAccount); + bankAccount.setUser(this); + } + } +} diff --git a/Application/src/main/java/Application/Models/Enums/HairColor.java b/Application/src/main/java/Application/Models/Enums/HairColor.java index b1768fb..532ce53 100644 --- a/Application/src/main/java/Application/Models/Enums/HairColor.java +++ b/Application/src/main/java/Application/Models/Enums/HairColor.java @@ -1,8 +1,5 @@ package Application.Models.Enums; -/** - * Перечисление возможных цветов волос пользователя. - */ public enum HairColor { Blond, Ash, diff --git a/Application/src/main/java/Application/Models/Enums/OperationType.java b/Application/src/main/java/Application/Models/Enums/OperationType.java index fba1823..99ef7e2 100644 --- a/Application/src/main/java/Application/Models/Enums/OperationType.java +++ b/Application/src/main/java/Application/Models/Enums/OperationType.java @@ -1,8 +1,5 @@ package Application.Models.Enums; -/** - * Перечисление возможных типов операций с банковским счётом. - */ public enum OperationType { Deposit, Withdraw, diff --git a/Application/src/main/java/Application/Models/Enums/Sex.java b/Application/src/main/java/Application/Models/Enums/Sex.java index 3ab3aac..6ec0f67 100644 --- a/Application/src/main/java/Application/Models/Enums/Sex.java +++ b/Application/src/main/java/Application/Models/Enums/Sex.java @@ -1,8 +1,5 @@ package Application.Models.Enums; -/** - * Перечисление возможных вариантов пола пользователя. - */ public enum Sex { Undefined, Male, diff --git a/Application/src/main/java/Application/ResultTypes/BankAccountResult.java b/Application/src/main/java/Application/ResultTypes/BankAccountResult.java index 321b999..f753677 100644 --- a/Application/src/main/java/Application/ResultTypes/BankAccountResult.java +++ b/Application/src/main/java/Application/ResultTypes/BankAccountResult.java @@ -3,10 +3,6 @@ import lombok.AllArgsConstructor; import lombok.Getter; -/** - * Абстрактный класс, представляющий result-type операций с банковским счетом. - * Включает различные типы результатов, такие как успешное выполнение операции или ошибка при создании, обновлении или удалении банковского счета. - */ public abstract sealed class BankAccountResult permits BankAccountResult.Success, BankAccountResult.BankAccountCreationError, BankAccountResult.BankAccountUpdateError, BankAccountResult.BankAccountDeletionError { diff --git a/Application/src/main/java/Application/ResultTypes/OperationResult.java b/Application/src/main/java/Application/ResultTypes/OperationResult.java index c834d01..e42903d 100644 --- a/Application/src/main/java/Application/ResultTypes/OperationResult.java +++ b/Application/src/main/java/Application/ResultTypes/OperationResult.java @@ -4,10 +4,6 @@ import lombok.Getter; import lombok.NoArgsConstructor; -/** - * Абстрактный класс, представляющий result-type операции с деньгами. - * Включает два типа результатов: успешное выполнение операции и ошибка при выполнении. - */ public abstract sealed class OperationResult permits OperationResult.Success, OperationResult.OperationError { @NoArgsConstructor diff --git a/Application/src/main/java/Application/ResultTypes/UserResult.java b/Application/src/main/java/Application/ResultTypes/UserResult.java index 95355bd..e248208 100644 --- a/Application/src/main/java/Application/ResultTypes/UserResult.java +++ b/Application/src/main/java/Application/ResultTypes/UserResult.java @@ -3,10 +3,6 @@ import lombok.AllArgsConstructor; import lombok.Getter; -/** - * Абстрактный класс, представляющий result-type операций с пользователями. - * Включает различные типы результатов, такие как успешное выполнение операции или ошибка при создании, обновлении или удалении пользователя. - */ public abstract sealed class UserResult permits UserResult.Success, UserResult.UserCreationError, UserResult.UserUpdateError, UserResult.UserDeletionError { diff --git a/DataAccess/pom.xml b/DataAccess/pom.xml index bf37e2d..494103d 100644 --- a/DataAccess/pom.xml +++ b/DataAccess/pom.xml @@ -8,6 +8,12 @@ DataAccess 1.0-SNAPSHOT + + com.example + lim0sha + 1.0-SNAPSHOT + + 17 17 @@ -29,35 +35,6 @@ Application 1.0-SNAPSHOT - - org.hibernate - hibernate-core - 6.4.4.Final - - - - org.hibernate - hibernate-ehcache - 4.3.0.Beta3 - - - - org.postgresql - postgresql - 42.7.2 - - - - net.bytebuddy - byte-buddy - 1.14.7 - - - - org.flywaydb - flyway-core - 9.22.0 - diff --git a/DataAccess/src/main/java/DAO/HibernateBankAccountDAO.java b/DataAccess/src/main/java/DAO/HibernateBankAccountDAO.java deleted file mode 100644 index f2c2d21..0000000 --- a/DataAccess/src/main/java/DAO/HibernateBankAccountDAO.java +++ /dev/null @@ -1,115 +0,0 @@ -package DAO; - -import Application.Models.Entities.BankAccount; -import DAO.Interfaces.IBankAccountDAO; -import org.hibernate.Session; -import org.hibernate.SessionFactory; -import org.hibernate.Transaction; - -public class HibernateBankAccountDAO implements IBankAccountDAO { - private final SessionFactory sessionFactory; - - public HibernateBankAccountDAO(SessionFactory sf) { - this.sessionFactory = sf; - } - - public BankAccount GetBankAccountByID(int id) { - try (Session session = sessionFactory.openSession()) { - return session.get(BankAccount.class, id); - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } - - public void SaveBankAccount(BankAccount account) { - try (Session session = sessionFactory.openSession()) { - Transaction tx = null; - try { - tx = session.beginTransaction(); - session.saveOrUpdate(account); - tx.commit(); - } catch (Exception e) { - if (tx != null) { - tx.rollback(); - } - e.printStackTrace(); - } - } - } - - public void DeleteBankAccount(BankAccount bankAccount) { - try (Session session = sessionFactory.openSession()) { - Transaction tx = null; - try { - tx = session.beginTransaction(); - session.delete(bankAccount); - tx.commit(); - } catch (Exception e) { - if (tx != null) { - tx.rollback(); - } - e.printStackTrace(); - } - } - } - - public boolean Deposit ( int accountId, double amount){ - try (Session session = sessionFactory.openSession()) { - Transaction tx = session.beginTransaction(); - BankAccount account = session.get(BankAccount.class, accountId); - if (account != null) { - account.setBalance(account.getBalance() + amount); - session.saveOrUpdate(account); - tx.commit(); - return true; - } - tx.rollback(); - } catch (Exception e) { - e.printStackTrace(); - } - return false; - } - - public boolean Withdraw ( int accountId, double amount){ - try (Session session = sessionFactory.openSession()) { - Transaction tx = session.beginTransaction(); - BankAccount account = session.get(BankAccount.class, accountId); - if (account != null && account.getBalance() >= amount) { - account.setBalance(account.getBalance() - amount); - session.saveOrUpdate(account); - tx.commit(); - return true; - } - tx.rollback(); - return false; - } catch (Exception e) { - e.printStackTrace(); - return false; - } - } - - public boolean Transfer ( int accountFromId, int accountToId, double amount){ - try (Session session = sessionFactory.openSession()) { - Transaction tx = session.beginTransaction(); - - BankAccount accountFrom = session.get(BankAccount.class, accountFromId); - BankAccount accountTo = session.get(BankAccount.class, accountToId); - - if (accountFrom != null && accountTo != null && accountFrom.getBalance() >= amount) { - accountFrom.setBalance(accountFrom.getBalance() - amount); - accountTo.setBalance(accountTo.getBalance() + amount); - session.saveOrUpdate(accountFrom); - session.saveOrUpdate(accountTo); - tx.commit(); - return true; - } - - tx.rollback(); - return false; - } catch (Exception e) { - e.printStackTrace(); - return false; - } - } - } diff --git a/DataAccess/src/main/java/DAO/HibernateOperationDAO.java b/DataAccess/src/main/java/DAO/HibernateOperationDAO.java deleted file mode 100644 index 4cf7954..0000000 --- a/DataAccess/src/main/java/DAO/HibernateOperationDAO.java +++ /dev/null @@ -1,92 +0,0 @@ -package DAO; - -import Application.Models.Entities.Operation; -import DAO.Interfaces.IOperationDAO; -import org.hibernate.Session; -import org.hibernate.SessionFactory; -import org.hibernate.Transaction; - -import java.util.ArrayList; -import java.util.List; - -public class HibernateOperationDAO implements IOperationDAO { - private final SessionFactory sessionFactory; - - public HibernateOperationDAO(SessionFactory sf) { - sessionFactory = sf; - } - - @Override - public Operation GetOperationById(int id) { - try (Session session = sessionFactory.openSession()) { - return session.get(Operation.class, id); - } catch (Exception e) { - e.printStackTrace(); - return null; - } - } - - @Override - public void SaveOperation(Operation operation) { - Session session = null; - Transaction tx = null; - try { - session = sessionFactory.openSession(); - tx = session.beginTransaction(); - session.saveOrUpdate(operation); - tx.commit(); - } catch (Exception e) { - if (tx != null) { - tx.rollback(); - } - e.printStackTrace(); - } finally { - if (session != null) { - session.close(); - } - } - } - - @Override - public void DeleteOperation(Operation operation) { - Session session = null; - Transaction tx = null; - try { - session = sessionFactory.openSession(); - tx = session.beginTransaction(); - session.delete(operation); - tx.commit(); - } catch (Exception e) { - if (tx != null) { - tx.rollback(); - } - e.printStackTrace(); - } finally { - if (session != null) { - session.close(); - } - } - } - - @Override - public List FindAllOperations() { - try (Session session = sessionFactory.openSession()) { - return session.createQuery("FROM Operation", Operation.class).list(); - } catch (Exception e) { - e.printStackTrace(); - return new ArrayList<>(); - } - } - - @Override - public List FindAllOperationsByAccountId(int id) { - try (Session session = sessionFactory.openSession()) { - return session.createQuery("FROM Operation WHERE bankAccount.id = :accountId", Operation.class) - .setParameter("accountId", id) - .getResultList(); - } catch (Exception e) { - e.printStackTrace(); - return new ArrayList<>(); - } - } -} \ No newline at end of file diff --git a/DataAccess/src/main/java/DAO/HibernateUserDAO.java b/DataAccess/src/main/java/DAO/HibernateUserDAO.java deleted file mode 100644 index bded311..0000000 --- a/DataAccess/src/main/java/DAO/HibernateUserDAO.java +++ /dev/null @@ -1,103 +0,0 @@ -package DAO; - -import Application.Models.Entities.User; -import DAO.Interfaces.IUserDAO; -import org.hibernate.Hibernate; -import org.hibernate.Session; -import org.hibernate.SessionFactory; -import org.hibernate.Transaction; - -import java.util.List; - -public class HibernateUserDAO implements IUserDAO { - private final SessionFactory sessionFactory; - - public HibernateUserDAO(SessionFactory sf) { - sessionFactory = sf; - } - - @Override - public void SaveUser(User user) { - if (user == null) { - throw new IllegalArgumentException("Пользователь не может быть null"); - } - Session session = null; - Transaction tx = null; - try { - session = sessionFactory.openSession(); - tx = session.beginTransaction(); - session.saveOrUpdate(user); - tx.commit(); - } catch (Exception e) { - if (tx != null) { - tx.rollback(); - } - e.printStackTrace(); - } finally { - if (session != null) { - session.close(); - } - } - } - - @Override - public void DeleteUser(User user) { - if (user == null || user.getId() == null) { - throw new IllegalArgumentException("Пользователь или его ID не могут быть null"); - } - Session session = null; - Transaction tx = null; - try { - session = sessionFactory.openSession(); - tx = session.beginTransaction(); - session.delete(user); - tx.commit(); - } catch (Exception e) { - if (tx != null) { - tx.rollback(); - } - e.printStackTrace(); - } finally { - if (session != null) { - session.close(); - } - } - } - - @Override - public User FindUserById(int id) { - Session session = null; - try { - session = sessionFactory.openSession(); - User user = session.get(User.class, id); - if (user != null) { - Hibernate.initialize(user.getBankAccounts()); - Hibernate.initialize(user.getFriends()); - } - return user; - } catch (Exception e) { - e.printStackTrace(); - return null; - } finally { - if (session != null) { - session.close(); - } - } - } - - @Override - public List FindAllUsers() { - Session session = null; - try { - session = sessionFactory.openSession(); - return session.createQuery("FROM User", User.class).list(); - } catch (Exception e) { - e.printStackTrace(); - return null; - } finally { - if (session != null) { - session.close(); - } - } - } -} \ No newline at end of file diff --git a/DataAccess/src/main/java/DAO/Interfaces/IBankAccountDAO.java b/DataAccess/src/main/java/DAO/Interfaces/IBankAccountDAO.java deleted file mode 100644 index b535210..0000000 --- a/DataAccess/src/main/java/DAO/Interfaces/IBankAccountDAO.java +++ /dev/null @@ -1,12 +0,0 @@ -package DAO.Interfaces; - -import Application.Models.Entities.BankAccount; - -public interface IBankAccountDAO { - BankAccount GetBankAccountByID(int id); - void SaveBankAccount(BankAccount bankAccount); - void DeleteBankAccount(BankAccount bankAccount); - boolean Deposit(int accountId, double amount); - boolean Withdraw(int accountId, double amount); - boolean Transfer(int accountFromId, int accountToId, double amount); -} diff --git a/DataAccess/src/main/java/DAO/Interfaces/IOperationDAO.java b/DataAccess/src/main/java/DAO/Interfaces/IOperationDAO.java deleted file mode 100644 index deb824a..0000000 --- a/DataAccess/src/main/java/DAO/Interfaces/IOperationDAO.java +++ /dev/null @@ -1,13 +0,0 @@ -package DAO.Interfaces; - -import Application.Models.Entities.Operation; - -import java.util.List; - -public interface IOperationDAO { - Operation GetOperationById(int id); - void SaveOperation(Operation operation); - void DeleteOperation(Operation operation); - List FindAllOperations(); - List FindAllOperationsByAccountId(int id); -} diff --git a/DataAccess/src/main/java/DAO/Interfaces/IUserDAO.java b/DataAccess/src/main/java/DAO/Interfaces/IUserDAO.java deleted file mode 100644 index 8e055fc..0000000 --- a/DataAccess/src/main/java/DAO/Interfaces/IUserDAO.java +++ /dev/null @@ -1,12 +0,0 @@ -package DAO.Interfaces; - -import Application.Models.Entities.User; - -import java.util.List; - -public interface IUserDAO { - void SaveUser(User user); - void DeleteUser(User user); - User FindUserById(int id); - List FindAllUsers(); -} diff --git a/DataAccess/src/main/java/DataAccess/Configs/DataAccessConfig.java b/DataAccess/src/main/java/DataAccess/Configs/DataAccessConfig.java new file mode 100644 index 0000000..8f702bc --- /dev/null +++ b/DataAccess/src/main/java/DataAccess/Configs/DataAccessConfig.java @@ -0,0 +1,9 @@ +package DataAccess.Configs; + +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; + +@Configuration +@ComponentScan(basePackages = "DataAccess.Services") +public class DataAccessConfig { +} \ No newline at end of file diff --git a/DataAccess/src/main/java/DataAccess/Configs/JPAConfig.java b/DataAccess/src/main/java/DataAccess/Configs/JPAConfig.java new file mode 100644 index 0000000..c8d1971 --- /dev/null +++ b/DataAccess/src/main/java/DataAccess/Configs/JPAConfig.java @@ -0,0 +1,11 @@ +package DataAccess.Configs; + +import org.springframework.context.annotation.Configuration; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.boot.autoconfigure.domain.EntityScan; + +@Configuration +@EnableJpaRepositories(basePackages = "DataAccess.Repositories") +@EntityScan(basePackages = "Application.Models.Entities") +public class JPAConfig { +} \ No newline at end of file diff --git a/DataAccess/src/main/java/DataAccess/Repositories/IBankAccountRepository.java b/DataAccess/src/main/java/DataAccess/Repositories/IBankAccountRepository.java new file mode 100644 index 0000000..589ac31 --- /dev/null +++ b/DataAccess/src/main/java/DataAccess/Repositories/IBankAccountRepository.java @@ -0,0 +1,8 @@ +package DataAccess.Repositories; + +import Application.Models.Entities.BankAccount; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface IBankAccountRepository extends JpaRepository { } diff --git a/DataAccess/src/main/java/DataAccess/Repositories/IOperationRepository.java b/DataAccess/src/main/java/DataAccess/Repositories/IOperationRepository.java new file mode 100644 index 0000000..9ce232f --- /dev/null +++ b/DataAccess/src/main/java/DataAccess/Repositories/IOperationRepository.java @@ -0,0 +1,12 @@ +package DataAccess.Repositories; + +import Application.Models.Entities.Operation; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface IOperationRepository extends JpaRepository { + List findAllByBankAccount_Id(int id); +} diff --git a/DataAccess/src/main/java/DataAccess/Repositories/IUserRepository.java b/DataAccess/src/main/java/DataAccess/Repositories/IUserRepository.java new file mode 100644 index 0000000..df93795 --- /dev/null +++ b/DataAccess/src/main/java/DataAccess/Repositories/IUserRepository.java @@ -0,0 +1,8 @@ +package DataAccess.Repositories; + +import Application.Models.Entities.User; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface IUserRepository extends JpaRepository { } diff --git a/DataAccess/src/main/java/DataAccess/Services/BankAccountService.java b/DataAccess/src/main/java/DataAccess/Services/BankAccountService.java new file mode 100644 index 0000000..11619e1 --- /dev/null +++ b/DataAccess/src/main/java/DataAccess/Services/BankAccountService.java @@ -0,0 +1,93 @@ +package DataAccess.Services; + +import Application.Models.Entities.BankAccount; +import DataAccess.Repositories.IBankAccountRepository; +import DataAccess.Services.Interfaces.IBankAccountService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; +import java.util.Optional; + +@Service +public class BankAccountService implements IBankAccountService { + private final IBankAccountRepository BankAccountRepository; + + @Autowired + public BankAccountService(IBankAccountRepository bankAccountRepository) { + this.BankAccountRepository = bankAccountRepository; + } + + @Override + public BankAccount GetAccount(int id) { + return BankAccountRepository.findById(id).orElse(null); + } + + @Override + @Transactional + public void UpdateAccount(BankAccount account) { + if (account != null) { + BankAccountRepository.save(account); + } + } + + @Override + public void DeleteAccount(BankAccount account) { + BankAccountRepository.delete(account); + } + + @Override + @Transactional + public boolean Deposit(int accountId, double amount) { + Optional optional = BankAccountRepository.findById(accountId); + if (optional.isPresent()) { + BankAccount account = optional.get(); + account.setBalance(account.getBalance() + amount); + BankAccountRepository.save(account); + return true; + } + return false; + } + + @Override + @Transactional + public boolean Withdraw(int accountId, double amount) { + Optional optional = BankAccountRepository.findById(accountId); + if (optional.isPresent()) { + BankAccount account = optional.get(); + if (account.getBalance() >= amount) { + account.setBalance(account.getBalance() - amount); + BankAccountRepository.save(account); + return true; + } + } + return false; + } + + @Override + @Transactional + public boolean Transfer(int accountFromId, int accountToId, double amount) { + Optional fromOpt = BankAccountRepository.findById(accountFromId); + Optional toOpt = BankAccountRepository.findById(accountToId); + + if (fromOpt.isPresent() && toOpt.isPresent()) { + BankAccount from = fromOpt.get(); + BankAccount to = toOpt.get(); + + if (from.getBalance() >= amount) { + from.setBalance(from.getBalance() - amount); + to.setBalance(to.getBalance() + amount); + BankAccountRepository.save(from); + BankAccountRepository.save(to); + return true; + } + } + return false; + } + + @Override + public List GetAllAccounts() { + return this.BankAccountRepository.findAll(); + } +} diff --git a/DataAccess/src/main/java/Services/Interfaces/IBankAccountService.java b/DataAccess/src/main/java/DataAccess/Services/Interfaces/IBankAccountService.java similarity index 78% rename from DataAccess/src/main/java/Services/Interfaces/IBankAccountService.java rename to DataAccess/src/main/java/DataAccess/Services/Interfaces/IBankAccountService.java index eac5e81..708de5a 100644 --- a/DataAccess/src/main/java/Services/Interfaces/IBankAccountService.java +++ b/DataAccess/src/main/java/DataAccess/Services/Interfaces/IBankAccountService.java @@ -1,12 +1,21 @@ -package Services.Interfaces; +package DataAccess.Services.Interfaces; import Application.Models.Entities.BankAccount; +import java.util.List; + public interface IBankAccountService { BankAccount GetAccount(int id); + void UpdateAccount(BankAccount account); + void DeleteAccount(BankAccount account); + boolean Deposit(int accountId, double amount); + boolean Withdraw(int accountId, double amount); + boolean Transfer(int accountFromId, int accountToId, double amount); + + List GetAllAccounts(); } diff --git a/DataAccess/src/main/java/Services/Interfaces/IOperationService.java b/DataAccess/src/main/java/DataAccess/Services/Interfaces/IOperationService.java similarity index 77% rename from DataAccess/src/main/java/Services/Interfaces/IOperationService.java rename to DataAccess/src/main/java/DataAccess/Services/Interfaces/IOperationService.java index f86fd3e..7b0131e 100644 --- a/DataAccess/src/main/java/Services/Interfaces/IOperationService.java +++ b/DataAccess/src/main/java/DataAccess/Services/Interfaces/IOperationService.java @@ -1,4 +1,4 @@ -package Services.Interfaces; +package DataAccess.Services.Interfaces; import Application.Models.Entities.Operation; @@ -6,7 +6,12 @@ public interface IOperationService { Operation GetOperation(int id); + void SaveOperation(Operation operation); + void DeleteOperation(Operation operation); + List FindAllOperationsByAccountId(int id); + + List FindAllOperations(); } diff --git a/DataAccess/src/main/java/Services/Interfaces/IUserService.java b/DataAccess/src/main/java/DataAccess/Services/Interfaces/IUserService.java similarity index 62% rename from DataAccess/src/main/java/Services/Interfaces/IUserService.java rename to DataAccess/src/main/java/DataAccess/Services/Interfaces/IUserService.java index 54e8164..6e3ead8 100644 --- a/DataAccess/src/main/java/Services/Interfaces/IUserService.java +++ b/DataAccess/src/main/java/DataAccess/Services/Interfaces/IUserService.java @@ -1,9 +1,15 @@ -package Services.Interfaces; +package DataAccess.Services.Interfaces; import Application.Models.Entities.User; +import java.util.List; + public interface IUserService { User GetUser(int id); + void SaveUser(User user); + void DeleteUser(User user); + + List GetAllUsers(); } diff --git a/DataAccess/src/main/java/DataAccess/Services/OperationService.java b/DataAccess/src/main/java/DataAccess/Services/OperationService.java new file mode 100644 index 0000000..daa4d7a --- /dev/null +++ b/DataAccess/src/main/java/DataAccess/Services/OperationService.java @@ -0,0 +1,44 @@ +package DataAccess.Services; + +import Application.Models.Entities.Operation; +import DataAccess.Repositories.IOperationRepository; +import DataAccess.Services.Interfaces.IOperationService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class OperationService implements IOperationService { + private final IOperationRepository OperationRepository; + + @Autowired + public OperationService(IOperationRepository operationRepository) { + OperationRepository = operationRepository; + } + + @Override + public Operation GetOperation(int id) { + return OperationRepository.findById(id).orElse(null); + } + + @Override + public void SaveOperation(Operation operation) { + OperationRepository.save(operation); + } + + @Override + public void DeleteOperation(Operation operation) { + OperationRepository.delete(operation); + } + + @Override + public List FindAllOperationsByAccountId(int id) { + return OperationRepository.findAllByBankAccount_Id(id); + } + + @Override + public List FindAllOperations() { + return OperationRepository.findAll(); + } +} diff --git a/DataAccess/src/main/java/DataAccess/Services/UserService.java b/DataAccess/src/main/java/DataAccess/Services/UserService.java new file mode 100644 index 0000000..b49d22a --- /dev/null +++ b/DataAccess/src/main/java/DataAccess/Services/UserService.java @@ -0,0 +1,39 @@ +package DataAccess.Services; + +import Application.Models.Entities.User; +import DataAccess.Repositories.IUserRepository; +import DataAccess.Services.Interfaces.IUserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class UserService implements IUserService { + private final IUserRepository UserRepository; + + @Autowired + public UserService(IUserRepository userRepository) { + this.UserRepository = userRepository; + } + + @Override + public User GetUser(int id) { + return UserRepository.findById(id).orElse(null); + } + + @Override + public void SaveUser(User user) { + UserRepository.save(user); + } + + @Override + public void DeleteUser(User user) { + UserRepository.delete(user); + } + + @Override + public List GetAllUsers() { + return UserRepository.findAll(); + } +} diff --git a/DataAccess/src/main/java/Services/BankAccountService.java b/DataAccess/src/main/java/Services/BankAccountService.java deleted file mode 100644 index fe291f0..0000000 --- a/DataAccess/src/main/java/Services/BankAccountService.java +++ /dev/null @@ -1,42 +0,0 @@ -package Services; - -import Application.Models.Entities.BankAccount; -import DAO.HibernateBankAccountDAO; -import Services.Interfaces.IBankAccountService; - -public class BankAccountService implements IBankAccountService { - private final HibernateBankAccountDAO BankAccountDAO; - - public BankAccountService(HibernateBankAccountDAO bankAccountDAO) { - BankAccountDAO = bankAccountDAO; - } - @Override - public BankAccount GetAccount(int id) { - return BankAccountDAO.GetBankAccountByID(id); - } - - @Override - public void UpdateAccount(BankAccount account) { - BankAccountDAO.SaveBankAccount(account); - } - - @Override - public void DeleteAccount(BankAccount account) { - BankAccountDAO.DeleteBankAccount(account); - } - - @Override - public boolean Deposit(int accountId, double amount) { - return BankAccountDAO.Deposit(accountId, amount); - } - - @Override - public boolean Withdraw(int accountId, double amount) { - return BankAccountDAO.Withdraw(accountId, amount); - } - - @Override - public boolean Transfer(int accountFromId, int accountToId, double amount) { - return BankAccountDAO.Transfer(accountFromId, accountToId, amount); - } -} diff --git a/DataAccess/src/main/java/Services/OperationService.java b/DataAccess/src/main/java/Services/OperationService.java deleted file mode 100644 index f2920a1..0000000 --- a/DataAccess/src/main/java/Services/OperationService.java +++ /dev/null @@ -1,35 +0,0 @@ -package Services; - -import Application.Models.Entities.Operation; -import DAO.HibernateOperationDAO; -import Services.Interfaces.IOperationService; - -import java.util.List; - -public class OperationService implements IOperationService { - private final HibernateOperationDAO OperationDAO; - - public OperationService(HibernateOperationDAO operationDAO) { - OperationDAO = operationDAO; - } - - @Override - public Operation GetOperation(int id) { - return OperationDAO.GetOperationById(id); - } - - @Override - public void SaveOperation(Operation operation) { - OperationDAO.SaveOperation(operation); - } - - @Override - public void DeleteOperation(Operation operation) { - OperationDAO.DeleteOperation(operation); - } - - @Override - public List FindAllOperationsByAccountId(int id) { - return OperationDAO.FindAllOperationsByAccountId(id); - } -} diff --git a/DataAccess/src/main/java/Services/UserService.java b/DataAccess/src/main/java/Services/UserService.java deleted file mode 100644 index 2339ea4..0000000 --- a/DataAccess/src/main/java/Services/UserService.java +++ /dev/null @@ -1,28 +0,0 @@ -package Services; - -import Application.Models.Entities.User; -import DAO.HibernateUserDAO; -import Services.Interfaces.IUserService; - -public class UserService implements IUserService { - private final HibernateUserDAO UserDAO; - - public UserService(HibernateUserDAO userDAO) { - UserDAO = userDAO; - } - - @Override - public User GetUser(int id) { - return UserDAO.FindUserById(id); - } - - @Override - public void SaveUser(User user) { - UserDAO.SaveUser(user); - } - - @Override - public void DeleteUser(User user) { - UserDAO.DeleteUser(user); - } -} diff --git a/DataAccess/src/main/java/Utils/HibernateSessionFactoryUtil.java b/DataAccess/src/main/java/Utils/HibernateSessionFactoryUtil.java deleted file mode 100644 index 230c5e8..0000000 --- a/DataAccess/src/main/java/Utils/HibernateSessionFactoryUtil.java +++ /dev/null @@ -1,35 +0,0 @@ -package Utils; - -import Application.Models.Entities.BankAccount; -import Application.Models.Entities.Operation; -import Application.Models.Entities.User; -import org.hibernate.SessionFactory; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.cfg.Configuration; - - -public class HibernateSessionFactoryUtil { - private static SessionFactory SessionFactory; - - private HibernateSessionFactoryUtil() {} - - public static SessionFactory GetSessionFactory() { - if (SessionFactory == null) { - try { - Configuration config = new Configuration().configure(); - - config.addAnnotatedClass(User.class); - config.addAnnotatedClass(BankAccount.class); - config.addAnnotatedClass(Operation.class); - StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder() - .applySettings(config.getProperties()); - - SessionFactory = config.buildSessionFactory(builder.build()); - } catch (Exception e) { - System.out.println("Error in getSessionFactory: " + e.getMessage()); - throw new RuntimeException("Failed to create sessionFactory", e); - } - } - return SessionFactory; - } -} diff --git a/DataAccess/src/main/resources/application.yml b/DataAccess/src/main/resources/application.yml new file mode 100644 index 0000000..5f42461 --- /dev/null +++ b/DataAccess/src/main/resources/application.yml @@ -0,0 +1,17 @@ +spring: + datasource: + url: ${DB_URL} + username: ${DB_USERNAME} + password: ${DB_PASSWORD} + driver-class-name: org.postgresql.Driver + + jpa: + database-platform: org.hibernate.dialect.PostgreSQLDialect + hibernate: + ddl-auto: none + show-sql: true + + flyway: + enabled: true + locations: classpath:db/migration + baseline-on-migrate: true diff --git a/DataAccess/src/main/resources/hibernate.cfg.xml b/DataAccess/src/main/resources/hibernate.cfg.xml deleted file mode 100644 index 99e6283..0000000 --- a/DataAccess/src/main/resources/hibernate.cfg.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - org.postgresql.Driver - jdbc:postgresql://localhost:5432/JavaLabsDb - postgres - limosha - - - org.hibernate.dialect.PostgreSQLDialect - - - true - true - - create-drop - - - - - - - diff --git a/Presentation/pom.xml b/Presentation/pom.xml index e799d3e..310d0e3 100644 --- a/Presentation/pom.xml +++ b/Presentation/pom.xml @@ -8,6 +8,12 @@ Presentation 1.0-SNAPSHOT + + com.example + lim0sha + 1.0-SNAPSHOT + + 17 17 @@ -16,20 +22,15 @@ - - org.junit.jupiter - junit-jupiter-api - 5.9.2 - test - org.junit.jupiter - junit-jupiter-engine - 5.9.2 + junit-jupiter + 5.10.0 test + org.projectlombok @@ -57,6 +58,18 @@ test + + org.springdoc + springdoc-openapi-starter-webmvc-ui + 2.0.2 + + + + + org.springframework.boot + spring-boot-starter-security + + @@ -118,7 +131,7 @@ org.apache.maven.plugins maven-surefire-plugin - 2.21.0 + 3.0.0-M9 org.junit.jupiter diff --git a/Presentation/src/main/java/Presentation/Configs/AppConfig.java b/Presentation/src/main/java/Presentation/Configs/AppConfig.java new file mode 100644 index 0000000..c9d1f91 --- /dev/null +++ b/Presentation/src/main/java/Presentation/Configs/AppConfig.java @@ -0,0 +1,37 @@ +package Presentation.Configs; + +import Application.Managers.IUserManager; +import Presentation.Console.Menu; +import DataAccess.Services.Interfaces.IBankAccountService; +import DataAccess.Services.Interfaces.IOperationService; +import DataAccess.Services.Interfaces.IUserService; +import Presentation.Interfaces.IBaseController; +import Presentation.Controllers.BaseController; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import java.util.Scanner; + +@Configuration +@ComponentScan(basePackages = { "Presentation", "DataAccess", "Application" }) +public class AppConfig { + + @Bean + public Scanner scanner() { + return new Scanner(System.in); + } + + @Bean + public BaseController baseController( + IUserManager userManager, + IUserService userService, + IBankAccountService bankAccountService, + IOperationService operationService) { + return new BaseController(userManager, userService, bankAccountService, operationService); + } + + @Bean + public Menu menu(IBaseController baseController, Scanner scanner) { + return new Menu(baseController, scanner); + } +} \ No newline at end of file diff --git a/Presentation/src/main/java/Presentation/Configs/AppInitializer.java b/Presentation/src/main/java/Presentation/Configs/AppInitializer.java new file mode 100644 index 0000000..622be4a --- /dev/null +++ b/Presentation/src/main/java/Presentation/Configs/AppInitializer.java @@ -0,0 +1,22 @@ +package Presentation.Configs; + +import Presentation.Interfaces.IMenu; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.stereotype.Component; + +@Component +public class AppInitializer implements CommandLineRunner { + + private final IMenu menu; + + @Autowired + public AppInitializer(IMenu menu) { + this.menu = menu; + } + + @Override + public void run(String... args) { + // menu.Run(); + } +} \ No newline at end of file diff --git a/Presentation/src/main/java/Presentation/Configs/DotenvInitializer.java b/Presentation/src/main/java/Presentation/Configs/DotenvInitializer.java new file mode 100644 index 0000000..52080ed --- /dev/null +++ b/Presentation/src/main/java/Presentation/Configs/DotenvInitializer.java @@ -0,0 +1,20 @@ +package Presentation.Configs; + +import io.github.cdimascio.dotenv.Dotenv; +import org.springframework.context.ApplicationContextInitializer; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.stereotype.Component; + +@Component +public class DotenvInitializer implements ApplicationContextInitializer { + + public static Dotenv dotenv; + + @Override + public void initialize(ConfigurableApplicationContext applicationContext) { + dotenv = Dotenv.configure().ignoreIfMissing().load(); + System.setProperty("DB_URL", dotenv.get("DB_URL")); + System.setProperty("DB_USERNAME", dotenv.get("DB_USERNAME")); + System.setProperty("DB_PASSWORD", dotenv.get("DB_PASSWORD")); + } +} \ No newline at end of file diff --git a/Presentation/src/main/java/Presentation/Configs/SecurityConfig.java b/Presentation/src/main/java/Presentation/Configs/SecurityConfig.java new file mode 100644 index 0000000..27890c3 --- /dev/null +++ b/Presentation/src/main/java/Presentation/Configs/SecurityConfig.java @@ -0,0 +1,24 @@ +package Presentation.Configs; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.Customizer; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; + +@Configuration +@EnableWebSecurity +public class SecurityConfig { + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + return http + .authorizeHttpRequests(auth -> auth + .anyRequest().permitAll() + ) + .csrf(csrf -> csrf.disable()) // отключаем CSRF + .httpBasic(Customizer.withDefaults()) // можно убрать если не нужен basic auth + .build(); + } +} diff --git a/Presentation/src/main/java/Presentation/Configs/SwaggerConfig.java b/Presentation/src/main/java/Presentation/Configs/SwaggerConfig.java new file mode 100644 index 0000000..d847d6c --- /dev/null +++ b/Presentation/src/main/java/Presentation/Configs/SwaggerConfig.java @@ -0,0 +1,18 @@ +package Presentation.Configs; + +import org.springdoc.core.models.GroupedOpenApi; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class SwaggerConfig { + + @Bean + public GroupedOpenApi publicApi() { + return GroupedOpenApi.builder() + .group("public-api") + .packagesToScan("Presentation.Controllers") + .pathsToMatch("/**") + .build(); + } +} \ No newline at end of file diff --git a/Presentation/src/main/java/Presentation/Console/Main.java b/Presentation/src/main/java/Presentation/Console/Main.java index 5487063..2a7456d 100644 --- a/Presentation/src/main/java/Presentation/Console/Main.java +++ b/Presentation/src/main/java/Presentation/Console/Main.java @@ -1,14 +1,14 @@ package Presentation.Console; +import Presentation.Configs.DotenvInitializer; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; -import Presentation.Interfaces.IMenu; -import org.flywaydb.core.Flyway; - +@SpringBootApplication public class Main { public static void main(String[] args) { - Flyway flyway = Flyway.configure().dataSource("jdbc:postgresql://localhost:5432/JavaLabsDb", "postgres", "limosha").load(); - flyway.migrate(); - IMenu menu = new Menu(); - menu.Run(); + SpringApplication app = new SpringApplication(Main.class); + app.addInitializers(new DotenvInitializer()); + app.run(args); } } diff --git a/Presentation/src/main/java/Presentation/Console/Menu.java b/Presentation/src/main/java/Presentation/Console/Menu.java index ecda47b..dc46e4c 100644 --- a/Presentation/src/main/java/Presentation/Console/Menu.java +++ b/Presentation/src/main/java/Presentation/Console/Menu.java @@ -1,72 +1,33 @@ package Presentation.Console; -import Application.Models.Entities.Operation; import Application.ResultTypes.BankAccountResult; import Application.ResultTypes.OperationResult; import Application.ResultTypes.UserResult; -import Application.Managers.UserManager; import Application.Models.Entities.BankAccount; import Application.Models.Entities.User; import Application.Models.Enums.HairColor; import Application.Models.Enums.Sex; -import DAO.HibernateBankAccountDAO; -import DAO.HibernateOperationDAO; -import DAO.HibernateUserDAO; -import Presentation.Controllers.UserController; -import Services.BankAccountService; -import Services.OperationService; -import Services.UserService; import Presentation.Interfaces.IMenu; -import Utils.HibernateSessionFactoryUtil; -import org.hibernate.Hibernate; -import org.hibernate.SessionFactory; -import org.hibernate.cfg.Configuration; +import Presentation.Interfaces.IBaseController; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.stereotype.Component; import java.util.Scanner; -/** - * Класс {@code Menu} представляет консольное меню для управления пользователями и банковскими счетами. - * Предоставляет интерфейс для создания пользователей, управления друзьями, работы с банковскими счетами - * и выполнения финансовых операций. - *

- * Реализует интерфейс {@link IMenu}. - *

- * Основные возможности: - *

    - *
  • Создание пользователя
  • - *
  • Просмотр информации о пользователе
  • - *
  • Управление списком друзей пользователя
  • - *
  • Создание банковского счета
  • - *
  • Проверка баланса счета
  • - *
  • Снятие и пополнение средств
  • - *
  • Перевод средств между счетами
  • - *
- * - * Зависимости: - *
    - *
  • {@link UserService} - основной сервис для работы с пользователями и счетами
  • - *
  • {@link Scanner} - для считывания ввода пользователя
  • - *
- * - * @author lim0sha - * @version 1.0 - */ +@Component +@ComponentScan(basePackages = "Presentation") public class Menu implements IMenu { - private final SessionFactory sf = HibernateSessionFactoryUtil.GetSessionFactory(); - private final UserController controller = new UserController( - new UserManager(), new UserService(new HibernateUserDAO(sf)), - new BankAccountService(new HibernateBankAccountDAO(sf)), - new OperationService(new HibernateOperationDAO(sf)) - ); + private final IBaseController baseController; + private final Scanner scanner; + @Autowired + public Menu(IBaseController baseController, Scanner scanner) { + this.baseController = baseController; + this.scanner = scanner; + } - private final Scanner scanner = new Scanner(System.in); - - /** - * Запускает основное меню и обрабатывает выбор пользователя. - * Предоставляет доступ к основным функциям системы через консольный интерфейс. - */ @Override public void Run() { while (true) { @@ -87,13 +48,11 @@ public void Run() { switch (choice) { case 1 -> createUser(); - case 2 -> getUserInfo(); - case 3 -> manageFriends(); - case 4 -> createBankAccount(); - case 5 -> checkBalance(); - case 6 -> withdraw(); - case 7 -> deposit(); - case 8 -> transfer(); + case 2 -> manageFriends(); + case 3 -> createBankAccount(); + case 4 -> withdraw(); + case 5 -> deposit(); + case 6 -> transfer(); case 0 -> { System.out.println("Выход..."); return; @@ -103,9 +62,6 @@ public void Run() { } } - /** - * Создает нового пользователя с вводом данных через консоль. - */ private void createUser() { System.out.print("Введите логин: "); String login = scanner.nextLine().trim(); @@ -184,11 +140,9 @@ private void createUser() { return; } - // Создаем пользователя без использования IdGenerator, так как ID генерируется базой данных User user = new User(login, name, age, sex, hairColor); - // Вызываем метод создания пользователя через контроллер - UserResult result = controller.CreateUser(user); + UserResult result = baseController.CreateUser(user); if (result instanceof UserResult.Success) { System.out.println("Пользователь создан!"); } else { @@ -196,18 +150,6 @@ private void createUser() { } } - /** - * Выводит информацию о пользователе по введенному ID. - */ - private void getUserInfo() { - System.out.print("Введите ID пользователя: "); - int userId = scanner.nextInt(); - controller.GetUserInfo(userId); - } - - /** - * Позволяет добавить или удалить друга из списка друзей пользователя. - */ private void manageFriends() { System.out.print("Введите ID пользователя: "); int userId = scanner.nextInt(); @@ -218,10 +160,10 @@ private void manageFriends() { int action = scanner.nextInt(); if (action == 1) { - controller.AddFriend(userId, friendId); + baseController.AddFriend(userId, friendId); System.out.println("Друг добавлен."); } else if (action == 2) { - controller.RemoveFriend(userId, friendId); + baseController.RemoveFriend(userId, friendId); System.out.println("Друг удален."); } else { System.out.println("Неверная команда."); @@ -231,20 +173,17 @@ private void manageFriends() { } } - /** - * Создает банковский счет для существующего пользователя. - */ private void createBankAccount() { System.out.print("Введите ID пользователя: "); int userId = scanner.nextInt(); - User user = controller.GetUserById(userId); + User user = baseController.GetUserById(userId); if (user == null) { System.out.println("Пользователь с ID " + userId + " не найден."); return; } BankAccount account = new BankAccount(user); - BankAccountResult result = controller.addBankAccount(userId, account); + BankAccountResult result = baseController.AddBankAccount(userId, account); if (result instanceof BankAccountResult.Success) { System.out.println("Счет создан!"); } else { @@ -252,34 +191,15 @@ private void createBankAccount() { } } - /** - * Проверяет баланс на указанном банковском счете. - */ - private void checkBalance() { - System.out.print("Введите ID счета: "); - int accountId = scanner.nextInt(); - BankAccount account = controller.GetBankAccountById(accountId); - - if (account == null) { - System.out.println("Счет не найден."); - return; - } - - controller.CheckBalance(account.getUser().getId(), accountId); - } - - /** - * Снимает средства с указанного банковского счета. - */ private void withdraw() { System.out.print("Введите ID счета: "); int accountId = scanner.nextInt(); System.out.print("Введите сумму снятия: "); double amount = scanner.nextDouble(); - BankAccount account = controller.GetBankAccountById(accountId); + BankAccount account = baseController.GetBankAccountById(accountId); if (account != null) { - OperationResult result = controller.Withdraw(account, amount); + OperationResult result = baseController.Withdraw(account, amount); if (result instanceof OperationResult.Success) { System.out.println("Деньги сняты."); @@ -291,18 +211,15 @@ private void withdraw() { } } - /** - * Пополняет баланс указанного банковского счета. - */ private void deposit() { System.out.print("Введите ID счета: "); int accountId = scanner.nextInt(); System.out.print("Введите сумму пополнения: "); double amount = scanner.nextDouble(); - BankAccount account = controller.GetBankAccountById(accountId); + BankAccount account = baseController.GetBankAccountById(accountId); if (account != null) { - OperationResult result = controller.Deposit(account, amount); + OperationResult result = baseController.Deposit(account, amount); if (result instanceof OperationResult.Success) { System.out.println("Счет пополнен."); } else if (result instanceof OperationResult.OperationError error) { @@ -313,9 +230,6 @@ private void deposit() { } } - /** - * Переводит средства с одного банковского счета на другой. - */ private void transfer() { try { System.out.print("Введите ID счета отправителя: "); @@ -327,11 +241,11 @@ private void transfer() { System.out.print("Введите сумму перевода: "); double amount = Double.parseDouble(scanner.nextLine().trim().replace(',', '.')); - BankAccount fromAccount = controller.GetBankAccountById(fromId); - BankAccount toAccount = controller.GetBankAccountById(toId); + BankAccount fromAccount = baseController.GetBankAccountById(fromId); + BankAccount toAccount = baseController.GetBankAccountById(toId); if (fromAccount != null && toAccount != null) { - OperationResult result = controller.Transfer(fromAccount, toAccount, amount); + OperationResult result = baseController.Transfer(fromAccount, toAccount, amount); if (result instanceof OperationResult.Success) { System.out.println("Перевод выполнен."); } else if (result instanceof OperationResult.OperationError error) { diff --git a/Presentation/src/main/java/Presentation/Controllers/BankAccountDTOController.java b/Presentation/src/main/java/Presentation/Controllers/BankAccountDTOController.java new file mode 100644 index 0000000..be441f4 --- /dev/null +++ b/Presentation/src/main/java/Presentation/Controllers/BankAccountDTOController.java @@ -0,0 +1,111 @@ +package Presentation.Controllers; + +import Application.Models.Entities.BankAccount; +import Application.ResultTypes.BankAccountResult; +import Presentation.DTO.BankAccountDTO; +import Presentation.Interfaces.IBaseController; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + + +@RestController +@RequestMapping("/bankaccounts") +public class BankAccountDTOController { + + private final IBaseController baseController; + + @Autowired + public BankAccountDTOController(IBaseController baseController) { + this.baseController = baseController; + } + + @Operation(summary = "Получить счет по ID", description = "Получает информацию о счете по ID") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Счет найден", content = @Content(mediaType = "application/json", schema = @Schema(implementation = BankAccountDTO.class))), + @ApiResponse(responseCode = "404", description = "Счет не найден") + }) + @GetMapping("/{id}") + public ResponseEntity getBankAccountById(@Parameter(description = "ID счета") @PathVariable int id) { + BankAccount account = baseController.GetBankAccountById(id); + if (account == null) { + return ResponseEntity.notFound().build(); + } + return ResponseEntity.ok(new BankAccountDTO(account)); + } + + @Operation(summary = "Создать новый счет", description = "Создает новый счет") + @ApiResponses(value = { + @ApiResponse(responseCode = "201", description = "Счет создан"), + @ApiResponse(responseCode = "400", description = "Некорректные данные") + }) + @PostMapping(consumes = "application/json", produces = "application/json") + public ResponseEntity createBankAccount(@RequestBody BankAccount account) { + try { + account.setId(null); + BankAccountResult result = baseController.AddBankAccount(account.getUser().getId(), account); + if (result instanceof BankAccountResult.Success) { + return ResponseEntity.status(HttpStatus.CREATED).body(result); + } else { + return ResponseEntity.badRequest().body(result); + } + } catch (Exception e) { + e.printStackTrace(); + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(e.getMessage()); + } + } + + + + @Operation(summary = "Обновить данные счета", description = "Обновляет данные о счете по ID") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Счет обновлен", content = @Content(mediaType = "application/json", schema = @Schema(implementation = BankAccountDTO.class))), + @ApiResponse(responseCode = "404", description = "Счет не найден"), + @ApiResponse(responseCode = "400", description = "Некорректные данные") + }) + @PutMapping("/{id}") + public ResponseEntity updateBankAccount(@Parameter(description = "ID счета") @PathVariable int id, + @RequestBody BankAccount bankAccount) { + BankAccount existingAccount = baseController.GetBankAccountById(id); + if (existingAccount == null) { + return ResponseEntity.notFound().build(); + } + + existingAccount.setBalance(bankAccount.getBalance()); + existingAccount.setUser(bankAccount.getUser()); + + BankAccountResult result = baseController.UpdateBankAccount(existingAccount); + if (result instanceof BankAccountResult.Success) { + return ResponseEntity.ok(new BankAccountDTO(existingAccount)); + } else { + return ResponseEntity.badRequest().body(result); + } + } + + + @Operation(summary = "Удалить счет", description = "Удаляет счет по ID") + @ApiResponses(value = { + @ApiResponse(responseCode = "204", description = "Счет удален"), + @ApiResponse(responseCode = "404", description = "Счет не найден") + }) + @DeleteMapping("/{id}") + public ResponseEntity deleteBankAccount(@Parameter(description = "ID счета") @PathVariable int id) { + BankAccount account = baseController.GetBankAccountById(id); + if (account == null) { + return ResponseEntity.notFound().build(); + } + BankAccountResult result = baseController.RemoveBankAccount(account.getUser().getId(), account); + if (result instanceof BankAccountResult.Success) { + return ResponseEntity.noContent().build(); + } else { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result); + } + } +} diff --git a/Presentation/src/main/java/Presentation/Controllers/BaseController.java b/Presentation/src/main/java/Presentation/Controllers/BaseController.java new file mode 100644 index 0000000..06cc749 --- /dev/null +++ b/Presentation/src/main/java/Presentation/Controllers/BaseController.java @@ -0,0 +1,275 @@ +package Presentation.Controllers; + +import Application.Managers.IUserManager; +import Application.Models.Entities.BankAccount; +import Application.Models.Entities.Operation; +import Application.Models.Entities.User; +import Application.Models.Enums.HairColor; +import Application.Models.Enums.OperationType; +import Application.Models.Enums.Sex; +import Application.ResultTypes.BankAccountResult; +import Application.ResultTypes.OperationResult; +import Application.ResultTypes.UserResult; +import Presentation.Interfaces.IBaseController; +import DataAccess.Services.Interfaces.IBankAccountService; +import DataAccess.Services.Interfaces.IOperationService; +import DataAccess.Services.Interfaces.IUserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +public class BaseController implements IBaseController { + + private final IUserManager userManager; + private final IUserService userService; + private final IBankAccountService bankAccountService; + private final IOperationService operationService; + + @Autowired + public BaseController(IUserManager userManager, IUserService userService, IBankAccountService bankAccountService, IOperationService operationService) { + this.userManager = userManager; + this.userService = userService; + this.bankAccountService = bankAccountService; + this.operationService = operationService; + } + + @Override + public UserResult CreateUser(User user) { + if (user == null || user.getLogin() == null || user.getName() == null) { + return new UserResult.UserCreationError("Некорректные данные пользователя"); + } + userService.SaveUser(user); + return new UserResult.Success(); + } + + @Override + public UserResult UpdateUser(User user) { + try { + userService.SaveUser(user); + return new UserResult.Success(); + } catch (Exception e) { + return new UserResult.UserUpdateError(e.getMessage()); + } + } + + @Override + public User GetUserById(int id) { + try { + return userService.GetUser(id); + } catch (Exception e) { + return null; + } + } + + @Override + public List GetAllUsersFiltered(Sex sex, HairColor color) { + List users = userService.GetAllUsers(); + return users.stream() + .filter(u -> (sex == null || u.getSex() == sex)) + .filter(u -> (color == null || u.getHairType() == color)) + .toList(); + } + + @Override + public List GetFriends(int userId) { + User user = userService.GetUser(userId); + if (user != null) { + return user.getFriends(); + } + return List.of(); + } + + @Override + public List GetUserBankAccounts(int userId) { + User user = userService.GetUser(userId); + if (user != null) { + return user.getBankAccounts(); + } + return List.of(); + } + + @Override + public List GetAllAccounts() { + return bankAccountService.GetAllAccounts(); + } + + @Override + public List GetFilteredOperations(OperationType type, Integer accountId) { + List operations; + + if (accountId != null) { + operations = operationService.FindAllOperationsByAccountId(accountId); + } else { + operations = operationService.FindAllOperations(); + } + + if (type != null) { + operations = operations.stream() + .filter(o -> o.getType().equalsIgnoreCase(type.toString())) + .toList(); + } + + return operations; + } + + + @Override + public BankAccount GetBankAccountById(int id) { + try { + return bankAccountService.GetAccount(id); + } catch (Exception e) { + return null; + } + } + + @Override + public UserResult DeleteUser(User user) { + try { + userService.DeleteUser(user); + return new UserResult.Success(); + } catch (Exception e) { + return new UserResult.UserDeletionError(e.getMessage()); + } + } + + @Override + public void AddFriend(int userId, int otherId) { + User user1 = userService.GetUser(userId); + User user2 = userService.GetUser(otherId); + userManager.AddFriend(user1, user2); + userService.SaveUser(user1); + userService.SaveUser(user2); + } + + @Override + public void RemoveFriend(int userId, int otherId) { + User user1 = userService.GetUser(userId); + User user2 = userService.GetUser(otherId); + userManager.RemoveFriend(user1, user2); + userService.SaveUser(user1); + userService.SaveUser(user2); + } + + @Override + public BankAccountResult AddBankAccount(int userId, BankAccount bankAccount) { + try { + User user = userService.GetUser(userId); + if (user == null) { + throw new IllegalStateException("User not found"); + } + bankAccount.setId(null); + userManager.AddBankAccount(user, bankAccount); + userService.SaveUser(user); + return new BankAccountResult.Success(); + } catch (Exception e) { + return new BankAccountResult.BankAccountCreationError(e.getMessage()); + } + } + + @Override + public BankAccountResult UpdateBankAccount(BankAccount bankAccount) { + try { + if (bankAccount == null || bankAccount.getId() == null) { + return new BankAccountResult.BankAccountUpdateError("Некорректные данные счета"); + } + bankAccountService.UpdateAccount(bankAccount); + return new BankAccountResult.Success(); + } catch (Exception e) { + return new BankAccountResult.BankAccountUpdateError(e.getMessage()); + } + } + + @Override + public BankAccountResult RemoveBankAccount(int userId, BankAccount bankAccount) { + try { + User user = userService.GetUser(userId); + userManager.RemoveBankAccount(user, bankAccount); + userService.SaveUser(user); + bankAccountService.DeleteAccount(bankAccount); + return new BankAccountResult.Success(); + } catch (Exception e) { + return new BankAccountResult.BankAccountDeletionError(e.getMessage()); + } + } + + @Override + public OperationResult CheckBalance(int userId, int accountId) { + BankAccount account = bankAccountService.GetAccount(accountId); + if (account == null || account.getUser().getId() != userId) { + return new OperationResult.OperationError("Счет не найден или принадлежит другому пользователю."); + } + System.out.println("Баланс счета: " + account.getBalance()); + return new OperationResult.Success(); + } + + @Override + public OperationResult Deposit(BankAccount bankAccount, Double amount) { + try { + boolean success = bankAccountService.Deposit(bankAccount.getId(), amount); + if (!success) { + return new OperationResult.OperationError("Deposit failed."); + } + operationService.SaveOperation(new Operation(bankAccount, OperationType.Deposit, amount)); + return new OperationResult.Success(); + } catch (Exception e) { + return new OperationResult.OperationError(e.getMessage()); + } + } + + @Override + public OperationResult Withdraw(BankAccount bankAccount, Double amount) { + try { + boolean success = bankAccountService.Withdraw(bankAccount.getId(), amount); + if (!success) { + return new OperationResult.OperationError("Not enough balance."); + } + operationService.SaveOperation(new Operation(bankAccount, OperationType.Withdraw, amount)); + return new OperationResult.Success(); + } catch (Exception e) { + return new OperationResult.OperationError(e.getMessage()); + } + } + + @Override + public OperationResult Transfer(BankAccount bankAccount1, BankAccount bankAccount2, Double amount) { + try { + User user1 = userService.GetUser(bankAccount1.getUser().getId()); + User user2 = userService.GetUser(bankAccount2.getUser().getId()); + + double commissionRate = user1.getId().equals(user2.getId()) ? 0.00 + : user1.getFriends().stream().anyMatch(f -> f.getId().equals(user2.getId())) ? 0.03 + : 0.10; + double commission = amount * commissionRate; + double totalAmount = amount + commission; + + boolean success = bankAccountService.Transfer(bankAccount1.getId(), bankAccount2.getId(), totalAmount); + if (!success) { + return new OperationResult.OperationError("Insufficient funds, including commission."); + } + + operationService.SaveOperation(new Operation(bankAccount1, OperationType.Transfer, totalAmount)); + operationService.SaveOperation(new Operation(bankAccount2, OperationType.Deposit, amount)); + + return new OperationResult.Success(); + } catch (Exception e) { + return new OperationResult.OperationError(e.getMessage()); + } + } + + @Override + public UserResult DeleteUserById(int id) { + try { + User user = userService.GetUser(id); + if (user == null) { + return new UserResult.UserDeletionError("Пользователь с данным ID не найден."); + } + + userService.DeleteUser(user); + return new UserResult.Success(); + } catch (Exception e) { + return new UserResult.UserDeletionError("Ошибка при удалении пользователя: " + e.getMessage()); + } + } +} diff --git a/Presentation/src/main/java/Presentation/Controllers/UserController.java b/Presentation/src/main/java/Presentation/Controllers/UserController.java deleted file mode 100644 index 74bee86..0000000 --- a/Presentation/src/main/java/Presentation/Controllers/UserController.java +++ /dev/null @@ -1,191 +0,0 @@ -package Presentation.Controllers; - -import Application.Managers.UserManager; -import Application.Models.Entities.BankAccount; -import Application.Models.Entities.Operation; -import Application.Models.Entities.User; -import Application.Models.Enums.OperationType; -import Application.ResultTypes.BankAccountResult; -import Application.ResultTypes.OperationResult; -import Application.ResultTypes.UserResult; -import Presentation.Interfaces.IUserController; -import Services.BankAccountService; -import Services.OperationService; -import Services.UserService; - -import java.util.ArrayList; -import java.util.List; - -public class UserController implements IUserController { - private final UserManager UserManager; - private final UserService UserService; - private final BankAccountService BankAccountService; - private final OperationService OperationService; - - public UserController(UserManager userManager, UserService userService, BankAccountService bankAccountService, OperationService operationService) { - UserManager = userManager; - UserService = userService; - BankAccountService = bankAccountService; - OperationService = operationService; - } - - @Override - public UserResult CreateUser(User user) { - if (user == null || user.getLogin() == null || user.getName() == null) { - return new UserResult.UserCreationError("Некорректные данные пользователя"); - } - UserService.SaveUser(user); - return new UserResult.Success(); - } - - @Override - public User GetUserById(int id) { - try { - return UserService.GetUser(id); - } catch (Exception e) { - return null; - } - } - - @Override - public BankAccount GetBankAccountById(int id) { - try { - return BankAccountService.GetAccount(id); - } catch (Exception e) { - return null; - } - } - - @Override - public UserResult DeleteUser(User user) { - try { - UserService.DeleteUser(user); - return new UserResult.Success(); - } catch (Exception e) { - return new UserResult.UserDeletionError(e.getMessage()); - } - } - - @Override - public void GetUserInfo(int id) { - UserManager.GetUserInfo(UserService.GetUser(id)); - } - - @Override - public void AddFriend(int userId, int otherId) { - User user1 = UserService.GetUser(userId); - User user2 = UserService.GetUser(otherId); - UserManager.AddFriend(user1, user2); - UserService.SaveUser(user1); - UserService.SaveUser(user2); - } - - @Override - public void RemoveFriend(int userId, int otherId) { - User user1 = UserService.GetUser(userId); - User user2 = UserService.GetUser(otherId); - UserManager.RemoveFriend(user1, user2); - UserService.SaveUser(user1); - UserService.SaveUser(user2); - } - - @Override - public BankAccountResult addBankAccount(int userId, BankAccount bankAccount) { - try { - User user = UserService.GetUser(userId); - UserManager.AddBankAccount(user, bankAccount); - UserService.SaveUser(user); - BankAccountService.UpdateAccount(bankAccount); - return new BankAccountResult.Success(); - } catch (Exception e) { - return new BankAccountResult.BankAccountCreationError(e.getMessage()); - } - } - - @Override - public BankAccountResult RemoveBankAccount(int userId, BankAccount bankAccount) { - try { - User user = UserService.GetUser(userId); - UserManager.RemoveBankAccount(user, bankAccount); - UserService.SaveUser(user); - BankAccountService.UpdateAccount(bankAccount); - return new BankAccountResult.Success(); - } catch (Exception e) { - return new BankAccountResult.BankAccountDeletionError(e.getMessage()); - } - } - - @Override - public OperationResult CheckBalance(int userId, int accountId) { - BankAccount account = BankAccountService.GetAccount(accountId); - if (account == null || account.getUser().getId() != userId) { - return new OperationResult.OperationError("Счет не найден или принадлежит другому пользователю."); - } - System.out.println("Баланс счета: " + account.getBalance()); - return new OperationResult.Success(); - } - - @Override - public OperationResult Deposit(BankAccount bankAccount, Double amount) { - try { - BankAccountService.Deposit(bankAccount.getId(), amount); - OperationService.SaveOperation(new Operation(bankAccount, OperationType.Deposit, amount)); - return new OperationResult.Success(); - } catch (Exception e) { - return new OperationResult.OperationError(e.getMessage()); - } - } - - @Override - public OperationResult Withdraw(BankAccount bankAccount, Double amount) { - try { - boolean success = BankAccountService.Withdraw(bankAccount.getId(), amount); - if (!success) { - return new OperationResult.OperationError("Not enough balance."); - } - OperationService.SaveOperation(new Operation(bankAccount, OperationType.Withdraw, amount)); - return new OperationResult.Success(); - } catch (Exception e) { - return new OperationResult.OperationError(e.getMessage()); - } - } - - @Override - public OperationResult Transfer(BankAccount bankAccount1, BankAccount bankAccount2, Double amount) { - try { - User user1 = UserService.GetUser(bankAccount1.getUser().getId()); - User user2 = UserService.GetUser(bankAccount2.getUser().getId()); - - double commissionRate = user1.getId().equals(user2.getId()) ? 0.00 - : user1.getFriends().stream().anyMatch(f -> f.getId().equals(user2.getId())) ? 0.03 - : 0.10; - double commission = amount * commissionRate; - double totalAmount = amount + commission; - - boolean success = BankAccountService.Transfer(bankAccount1.getId(), bankAccount2.getId(), totalAmount); - if (!success) { - return new OperationResult.OperationError("Insufficient funds, including commission."); - } - - OperationService.SaveOperation(new Operation(bankAccount1, OperationType.Transfer, totalAmount)); - OperationService.SaveOperation(new Operation(bankAccount2, OperationType.Deposit, amount)); - - return new OperationResult.Success(); - } catch (Exception e) { - return new OperationResult.OperationError(e.getMessage()); - } - } - - @Override - public OperationResult GetOperationHistory(int bankAccountId) { - try { - BankAccount account = BankAccountService.GetAccount(bankAccountId); - List operations = OperationService.FindAllOperationsByAccountId(account.getId()); - return UserManager.PrintHistory(account, operations); - } catch (Exception e) { - e.printStackTrace(); - return new OperationResult.OperationError(e.getMessage()); - } - } - -} diff --git a/Presentation/src/main/java/Presentation/Controllers/UserDTOController.java b/Presentation/src/main/java/Presentation/Controllers/UserDTOController.java new file mode 100644 index 0000000..b008660 --- /dev/null +++ b/Presentation/src/main/java/Presentation/Controllers/UserDTOController.java @@ -0,0 +1,96 @@ +package Presentation.Controllers; + +import Application.Models.Entities.User; +import Application.ResultTypes.UserResult; +import Presentation.DTO.UserDTO; +import Presentation.Interfaces.IBaseController; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +@RestController +@RequestMapping("/users") +public class UserDTOController { + + private final IBaseController baseController; + + @Autowired + public UserDTOController(IBaseController baseController) { + this.baseController = baseController; + } + + @Operation(summary = "Получить пользователя по ID", description = "Получает информацию о пользователе по ID") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Пользователь найден", content = @Content(mediaType = "application/json", schema = @Schema(implementation = UserDTO.class))), + @ApiResponse(responseCode = "404", description = "Пользователь не найден") + }) + @GetMapping("/{id}") + public ResponseEntity getUserById(@Parameter(description = "ID пользователя") @PathVariable int id) { + User user = baseController.GetUserById(id); + if (user == null) { + return ResponseEntity.notFound().build(); + } + return ResponseEntity.ok(new UserDTO(user)); + } + + @Operation(summary = "Создать нового пользователя", description = "Создает нового пользователя") + @ApiResponses(value = { + @ApiResponse(responseCode = "201", description = "Пользователь создан"), + @ApiResponse(responseCode = "400", description = "Некорректные данные") + }) + @PostMapping + public ResponseEntity createUser(@RequestBody User user) { + UserResult result = baseController.CreateUser(user); + if (result instanceof UserResult.Success) { + return ResponseEntity.status(HttpStatus.CREATED).body(result); + } else { + return ResponseEntity.badRequest().body(result); + } + } + + @Operation(summary = "Обновить данные пользователя", description = "Обновляет данные о пользователе по ID") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Пользователь обновлен", content = @Content(mediaType = "application/json", schema = @Schema(implementation = UserDTO.class))), + @ApiResponse(responseCode = "404", description = "Пользователь не найден"), + @ApiResponse(responseCode = "400", description = "Некорректные данные") + }) + @PutMapping("/{id}") + public ResponseEntity updateUser(@Parameter(description = "ID пользователя") @PathVariable int id, @RequestBody User user) { + User existingUser = baseController.GetUserById(id); + if (existingUser == null) { + return ResponseEntity.notFound().build(); + } + UserResult result = baseController.UpdateUser(user); + if (result instanceof UserResult.Success) { + return ResponseEntity.ok(new UserDTO(user)); + } else { + return ResponseEntity.badRequest().body(result); + } + } + + @Operation(summary = "Удалить пользователя", description = "Удаляет пользователя по ID") + @ApiResponses(value = { + @ApiResponse(responseCode = "204", description = "Пользователь удален"), + @ApiResponse(responseCode = "404", description = "Пользователь не найден") + }) + @DeleteMapping("/{id}") + public ResponseEntity deleteUser(@Parameter(description = "ID пользователя") @PathVariable int id) { + User user = baseController.GetUserById(id); + if (user == null) { + return ResponseEntity.notFound().build(); + } + UserResult result = baseController.DeleteUser(user); + if (result instanceof UserResult.Success) { + return ResponseEntity.noContent().build(); + } else { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(result); + } + } +} \ No newline at end of file diff --git a/Presentation/src/main/java/Presentation/Controllers/UserDataController.java b/Presentation/src/main/java/Presentation/Controllers/UserDataController.java new file mode 100644 index 0000000..d60c6f7 --- /dev/null +++ b/Presentation/src/main/java/Presentation/Controllers/UserDataController.java @@ -0,0 +1,102 @@ +package Presentation.Controllers; + +import Application.Models.Entities.BankAccount; +import Application.Models.Entities.User; +import Application.Models.Enums.HairColor; +import Application.Models.Enums.OperationType; +import Application.Models.Enums.Sex; +import Presentation.DTO.BankAccountDTO; +import Presentation.DTO.OperationDTO; +import Presentation.DTO.UserDTO; +import Presentation.Interfaces.IBaseController; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.media.Content; +import io.swagger.v3.oas.annotations.media.Schema; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@RestController +@RequestMapping("/data") +public class UserDataController { + + private final IBaseController baseController; + + @Autowired + public UserDataController(IBaseController baseController) { + this.baseController = baseController; + } + + @Operation(summary = "Получить всех пользователей с фильтрами", description = "Возвращает список пользователей, отфильтрованных по полу и цвету волос") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Список пользователей", content = @Content(mediaType = "application/json", schema = @Schema(implementation = UserDTO.class))), + @ApiResponse(responseCode = "400", description = "Некорректные параметры запроса") + }) + @GetMapping("/users") + public ResponseEntity> getAllUsersFiltered( + @Parameter(description = "Пол пользователя") @RequestParam(required = false) Sex sex, + @Parameter(description = "Цвет волос пользователя") @RequestParam(required = false) HairColor hairColor + ) { + List users = baseController.GetAllUsersFiltered(sex, hairColor); + List dtos = users.stream().map(UserDTO::new).toList(); + return ResponseEntity.ok(dtos); + } + + @Operation(summary = "Получить друзей пользователя", description = "Возвращает список друзей по ID пользователя") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Список друзей", content = @Content(mediaType = "application/json", schema = @Schema(implementation = UserDTO.class))), + @ApiResponse(responseCode = "404", description = "Пользователь не найден"), + @ApiResponse(responseCode = "400", description = "Некорректный ID пользователя") + }) + @GetMapping("/users/{id}/friends") + public ResponseEntity> getFriends(@Parameter(description = "ID пользователя") @PathVariable int id) { + List friends = baseController.GetFriends(id); + List dtos = friends.stream().map(UserDTO::new).toList(); + return ResponseEntity.ok(dtos); + } + + @Operation(summary = "Получить банковские счета пользователя", description = "Возвращает все банковские счета, принадлежащие пользователю по ID") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Список счетов", content = @Content(mediaType = "application/json", schema = @Schema(implementation = BankAccountDTO.class))), + @ApiResponse(responseCode = "404", description = "Пользователь не найден"), + @ApiResponse(responseCode = "400", description = "Некорректный ID пользователя") + }) + @GetMapping("/users/{id}/accounts") + public ResponseEntity> getAccountsByUser(@Parameter(description = "ID пользователя") @PathVariable int id) { + List accounts = baseController.GetUserBankAccounts(id); + List dtos = accounts.stream().map(BankAccountDTO::new).toList(); + return ResponseEntity.ok(dtos); + } + + @Operation(summary = "Получить все банковские счета", description = "Возвращает список всех банковских счетов в системе") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Список счетов", content = @Content(mediaType = "application/json", schema = @Schema(implementation = BankAccountDTO.class))), + @ApiResponse(responseCode = "400", description = "Ошибка при обработке запроса") + }) + @GetMapping("/accounts") + public ResponseEntity> getAllAccounts() { + List accounts = baseController.GetAllAccounts(); + List dtos = accounts.stream().map(BankAccountDTO::new).toList(); + return ResponseEntity.ok(dtos); + } + + @Operation(summary = "Получить операции (транзакции)", description = "Возвращает список операций с фильтрацией по типу и ID счета") + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Список операций", content = @Content(mediaType = "application/json", schema = @Schema(implementation = OperationDTO.class))), + @ApiResponse(responseCode = "400", description = "Некорректные параметры запроса") + }) + @GetMapping("/operations") + public ResponseEntity> getTransactions( + @Parameter(description = "Тип операции (Deposit, Withdraw, Transfer)") @RequestParam(required = false) OperationType type, + @Parameter(description = "ID банковского счета") @RequestParam(required = false) Integer accountId + ) { + List txs = baseController.GetFilteredOperations(type, accountId); + List dtos = txs.stream().map(OperationDTO::new).toList(); + return ResponseEntity.ok(dtos); + } +} diff --git a/Presentation/src/main/java/Presentation/DTO/BankAccountDTO.java b/Presentation/src/main/java/Presentation/DTO/BankAccountDTO.java new file mode 100644 index 0000000..6039bc6 --- /dev/null +++ b/Presentation/src/main/java/Presentation/DTO/BankAccountDTO.java @@ -0,0 +1,21 @@ +package Presentation.DTO; + +import Application.Models.Entities.BankAccount; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class BankAccountDTO { + private final Integer id; + private final Double balance; + private final String userLogin; + private final Integer userId; + + public BankAccountDTO(BankAccount account) { + this.id = account.getId(); + this.balance = account.getBalance(); + this.userLogin = account.getUserLogin(); + this.userId = account.getUser() != null ? account.getUser().getId() : null; + } +} diff --git a/Presentation/src/main/java/Presentation/DTO/OperationDTO.java b/Presentation/src/main/java/Presentation/DTO/OperationDTO.java new file mode 100644 index 0000000..b1a3408 --- /dev/null +++ b/Presentation/src/main/java/Presentation/DTO/OperationDTO.java @@ -0,0 +1,22 @@ +package Presentation.DTO; + +import Application.Models.Entities.Operation; +import Application.Models.Enums.OperationType; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class OperationDTO { + private final Integer id; + private final OperationType type; + private final Double amount; + private final Integer accountId; + + public OperationDTO(Operation operation) { + this.id = operation.getId(); + this.amount = operation.getAmount(); + this.type = OperationType.valueOf(operation.getType()); + this.accountId = operation.getBankAccount().getId(); + } +} diff --git a/Presentation/src/main/java/Presentation/DTO/UserDTO.java b/Presentation/src/main/java/Presentation/DTO/UserDTO.java new file mode 100644 index 0000000..acbe7b5 --- /dev/null +++ b/Presentation/src/main/java/Presentation/DTO/UserDTO.java @@ -0,0 +1,39 @@ +package Presentation.DTO; + +import Application.Models.Entities.BankAccount; +import Application.Models.Entities.User; +import Application.Models.Enums.HairColor; +import Application.Models.Enums.Sex; +import lombok.AllArgsConstructor; +import lombok.Getter; + +import java.util.List; +import java.util.stream.Collectors; + +@Getter +@AllArgsConstructor +public class UserDTO { + private final Integer id; + private final String login; + private final String name; + private final Integer age; + private final Sex sex; + private final HairColor hairType; + private final List friendIds; + private final List bankAccountIds; + + public UserDTO(User user) { + this.id = user.getId(); + this.login = user.getLogin(); + this.name = user.getName(); + this.age = user.getAge(); + this.sex = user.getSex(); + this.hairType = user.getHairType(); + this.friendIds = user.getFriends().stream() + .map(User::getId) + .collect(Collectors.toList()); + this.bankAccountIds = user.getBankAccounts().stream() + .map(BankAccount::getId) + .collect(Collectors.toList()); + } +} diff --git a/Presentation/src/main/java/Presentation/Interfaces/IBaseController.java b/Presentation/src/main/java/Presentation/Interfaces/IBaseController.java new file mode 100644 index 0000000..7a50acc --- /dev/null +++ b/Presentation/src/main/java/Presentation/Interfaces/IBaseController.java @@ -0,0 +1,58 @@ +package Presentation.Interfaces; + +import Application.Models.Entities.Operation; +import Application.Models.Enums.HairColor; +import Application.Models.Enums.OperationType; +import Application.Models.Enums.Sex; +import Application.ResultTypes.BankAccountResult; +import Application.ResultTypes.OperationResult; +import Application.ResultTypes.UserResult; +import Application.Models.Entities.BankAccount; +import Application.Models.Entities.User; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +public interface IBaseController { + + UserResult CreateUser(User user); + + UserResult UpdateUser(User user); + + User GetUserById(int id); + + List GetAllUsersFiltered(Sex sex, HairColor color); + + List GetFriends(int userId); + + List GetUserBankAccounts(int userId); + + List GetAllAccounts(); + + List GetFilteredOperations(OperationType type, Integer accountId); + + BankAccount GetBankAccountById(int id); + + UserResult DeleteUser(User user); + + void AddFriend(int userId, int otherId); + + void RemoveFriend(int userId, int otherId); + + BankAccountResult AddBankAccount(int userId, BankAccount bankAccount); + + BankAccountResult UpdateBankAccount(BankAccount bankAccount); + + BankAccountResult RemoveBankAccount(int userId, BankAccount bankAccount); + + OperationResult CheckBalance(int userId, int bankAccountId); + + OperationResult Deposit(BankAccount bankAccount, Double amount); + + OperationResult Withdraw(BankAccount bankAccount, Double amount); + + OperationResult Transfer(BankAccount bankAccount1, BankAccount bankAccount2, Double amount); + + UserResult DeleteUserById(int id); +} diff --git a/Presentation/src/main/java/Presentation/Interfaces/IMenu.java b/Presentation/src/main/java/Presentation/Interfaces/IMenu.java index 592e4d8..869abd7 100644 --- a/Presentation/src/main/java/Presentation/Interfaces/IMenu.java +++ b/Presentation/src/main/java/Presentation/Interfaces/IMenu.java @@ -1,14 +1,5 @@ package Presentation.Interfaces; -/** - * Интерфейс для меню пользовательского интерфейса в консоли. - * Обеспечивает базовый контракт для запуска меню. - */ public interface IMenu { - - /** - * Запускает отображение и обработку логики меню. - * Отображает доступные опции и обрабатывает пользовательский ввод. - */ void Run(); } diff --git a/Presentation/src/main/java/Presentation/Interfaces/IUserController.java b/Presentation/src/main/java/Presentation/Interfaces/IUserController.java deleted file mode 100644 index a59ac15..0000000 --- a/Presentation/src/main/java/Presentation/Interfaces/IUserController.java +++ /dev/null @@ -1,133 +0,0 @@ -package Presentation.Interfaces; - -import Application.ResultTypes.BankAccountResult; -import Application.ResultTypes.OperationResult; -import Application.ResultTypes.UserResult; -import Application.Models.Entities.BankAccount; -import Application.Models.Entities.User; - -/** - * Интерфейс, предоставляющий операции для управления пользователями и их банковскими счетами. - * Включает методы для создания, удаления пользователей, управления их друзьями и банковскими счетами, - * а также выполнения различных операций с банковскими счетами. - */ -public interface IUserController { - - /** - * Создание нового пользователя. - * - * @param user объект пользователя, который должен быть создан. - * @return результат операции создания пользователя. - */ - UserResult CreateUser(User user); - - /** - * Создание нового пользователя. - * - * @param id идентификатор пользователя, который должен быть найден. - * @return результат операции поиска пользователя. - */ - User GetUserById(int id); - - /** - * Создание нового пользователя. - * - * @param id идентификатор аккаунта, который должен быть найден. - * @return результат операции поиска аккаунта. - */ - BankAccount GetBankAccountById(int id); - - /** - * Удаление пользователя. - * - * @param user объект пользователя, который должен быть удален. - * @return результат операции удаления пользователя. - */ - UserResult DeleteUser(User user); - - /** - * Получение информации о пользователе. - * - * @param id идентификатор пользователя, информацию о котором необходимо получить. - */ - void GetUserInfo(int id); - - /** - * Добавление пользователя в друзья. - * - * @param userId идентификатор текущего пользователя. - * @param otherId идентификатор пользователя, которого нужно добавить в друзья. - */ - void AddFriend(int userId, int otherId); - - /** - * Удаление пользователя из списка друзей. - * - * @param userId идентификатор текущего пользователя. - * @param otherId идентификатор пользователя, которого нужно удалить из друзей. - */ - void RemoveFriend(int userId, int otherId); - - /** - * Добавление нового банковского счета пользователю. - * - * @param userId идентификатор пользователя, которому нужно добавить банковский счет. - * @param bankAccount объект банковского счета, который нужно добавить. - * @return результат операции добавления банковского счета. - */ - BankAccountResult addBankAccount(int userId, BankAccount bankAccount); - - /** - * Удаление банковского счета пользователя. - * - * @param userId идентификатор пользователя, чей банковский счет должен быть удален. - * @param bankAccount объект банковского счета, который нужно удалить. - * @return результат операции удаления банковского счета. - */ - BankAccountResult RemoveBankAccount(int userId, BankAccount bankAccount); - - /** - * Проверка баланса банковского счета пользователя. - * - * @param userId идентификатор пользователя, чей баланс нужно проверить. - * @param bankAccountId объект банковского счета, баланс которого нужно проверить. - * @return результат операции проверки баланса. - */ - OperationResult CheckBalance(int userId, int bankAccountId); - - /** - * Пополнение банковского счета. - * - * @param bankAccount объект банковского счета, на который нужно пополнить средства. - * @param amount сумма, которую нужно внести на счет. - * @return результат операции пополнения. - */ - OperationResult Deposit(BankAccount bankAccount, Double amount); - - /** - * Снятие средств с банковского счета. - * - * @param bankAccount объект банковского счета, с которого нужно снять средства. - * @param amount сумма, которую нужно снять со счета. - * @return результат операции снятия средств. - */ - OperationResult Withdraw(BankAccount bankAccount, Double amount); - - /** - * Перевод средств между двумя банковскими счетами. - * - * @param bankAccount1 объект исходного банковского счета. - * @param bankAccount2 объект целевого банковского счета. - * @param amount сумма, которую нужно перевести. - * @return результат операции перевода. - */ - OperationResult Transfer(BankAccount bankAccount1, BankAccount bankAccount2, Double amount); - - /** - * Получение истории операций для конкретного банковского счета. - * - * @param bankAccountId идентификатор банковского счета, для которого нужно получить историю операций. - * @return результат операции получения истории. - */ - OperationResult GetOperationHistory(int bankAccountId); -} diff --git a/Presentation/src/main/resources/application.yml b/Presentation/src/main/resources/application.yml index 204317a..d1ec292 100644 --- a/Presentation/src/main/resources/application.yml +++ b/Presentation/src/main/resources/application.yml @@ -1,9 +1,9 @@ spring: datasource: - url: jdbc:postgresql://localhost:5432/JavaLabsDb - username: postgres - password: limosha + url: ${DB_URL} + username: ${DB_USERNAME} + password: ${DB_PASSWORD} flyway: enabled: true locations: classpath:db/migration - baseline-on-migrate: true \ No newline at end of file + baseline-on-migrate: true diff --git a/Presentation/src/main/resources/db/migration/V1__init.sql b/Presentation/src/main/resources/db/migration/V1__init.sql index 26dd68f..6818625 100644 --- a/Presentation/src/main/resources/db/migration/V1__init.sql +++ b/Presentation/src/main/resources/db/migration/V1__init.sql @@ -1,32 +1,40 @@ -CREATE TABLE Users -( - id SERIAL PRIMARY KEY, - login VARCHAR(255) UNIQUE NOT NULL, - name VARCHAR(255) NOT NULL, - age INT NOT NULL, - sex VARCHAR(255) NOT NULL, - hairColor VARCHAR(255) +CREATE SEQUENCE IF NOT EXISTS bankaccounts_id_seq START WITH 1 INCREMENT BY 1; +CREATE SEQUENCE IF NOT EXISTS operations_id_seq START WITH 1 INCREMENT BY 1; +CREATE SEQUENCE IF NOT EXISTS users_id_seq START WITH 1 INCREMENT BY 1; + +CREATE TABLE users ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL, + login VARCHAR(255) NOT NULL, + name VARCHAR(255) NOT NULL, + age INTEGER NOT NULL, + sex VARCHAR(255) NOT NULL, + haircolor VARCHAR(255), + CONSTRAINT users_pkey PRIMARY KEY (id), + CONSTRAINT users_login_key UNIQUE (login) ); -CREATE TABLE BankAccounts -( - id SERIAL PRIMARY KEY, - balance DOUBLE PRECISION NOT NULL, - userLogin VARCHAR(255) NOT NULL, - userId INT NOT NULL REFERENCES Users (id) +CREATE TABLE bankaccounts ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL, + balance DOUBLE PRECISION NOT NULL, + userlogin VARCHAR(255) NOT NULL, + user_id INTEGER NOT NULL, + CONSTRAINT bankaccounts_pkey PRIMARY KEY (id), + CONSTRAINT bankaccounts_userid_fkey FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE NO ACTION ); -CREATE TABLE Operations -( - id SERIAL PRIMARY KEY, - accountId INT NOT NULL REFERENCES BankAccounts (id), - type VARCHAR(255) NOT NULL, - amount DOUBLE PRECISION NOT NULL +CREATE TABLE operations ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL, + account_id INTEGER NOT NULL, + type VARCHAR(255) NOT NULL, + amount DOUBLE PRECISION NOT NULL, + CONSTRAINT operations_pkey PRIMARY KEY (id), + CONSTRAINT operations_accountid_fkey FOREIGN KEY (account_id) REFERENCES bankaccounts (id) ON DELETE NO ACTION ); -CREATE TABLE Friends -( - userId INT NOT NULL REFERENCES Users (id), - friendId INT NOT NULL REFERENCES Users (id), - PRIMARY KEY (userId, friendId) -); \ No newline at end of file +CREATE TABLE friends ( + user_id INTEGER NOT NULL, + friend_id INTEGER NOT NULL, + CONSTRAINT friends_pkey PRIMARY KEY (user_id, friend_id), + CONSTRAINT friends_userid_fkey FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE NO ACTION, + CONSTRAINT friends_friendid_fkey FOREIGN KEY (friend_id) REFERENCES users (id) ON DELETE NO ACTION +); diff --git a/Presentation/src/main/resources/db/migration/V2__drop.sql b/Presentation/src/main/resources/db/migration/V2__drop.sql new file mode 100644 index 0000000..85e8be5 --- /dev/null +++ b/Presentation/src/main/resources/db/migration/V2__drop.sql @@ -0,0 +1,4 @@ +DROP TABLE friends; +DROP TABLE operations; +DROP TABLE bankaccounts; +DROP TABLE users; \ No newline at end of file diff --git a/Presentation/src/main/resources/db/migration/V2__drop_tables.sql b/Presentation/src/main/resources/db/migration/V2__drop_tables.sql deleted file mode 100644 index ea5d75d..0000000 --- a/Presentation/src/main/resources/db/migration/V2__drop_tables.sql +++ /dev/null @@ -1,4 +0,0 @@ -DROP TABLE Friends; -DROP TABLE Operations; -DROP TABLE BankAccounts; -DROP TABLE Users; diff --git a/Presentation/src/main/resources/db/migration/V3__init.sql b/Presentation/src/main/resources/db/migration/V3__init.sql deleted file mode 100644 index 01d855f..0000000 --- a/Presentation/src/main/resources/db/migration/V3__init.sql +++ /dev/null @@ -1,56 +0,0 @@ -CREATE SEQUENCE IF NOT EXISTS bankaccounts_id_seq START WITH 1 INCREMENT BY 1; - -CREATE SEQUENCE IF NOT EXISTS operations_id_seq START WITH 1 INCREMENT BY 1; - -CREATE SEQUENCE IF NOT EXISTS users_id_seq START WITH 1 INCREMENT BY 1; - -CREATE TABLE bankaccounts -( - id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL, - balance DOUBLE PRECISION NOT NULL, - userlogin VARCHAR(255) NOT NULL, - userid INTEGER NOT NULL, - CONSTRAINT bankaccounts_pkey PRIMARY KEY (id) -); - -CREATE TABLE friends -( - userid INTEGER NOT NULL, - friendid INTEGER NOT NULL, - CONSTRAINT friends_pkey PRIMARY KEY (userid, friendid) -); - -CREATE TABLE operations -( - id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL, - accountid INTEGER NOT NULL, - type VARCHAR(255) NOT NULL, - amount DOUBLE PRECISION NOT NULL, - CONSTRAINT operations_pkey PRIMARY KEY (id) -); - -CREATE TABLE users -( - id INTEGER GENERATED BY DEFAULT AS IDENTITY NOT NULL, - login VARCHAR(255) NOT NULL, - name VARCHAR(255) NOT NULL, - age INTEGER NOT NULL, - sex VARCHAR(255) NOT NULL, - haircolor VARCHAR(255), - CONSTRAINT users_pkey PRIMARY KEY (id) -); - -ALTER TABLE users - ADD CONSTRAINT users_login_key UNIQUE (login); - -ALTER TABLE bankaccounts - ADD CONSTRAINT bankaccounts_userid_fkey FOREIGN KEY (userid) REFERENCES users (id) ON DELETE NO ACTION; - -ALTER TABLE friends - ADD CONSTRAINT friends_friendid_fkey FOREIGN KEY (friendid) REFERENCES users (id) ON DELETE NO ACTION; - -ALTER TABLE friends - ADD CONSTRAINT friends_userid_fkey FOREIGN KEY (userid) REFERENCES users (id) ON DELETE NO ACTION; - -ALTER TABLE operations - ADD CONSTRAINT operations_accountid_fkey FOREIGN KEY (accountid) REFERENCES bankaccounts (id) ON DELETE NO ACTION; \ No newline at end of file diff --git a/Presentation/src/test/java/BankTests.java b/Presentation/src/test/java/BankTests.java index a1b0b16..9b3466f 100644 --- a/Presentation/src/test/java/BankTests.java +++ b/Presentation/src/test/java/BankTests.java @@ -4,56 +4,58 @@ import Application.Models.Entities.User; import Application.Models.Enums.HairColor; import Application.Models.Enums.Sex; -import Presentation.Controllers.UserController; -import Services.BankAccountService; -import Services.OperationService; -import Services.UserService; -import org.junit.jupiter.api.BeforeEach; +import DataAccess.Services.BankAccountService; +import DataAccess.Services.Interfaces.IUserService; +import DataAccess.Services.OperationService; +import Presentation.Controllers.*; +import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; -import org.mockito.MockitoAnnotations; +import org.mockito.junit.jupiter.MockitoExtension; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.mockito.Mockito.*; +@ExtendWith(MockitoExtension.class) public class BankTests { @Mock - private UserManager userManager; + private BankAccountService bankAccountService; @Mock - private UserService userService; + private OperationService operationService; @Mock - private BankAccountService bankAccountService; + private UserManager userManager; @Mock - private OperationService operationService; + private IUserService userService; @InjectMocks - private UserController userController; + private BaseController baseController; - private BankAccount bankAccount; - private User user; + private static BankAccount bankAccount; + private static User user; - @BeforeEach - void setUp() { - MockitoAnnotations.initMocks(this); + @BeforeAll + static void init() { user = new User("lim0sha", "Sasha", 22, Sex.Male, HairColor.Brown); bankAccount = new BankAccount(user); bankAccount.setId(1); bankAccount.setBalance(100.0); } + @Test - void testWithdrawWithSufficientBalance() { + public void testWithdrawWithSufficientBalance() { double withdrawAmount = 50.0; when(bankAccountService.Withdraw(bankAccount.getId(), withdrawAmount)).thenReturn(true); doNothing().when(operationService).SaveOperation(any()); - OperationResult operationResult = userController.Withdraw(bankAccount, withdrawAmount); + OperationResult operationResult = baseController.Withdraw(bankAccount, withdrawAmount); assertInstanceOf(OperationResult.Success.class, operationResult); verify(bankAccountService, times(1)).Withdraw(bankAccount.getId(), withdrawAmount); @@ -61,25 +63,25 @@ void testWithdrawWithSufficientBalance() { } @Test - void testWithdrawWithInsufficientBalance() { + public void testWithdrawWithInsufficientBalance() { double withdrawAmount = 150.0; when(bankAccountService.Withdraw(bankAccount.getId(), withdrawAmount)).thenReturn(false); - OperationResult operationResult = userController.Withdraw(bankAccount, withdrawAmount); + OperationResult operationResult = baseController.Withdraw(bankAccount, withdrawAmount); assertInstanceOf(OperationResult.OperationError.class, operationResult); assertEquals("Not enough balance.", ((OperationResult.OperationError) operationResult).getMessage()); verify(bankAccountService, times(1)).Withdraw(bankAccount.getId(), withdrawAmount); - verify(operationService, times(0)).SaveOperation(any()); // SaveOperation не должен вызываться + verify(operationService, times(0)).SaveOperation(any()); } @Test - void testDeposit() { + public void testDeposit() { double depositAmount = 100.0; when(bankAccountService.Deposit(bankAccount.getId(), depositAmount)).thenReturn(true); doNothing().when(operationService).SaveOperation(any()); - OperationResult operationResult = userController.Deposit(bankAccount, depositAmount); + OperationResult operationResult = baseController.Deposit(bankAccount, depositAmount); assertInstanceOf(OperationResult.Success.class, operationResult); verify(bankAccountService, times(1)).Deposit(bankAccount.getId(), depositAmount); diff --git a/pom.xml b/pom.xml index b718579..3b6964c 100644 --- a/pom.xml +++ b/pom.xml @@ -5,9 +5,28 @@ com.example lim0sha 1.0-SNAPSHOT + + + 2.0 + + pom + + org.springframework.boot + spring-boot-starter-parent + 3.4.4 + + + + + io.github.cdimascio + dotenv-java + 3.0.0 + + + org.hibernate hibernate-core @@ -20,24 +39,57 @@ 4.3.0.Beta3 - - org.postgresql - postgresql - 42.7.2 - - net.bytebuddy byte-buddy 1.14.7 + + + org.postgresql + postgresql + 42.7.2 + + + org.flywaydb flyway-core 9.22.0 + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + + org.springframework.boot + spring-boot-starter-validation + + + + + org.springframework.boot + spring-boot-starter-actuator + + + + + org.springframework.boot + spring-boot-starter-test + test + +