diff --git a/pom.xml b/pom.xml
index bc89875..97e8c14 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,20 +21,20 @@
org.springframework.boot
spring-boot-starter-data-jpa
+
+ org.springframework.boot
+ spring-boot-starter-validation
+ 2.7.1
+
com.auth0
java-jwt
4.0.0
- javax.validation
- validation-api
- 2.0.1.Final
-
-
- org.hibernate.validator
- hibernate-validator
- 7.0.5.Final
+ org.liquibase
+ liquibase-core
+ 4.16.0
org.springframework.boot
@@ -54,6 +54,10 @@
javax.servlet-api
provided
+
+ org.codehaus.groovy
+ groovy
+
io.projectreactor
reactor-test
@@ -159,7 +163,15 @@
-
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 17
+ 17
+
+
+
-
\ No newline at end of file
+
diff --git a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/CorsConfiguration.java b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/CorsConfiguration.java
new file mode 100644
index 0000000..477a4c7
--- /dev/null
+++ b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/CorsConfiguration.java
@@ -0,0 +1,37 @@
+package com.github.WeeiaEduTeam.InfinityFinanceAPI;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+class CorsConfiguration {
+
+ @Value("${management.endpoints.web.cors.mapping-pattern}")
+ private String mappingPattern;
+
+ @Value("${management.endpoints.web.cors.allowed-methods}")
+ private String allowedMethods;
+
+ @Value("${management.endpoints.web.cors.allowed-headers}")
+ private String allowedHeaders;
+
+ @Value("${management.endpoints.web.cors.allowed-origins}")
+ private String allowedOrigins;
+
+ @Bean
+ public WebMvcConfigurer corsConfigurer() {
+ return new WebMvcConfigurer() {
+ @Override
+ public void addCorsMappings(CorsRegistry registry) {
+ registry.addMapping("/**")
+ .allowedOrigins("http://localhost:3000")
+ .allowedMethods("GET", "POST", "PUT", "DELETE", "PATCH")
+ .allowedHeaders("*")
+ .allowCredentials(true);
+ }
+ };
+ }
+}
diff --git a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/InfinityFinanceApiApplication.java b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/InfinityFinanceApiApplication.java
index 6c42943..d9d7610 100644
--- a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/InfinityFinanceApiApplication.java
+++ b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/InfinityFinanceApiApplication.java
@@ -1,12 +1,16 @@
package com.github.WeeiaEduTeam.InfinityFinanceAPI;
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.role.RoleType;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Configuration;
+import java.util.Arrays;
+import java.util.stream.Collectors;
+
@Configuration
@SpringBootApplication
-public class InfinityFinanceApiApplication {
+class InfinityFinanceApiApplication {
public static void main(String[] args) {
SpringApplication.run(InfinityFinanceApiApplication.class, args);
diff --git a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/AppUser.java b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/AppUser.java
index 66a7aac..eb45b70 100644
--- a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/AppUser.java
+++ b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/AppUser.java
@@ -25,25 +25,25 @@ public class AppUser implements UserDetails {
@Column(name = "user_id")
private Long id;
- //@Column(unique = true)
+ @Column(unique = true)
private String username;
- //@Column(unique = true)
+ @Column(unique = true)
private String email;
private String password;
private String firstName;
private String secondName;
-
-
- @ManyToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
- @JoinTable(name="user_roles",
+
+ @ManyToMany(fetch = FetchType.LAZY)
+ @JoinTable(name = "user_roles",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "role_id")
)
private List roles = new ArrayList<>();
+ @JsonIgnore
@OneToMany(mappedBy = "appuser")
private List transactions = new ArrayList<>();
diff --git a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/AppUserAdminController.java b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/AppUserAdminController.java
new file mode 100644
index 0000000..dbbab17
--- /dev/null
+++ b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/AppUserAdminController.java
@@ -0,0 +1,64 @@
+package com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser;
+
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser.dto.*;
+import lombok.RequiredArgsConstructor;
+import org.springframework.data.domain.Sort;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.net.URI;
+import java.util.List;
+
+@RestController
+@RequiredArgsConstructor
+@RequestMapping(path = "/api/v1")
+class AppUserAdminController {
+
+ private final AppUserAdminService appUserAdminService;
+
+ @GetMapping("/admin/users")
+ public ResponseEntity> getAllUsers(
+ @RequestParam(defaultValue = "0") Integer page,
+ @RequestParam(defaultValue = "ASC") Sort.Direction direction,
+ @RequestParam(defaultValue = "id") String by) {
+
+ var users = appUserAdminService.getAllUsers(page, direction, by);
+
+ return ResponseEntity.ok(users);
+ }
+
+ @GetMapping("/admin/users/{userId:[0-9]+}")
+ public ResponseEntity getSingleUser(@PathVariable long userId) {
+
+ var user = appUserAdminService.getSingleUser(userId);
+
+ return ResponseEntity.ok(user);
+ }
+
+ @PostMapping("/admin/users")
+ ResponseEntity createAccount(@RequestBody CreateAppUserAdminDTO createAppUserAdminDTO) {
+
+ var user = appUserAdminService.createAccount(createAppUserAdminDTO);
+
+ return ResponseEntity.created(URI.create("/users/" + user.getId())).body(user);
+ }
+
+ @DeleteMapping("/admin/users/{userId:[0-9]+}")
+ ResponseEntity deleteAllUsersAndAllRelated(@PathVariable long userId) {
+ appUserAdminService.findAndDeleteUserWithRolesAndTransactions(userId);
+
+ return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
+ }
+
+ @PutMapping("/admin/users/{userId:[0-9]+}")
+ ResponseEntity replaceUserAllDetails(
+ @PathVariable long userId,
+ @RequestBody ReplaceAppUserAllDetailsDTO replaceAppUserAllDetailsDTO) {
+
+ var replacedUser = appUserAdminService.replaceUserAllDetails(userId, replaceAppUserAllDetailsDTO);
+
+ return ResponseEntity.ok(replacedUser);
+ }
+
+}
diff --git a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/AppUserAdminService.java b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/AppUserAdminService.java
new file mode 100644
index 0000000..b92dba6
--- /dev/null
+++ b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/AppUserAdminService.java
@@ -0,0 +1,153 @@
+package com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser;
+
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser.dto.*;
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser.rolestrategy.AppUserRoleStrategyFacade;
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.exception.ResourceNotFoundException;
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.util.CustomPageable;
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.transaction.TransactionAdminService;
+import lombok.extern.slf4j.Slf4j;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.stereotype.Service;
+
+import javax.transaction.Transactional;
+import java.util.List;
+import java.util.function.Function;
+
+@Service
+@Slf4j
+public class AppUserAdminService implements UserDetailsService {
+
+ @Autowired
+ private AppUserRepository appUserRepository;
+ @Autowired
+ private AppUserUtil appUserUtil;
+ @Autowired
+ private AppUserRoleStrategyFacade appUserRoleStrategyFacade;
+ @Autowired
+ private CustomPageable customPageable;
+
+ private TransactionAdminService transactionAdminService;
+
+ public void setTransactionAdminService(TransactionAdminService transactionAdminService) {
+ this.transactionAdminService = transactionAdminService;
+ }
+
+ public AppUser getUserById(long userId) {
+
+ return appUserRepository.findById(userId).orElseThrow(() -> ResourceNotFoundException.createWith("Could not find any user with id " + userId));
+ }
+
+ public AppUser getUserByUserName(String username) {
+ return appUserRepository.findByUsername(username);
+ }
+
+ @Override
+ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
+ return getUserByUserName(username);
+ }
+
+ public Long getLoggedInUserId() {
+ return appUserRepository.getLoggedInUserId().orElseThrow(() -> new UsernameNotFoundException("User not found in the database"));
+ }
+
+ public List getAllUsers(Integer pageNumber, Sort.Direction sortDirection, String sortBy) {
+ Pageable page = validateAndCreatePageable(pageNumber, sortDirection, sortBy);
+
+ var foundUsers = getUsers(page);
+
+ return foundUsers.stream().map(mapToAppUserDTO()).toList();
+ }
+
+ private @NotNull Page getUsers(Pageable page) {
+ return appUserRepository.findAll(page);
+ }
+
+ @NotNull
+ private Function mapToAppUserDTO() {
+ return appUserUtil::mapToAppUserDTO;
+ }
+
+ private Pageable validateAndCreatePageable(int pageNumber, Sort.Direction sortDirection, String sortBy) {
+ return customPageable.validateAndCreatePageable(pageNumber, sortDirection, sortBy, AppUser.class);
+ }
+
+ public AppUserDTO getSingleUser(long userId) {
+ var foundUser = getUserById(userId);
+
+ return mapToAppUserDTO(foundUser);
+ }
+
+ private AppUserDTO mapToAppUserDTO(AppUser foundUser) {
+ return appUserUtil.mapToAppUserDTO(foundUser);
+ }
+
+ public AppUserDTO createAccount(T objectDTO) {
+ AppUser user = createAppUserFromCreateAppUserDTOAndHashPassword(objectDTO);
+
+ setRolesForUser(user, objectDTO);
+
+ user = saveUser(user);
+
+ return mapToAppUserDTO(user);
+ }
+
+ private void setRolesForUser(AppUser user, T objectDTO) {
+ appUserRoleStrategyFacade.addRolesForUser(user, objectDTO);
+ }
+
+
+ private AppUser createAppUserFromCreateAppUserDTOAndHashPassword(T createAppUserDTO) {
+ return appUserUtil.mapToAppUserFactory(createAppUserDTO);
+ }
+ @Transactional
+ public void findAndDeleteUserWithRolesAndTransactions(long userId) {
+ deleteTransactionsRelatedWithUser(userId);
+ deleteUserWithRoles(userId);
+ }
+
+ private void deleteTransactionsRelatedWithUser(long userId) {
+ transactionAdminService.deleteTransactionsRelatedWithUser(userId);
+ }
+
+ private void deleteUserWithRoles(long userId) {
+ var user = getUserById(userId);
+ deleteUser(user);
+ deleteRoleFromUser(user);
+ }
+
+ private void deleteRoleFromUser(AppUser user) {
+ appUserRoleStrategyFacade.removeRoles(user);
+ }
+
+ private void deleteUser(AppUser user) {
+ appUserRepository.delete(user);
+ }
+
+ AppUser saveUser(AppUser user) {
+ return appUserRepository.save(user);
+ }
+
+ @Transactional
+ public AppUserDTO replaceUserAllDetails(long userId, ReplaceAppUserAllDetailsDTO replaceAppUserAllDetailsDTO) {
+ var foundUser = getUserById(userId);
+
+ var overwrittenUser = overwriteAppUserAllDetails(foundUser, replaceAppUserAllDetailsDTO);
+
+ return mapAppUserToAppUserDTO(overwrittenUser);
+ }
+
+ private AppUserDTO mapAppUserToAppUserDTO(AppUser user) {
+ return appUserUtil.mapToAppUserDTO(user);
+ }
+
+ private AppUser overwriteAppUserAllDetails(AppUser foundUser, ReplaceAppUserAllDetailsDTO replaceAppUserAllDetailsDTO) {
+ return appUserUtil.overwriteAppUserAllDetails(foundUser, replaceAppUserAllDetailsDTO);
+ }
+}
diff --git a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/AppUserMapperFactory.java b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/AppUserMapperFactory.java
new file mode 100644
index 0000000..6e49b01
--- /dev/null
+++ b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/AppUserMapperFactory.java
@@ -0,0 +1,116 @@
+package com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser;
+
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser.dto.*;
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.role.Role;
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.role.RoleService;
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.role.dto.RoleDTO;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Component;
+
+import java.util.List;
+
+@Component
+@Slf4j
+public class AppUserMapperFactory {
+
+ @Autowired
+ private PasswordEncoder encoder;
+ @Autowired //INTO MAPPER SOON
+ private RoleService roleService;
+
+ public AppUser mapToAppUserFactory(T dto) {
+ AppUser user = null;
+
+ /* Keep taken dtos higher than others
+ * ReplaceAll details > CreateAdminDTO > CreateUserDTO
+ * because of the inheritance */
+ if(dto instanceof ReplaceAppUserAllDetailsDTO) {
+ user = mapToAppUser((ReplaceAppUserAllDetailsDTO) dto);
+ user.setPassword(hashPassword(((ReplaceAppUserAllDetailsDTO) dto).getPassword()));
+ } else if(dto instanceof CreateAppUserAdminDTO) {
+ user = mapToAppUser((CreateAppUserAdminDTO) dto);
+ user.setPassword(hashPassword(((CreateAppUserAdminDTO) dto).getPassword()));
+ } else if(dto instanceof CreateAppUserUserDTO) {
+ user = mapToAppUser((CreateAppUserUserDTO) dto);
+ user.setPassword(hashPassword(((CreateAppUserUserDTO) dto).getPassword()));
+ } else if(dto instanceof ReplaceAppUserByUserDTO) {
+ user = mapToAppUser((ReplaceAppUserByUserDTO) dto);
+ } else if(dto instanceof AppUserCredentialsDTO) {
+ user = mapToAppUser((AppUserCredentialsDTO) dto);
+ user.setPassword(hashPassword(((AppUserCredentialsDTO) dto).getPassword()));
+ }
+
+ return user;
+ }
+
+ private String hashPassword(String password) {
+ return encoder.encode(password);
+ }
+
+ private AppUser mapToAppUser(ReplaceAppUserAllDetailsDTO dto) {
+
+ return AppUser.builder()
+ .username(dto.getUsername())
+ .password(dto.getPassword())
+ .email(dto.getEmail())
+ .secondName(dto.getSecondName())
+ .firstName(dto.getFirstName())
+ .build();
+ }
+
+ private AppUser mapToAppUser(AppUserCredentialsDTO dto) {
+
+ return AppUser.builder()
+ .username(dto.getUsername())
+ .password(dto.getPassword())
+ .build();
+ }
+
+ private AppUser mapToAppUser(CreateAppUserUserDTO dto) {
+
+ return AppUser.builder()
+ .username(dto.getUsername())
+ .password(dto.getPassword())
+ .email(dto.getEmail())
+ .build();
+ }
+
+ private AppUser mapToAppUser(CreateAppUserAdminDTO dto) {
+
+ return AppUser.builder()
+ .username(dto.getUsername())
+ .email(dto.getEmail())
+ .password(dto.getPassword())
+ .build();
+ }
+
+ private AppUser mapToAppUser(ReplaceAppUserByUserDTO dto) {
+
+ return AppUser.builder()
+ .firstName(dto.getFirstName())
+ .email(dto.getEmail())
+ .secondName(dto.getSecondName())
+ .build();
+ }
+
+ public AppUserDTO mapToAppUserDTO(AppUser appUser) {
+
+ return AppUserDTO.builder()
+ .id(appUser.getId())
+ .username(appUser.getUsername())
+ .email(appUser.getEmail())
+ .firstName(appUser.getFirstName())
+ .secondName(appUser.getSecondName())
+ .roles(mapToRolesDTO(appUser.getRoles()))
+ .build();
+ }
+
+
+ //INTO MAPPER SOON
+
+ private List mapToRolesDTO(List roles) {
+ return roleService.mapToRolesDTO(roles);
+ }
+}
diff --git a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/AppUserRepository.java b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/AppUserRepository.java
index e0f98f4..d066e83 100644
--- a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/AppUserRepository.java
+++ b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/AppUserRepository.java
@@ -1,9 +1,41 @@
package com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.security.authentication.AnonymousAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Repository;
+import java.util.List;
+import java.util.Optional;
+
@Repository
-public interface AppUserRepository extends JpaRepository {
+interface AppUserRepository extends JpaRepository {
+ default Optional getLoggedInUserId() {
+ Authentication auth = SecurityContextHolder.getContext().getAuthentication();
+
+ if (!(auth instanceof AnonymousAuthenticationToken)) {
+ return getIdByUsername(auth.getName());
+ }
+
+ return Optional.empty();
+ }
+
+ @Query("SELECT u.id FROM AppUser u WHERE u.username = :username")
+ Optional getIdByUsername(String username);
+
+ @Query("SELECT u FROM AppUser u JOIN FETCH u.roles WHERE u.username = :username")
AppUser findByUsername(String username);
+
+
+ @Override
+ @Query( value = "FROM AppUser u LEFT JOIN FETCH u.roles", /* avoid n + 1 */
+ countQuery = "SELECT COUNT(u) FROM AppUser u LEFT JOIN u.roles") /* add pageable without n + 1 */
+ @NotNull
+ Page findAll(@NotNull Pageable pageable);
+
}
diff --git a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/AppUserService.java b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/AppUserService.java
deleted file mode 100644
index 89ae40d..0000000
--- a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/AppUserService.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser;
-
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.context.annotation.Bean;
-import org.springframework.security.core.userdetails.UserDetails;
-import org.springframework.security.core.userdetails.UserDetailsService;
-import org.springframework.security.core.userdetails.UsernameNotFoundException;
-import org.springframework.stereotype.Service;
-
-import java.util.Optional;
-
-@Service
-@RequiredArgsConstructor
-@Slf4j
-public class AppUserService implements UserDetailsService {
-
- private final AppUserRepository appUserRepository;
-
- public Optional getUserById(long userId) {
-
- return appUserRepository.findById(userId);
- }
-
- public AppUser getUserByUserName(String username) {
- return appUserRepository.findByUsername(username);
- }
-
- @Override
- public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
- return getUserByUserName(username);
- }
-}
diff --git a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/AppUserUserController.java b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/AppUserUserController.java
new file mode 100644
index 0000000..8f2cff6
--- /dev/null
+++ b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/AppUserUserController.java
@@ -0,0 +1,68 @@
+package com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser;
+
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser.dto.*;
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+
+import java.net.URI;
+
+/*
+ * If you hit the
+ * - DELETE "/users" endpoint
+ * - PUT "/users/credentials" endpoint
+ * make sure that you logout
+ * current user to ensure getting
+ * troubleshoot errors.
+ */
+
+@RestController
+@RequiredArgsConstructor
+@RequestMapping(path = "/api/v1")
+class AppUserUserController {
+
+ private final AppUserUserService appUserUserService;
+
+ @GetMapping("/users")
+ public ResponseEntity getCurrentLoggedUserInformation() {
+
+ var user = appUserUserService.getCurrentLoggedUserInformation();
+
+ return ResponseEntity.ok(user);
+ }
+
+ @PostMapping("/users")
+ ResponseEntity createAccount(@RequestBody CreateAppUserUserDTO createAppUserUserDTO) {
+
+ var user = appUserUserService.createAccount(createAppUserUserDTO);
+
+ return ResponseEntity.created(URI.create("/users/" + user.getId())).body(user);
+ }
+
+ @DeleteMapping("/users")
+ ResponseEntity deleteCurrentLoggedUser() {
+ appUserUserService.deleteCurrentLoggedUser();
+
+ return ResponseEntity.status(HttpStatus.NO_CONTENT).build();
+ }
+
+ @PutMapping("/users/credentials")
+ ResponseEntity replaceUserCredentials(
+ @RequestBody AppUserCredentialsDTO appUserCredentialsDTO) {
+
+ var replacedUser = appUserUserService.replaceUserCredentials(appUserCredentialsDTO);
+
+ return ResponseEntity.ok(replacedUser);
+ }
+
+ @PutMapping("/users/details")
+ ResponseEntity replaceUserDetails(
+ @RequestBody ReplaceAppUserByUserDTO replaceAppUserByUserDTO) {
+
+ var replacedUser = appUserUserService.replaceUserDetails(replaceAppUserByUserDTO);
+
+ return ResponseEntity.ok(replacedUser);
+ }
+
+}
diff --git a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/AppUserUserService.java b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/AppUserUserService.java
new file mode 100644
index 0000000..7a416e2
--- /dev/null
+++ b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/AppUserUserService.java
@@ -0,0 +1,85 @@
+package com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser;
+
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser.dto.AppUserCredentialsDTO;
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser.dto.AppUserDTO;
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser.dto.CreateAppUserUserDTO;
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser.dto.ReplaceAppUserByUserDTO;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+
+@Service
+@Slf4j
+@RequiredArgsConstructor
+public class AppUserUserService {
+
+ private final AppUserAdminService appUserAdminService;
+ private final AppUserUtil appUserUtil;
+
+ public AppUserDTO getCurrentLoggedUserInformation() {
+ long loggedInUserId = getLoggedUserId();
+
+ var user = getUserById(loggedInUserId);
+
+ return mapToAppUserDTO(user);
+ }
+
+ private AppUserDTO mapToAppUserDTO(AppUser user) {
+ return appUserUtil.mapToAppUserDTO(user);
+ }
+
+ private AppUser getUserById(long id) {
+ return appUserAdminService.getUserById(id);
+ }
+
+ private long getLoggedUserId() {
+ return appUserAdminService.getLoggedInUserId();
+ }
+
+ public void deleteCurrentLoggedUser() {
+ long loggedInUserId = getLoggedUserId();
+
+ appUserAdminService.findAndDeleteUserWithRolesAndTransactions(loggedInUserId);
+ }
+
+ public AppUserDTO createAccount(CreateAppUserUserDTO createAppUserUserDTO) {
+ return appUserAdminService.createAccount(createAppUserUserDTO);
+ }
+
+ public AppUserDTO replaceUserCredentials(AppUserCredentialsDTO appUserCredentialsDTO) {
+ long loggedInUserId = getLoggedUserId();
+
+ var foundUser = getUserById(loggedInUserId);
+
+ var overwrittenUser = overwriteAppUserCredentials(foundUser, appUserCredentialsDTO);
+
+ overwrittenUser = saveUser(overwrittenUser);
+
+ return mapToAppUserDTO(overwrittenUser);
+ }
+
+ private AppUser overwriteAppUserCredentials(AppUser foundUser, AppUserCredentialsDTO appUserCredentialsDTO) {
+ return appUserUtil.overwriteAppUserCredentials(foundUser, appUserCredentialsDTO);
+ }
+
+ public AppUserDTO replaceUserDetails(ReplaceAppUserByUserDTO replaceAppUserByUserDTO) {
+ long loggedInUserId = getLoggedUserId();
+
+ var foundUser = getUserById(loggedInUserId);
+
+ var overwrittenUser = overwriteAppUserDetails(foundUser, replaceAppUserByUserDTO);
+
+ overwrittenUser = saveUser(overwrittenUser);
+
+ return mapToAppUserDTO(overwrittenUser);
+ }
+
+ public AppUser overwriteAppUserDetails(AppUser foundUser, ReplaceAppUserByUserDTO replaceAppUserByUserDTO) {
+ return appUserUtil.overwriteAppUserDetails(foundUser, replaceAppUserByUserDTO);
+ }
+
+ private AppUser saveUser(AppUser user) {
+ return appUserAdminService.saveUser(user);
+ }
+
+}
diff --git a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/AppUserUtil.java b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/AppUserUtil.java
new file mode 100644
index 0000000..bdf3bda
--- /dev/null
+++ b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/AppUserUtil.java
@@ -0,0 +1,68 @@
+package com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser;
+
+
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser.dto.*;
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser.rolestrategy.AppUserRoleStrategyFacade;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+@Component
+@Slf4j
+@RequiredArgsConstructor
+class AppUserUtil {
+
+ private final AppUserMapperFactory appUserMapperFactory;
+ private final AppUserRoleStrategyFacade appUserRoleStrategyFacade;
+
+ public AppUser mapToAppUserFactory(T dto) {
+ return appUserMapperFactory.mapToAppUserFactory(dto);
+ }
+
+ public AppUserDTO mapToAppUserDTO(AppUser appUser) {
+ return appUserMapperFactory.mapToAppUserDTO(appUser);
+ }
+
+ public AppUser overwriteAppUserDetails(AppUser foundUser, ReplaceAppUserByUserDTO replaceAppUserByUserDTO) {
+ var convertedUser = mapToAppUser(replaceAppUserByUserDTO);
+
+ foundUser.setFirstName(convertedUser.getFirstName());
+ foundUser.setSecondName(convertedUser.getSecondName());
+ foundUser.setEmail(convertedUser.getEmail());
+
+ return foundUser;
+ }
+
+ private AppUser mapToAppUser(T dto) {
+ return appUserMapperFactory.mapToAppUserFactory(dto);
+ }
+
+ public AppUser overwriteAppUserCredentials(AppUser foundUser, AppUserCredentialsDTO appUserCredentialsDTO) {
+ var convertedUser = mapToAppUser(appUserCredentialsDTO);
+
+ foundUser.setPassword(convertedUser.getPassword());
+ foundUser.setUsername(convertedUser.getUsername());
+
+ return foundUser;
+ }
+
+ public AppUser overwriteAppUserAllDetails(AppUser foundUser, ReplaceAppUserAllDetailsDTO replaceAppUserAllDetailsDTO) {
+ var convertedUser = mapToAppUser(replaceAppUserAllDetailsDTO);
+
+ foundUser.setPassword(convertedUser.getPassword());
+ foundUser.setUsername(convertedUser.getUsername());
+ foundUser.setEmail(convertedUser.getEmail());
+ foundUser.setSecondName(convertedUser.getSecondName());
+ foundUser.setFirstName(convertedUser.getFirstName());
+
+ removeAndSetRoles(foundUser, replaceAppUserAllDetailsDTO);
+
+ return foundUser;
+ }
+
+ private void removeAndSetRoles(AppUser foundUser, ReplaceAppUserAllDetailsDTO replaceAppUserAllDetailsDTO) {
+ appUserRoleStrategyFacade.removeRoles(foundUser);
+
+ appUserRoleStrategyFacade.addRolesForUser(foundUser, replaceAppUserAllDetailsDTO);
+ }
+}
diff --git a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/dto/AppUserCredentialsDTO.java b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/dto/AppUserCredentialsDTO.java
index 6f37406..590d9f6 100644
--- a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/dto/AppUserCredentialsDTO.java
+++ b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/dto/AppUserCredentialsDTO.java
@@ -1,10 +1,12 @@
package com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser.dto;
import lombok.AllArgsConstructor;
+import lombok.Builder;
import lombok.Getter;
@Getter
@AllArgsConstructor
+@Builder
public class AppUserCredentialsDTO {
private String username;
private String password;
diff --git a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/dto/AppUserDTO.java b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/dto/AppUserDTO.java
new file mode 100644
index 0000000..8d68e8d
--- /dev/null
+++ b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/dto/AppUserDTO.java
@@ -0,0 +1,24 @@
+package com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser.dto;
+
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.role.dto.RoleDTO;
+import lombok.*;
+import lombok.experimental.FieldNameConstants;
+
+import java.util.List;
+
+@Getter
+@Setter
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@FieldNameConstants
+public class AppUserDTO {
+ private long id;
+
+ private String username;
+ private String email;
+ private String firstName;
+ private String secondName;
+
+ private List roles;
+}
diff --git a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/dto/CreateAppUserAdminDTO.java b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/dto/CreateAppUserAdminDTO.java
new file mode 100644
index 0000000..dc8ac16
--- /dev/null
+++ b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/dto/CreateAppUserAdminDTO.java
@@ -0,0 +1,25 @@
+package com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser.dto;
+
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.role.dto.RoleDTO;
+import lombok.*;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.List;
+
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+@Slf4j
+public class CreateAppUserAdminDTO extends CreateAppUserUserDTO {
+ private List roles;
+
+ public boolean hasRole(String name) {
+ RoleDTO role = new RoleDTO(name);
+
+ return roles.stream()
+ .filter(e -> e.equals(role))
+ .toList()
+ .size() > 0;
+ }
+}
diff --git a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/dto/CreateAppUserUserDTO.java b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/dto/CreateAppUserUserDTO.java
new file mode 100644
index 0000000..0181747
--- /dev/null
+++ b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/dto/CreateAppUserUserDTO.java
@@ -0,0 +1,16 @@
+package com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser.dto;
+
+import lombok.*;
+import lombok.experimental.FieldNameConstants;
+
+@Getter
+@Setter
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@FieldNameConstants
+public class CreateAppUserUserDTO {
+ private String username;
+ private String password;
+ private String email;
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/dto/ReplaceAppUserAllDetailsDTO.java b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/dto/ReplaceAppUserAllDetailsDTO.java
new file mode 100644
index 0000000..af367ea
--- /dev/null
+++ b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/dto/ReplaceAppUserAllDetailsDTO.java
@@ -0,0 +1,18 @@
+package com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser.dto;
+
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.role.dto.RoleDTO;
+import lombok.*;
+import lombok.experimental.FieldNameConstants;
+
+import java.util.List;
+
+@Getter
+@Setter
+@NoArgsConstructor
+@AllArgsConstructor
+@FieldNameConstants
+public class ReplaceAppUserAllDetailsDTO extends CreateAppUserAdminDTO {
+
+ private String firstName;
+ private String secondName;
+}
diff --git a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/dto/ReplaceAppUserByUserDTO.java b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/dto/ReplaceAppUserByUserDTO.java
new file mode 100644
index 0000000..b939486
--- /dev/null
+++ b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/dto/ReplaceAppUserByUserDTO.java
@@ -0,0 +1,17 @@
+package com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser.dto;
+
+import lombok.*;
+import lombok.experimental.FieldNameConstants;
+
+@Getter
+@Setter
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+@FieldNameConstants
+public class ReplaceAppUserByUserDTO {
+
+ private String email;
+ private String firstName;
+ private String secondName;
+}
diff --git a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/rolestrategy/AppUserAddAdminRole.java b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/rolestrategy/AppUserAddAdminRole.java
new file mode 100644
index 0000000..b65425d
--- /dev/null
+++ b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/rolestrategy/AppUserAddAdminRole.java
@@ -0,0 +1,60 @@
+package com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser.rolestrategy;
+
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser.AppUser;
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.role.Role;
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.role.RoleType;
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.role.RoleService;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Component
+class AppUserAddAdminRole implements AppUserRoleStrategy {
+
+ private static AppUserAddAdminRole instance = null;
+ private final RoleService roleService;
+
+ private AppUserAddAdminRole(RoleService roleService) {
+ this.roleService = roleService;
+ }
+
+ public static AppUserAddAdminRole getInstance(RoleService roleService) {
+ if (instance == null) {
+ instance = new AppUserAddAdminRole(roleService);
+ }
+
+ return instance;
+ }
+
+ @Override
+ public void addRolesForUser(AppUser user) {
+ var roles = getRoles(user);
+
+ if(!adminRoleExists(roles)) {
+ var userRoles = getAdminRoleList();
+
+ user.setRoles(userRoles);
+ }
+ }
+
+ private List getRoles(AppUser user) {
+ if(user.getRoles() == null)
+ return new ArrayList<>();
+
+ return user.getRoles();
+ }
+
+ private boolean adminRoleExists(List roles) {
+ return roles.stream()
+ .map(Role::getName)
+ .filter(e -> e.equals(RoleType.ROLE_ADMIN.getName()))
+ .toList()
+ .size() > 0;
+ }
+
+
+ private List getAdminRoleList() {
+ return List.of(roleService.getUserRoleOrCreate(), roleService.getAdminRoleOrCreate());
+ }
+}
diff --git a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/rolestrategy/AppUserAddUserRole.java b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/rolestrategy/AppUserAddUserRole.java
new file mode 100644
index 0000000..336a81a
--- /dev/null
+++ b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/rolestrategy/AppUserAddUserRole.java
@@ -0,0 +1,59 @@
+package com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser.rolestrategy;
+
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser.AppUser;
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.role.Role;
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.role.RoleType;
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.role.RoleService;
+import org.springframework.stereotype.Component;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Component
+class AppUserAddUserRole implements AppUserRoleStrategy {
+
+ private static AppUserAddUserRole instance = null;
+ private final RoleService roleService;
+
+ private AppUserAddUserRole(RoleService roleService) {
+ this.roleService = roleService;
+ }
+
+ public static AppUserAddUserRole getInstance(RoleService roleService) {
+ if (instance == null) {
+ instance = new AppUserAddUserRole(roleService);
+ }
+
+ return instance;
+ }
+
+ @Override
+ public void addRolesForUser(AppUser user) {
+ var roles = getRoles(user);
+
+ if(!userRoleExists(roles)) {
+ var userRoles = getUserRoleList();
+
+ user.setRoles(userRoles);
+ }
+ }
+
+ private List getRoles(AppUser user) {
+ if(user.getRoles() == null)
+ return new ArrayList<>();
+
+ return user.getRoles();
+ }
+
+ private boolean userRoleExists(List roles) {
+ return roles.stream()
+ .map(Role::getName)
+ .filter(e -> e.equals(RoleType.ROLE_USER.getName()))
+ .toList()
+ .size() > 0;
+ }
+
+ private List getUserRoleList() {
+ return List.of(roleService.getUserRoleOrCreate());
+ }
+}
diff --git a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/rolestrategy/AppUserRoleRemover.java b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/rolestrategy/AppUserRoleRemover.java
new file mode 100644
index 0000000..b69e2cd
--- /dev/null
+++ b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/rolestrategy/AppUserRoleRemover.java
@@ -0,0 +1,26 @@
+package com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser.rolestrategy;
+
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser.AppUser;
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.role.RoleService;
+
+class AppUserRoleRemover {
+
+ private static AppUserRoleRemover instance = null;
+ private final RoleService roleService;
+
+ private AppUserRoleRemover(RoleService roleService) {
+ this.roleService = roleService;
+ }
+
+ public static AppUserRoleRemover getInstance(RoleService roleService) {
+ if (instance == null) {
+ instance = new AppUserRoleRemover(roleService);
+ }
+
+ return instance;
+ }
+
+ public void deleteRolesForUser(AppUser user) {
+ roleService.deleteRolesFromUser(user);
+ }
+}
diff --git a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/rolestrategy/AppUserRoleStrategy.java b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/rolestrategy/AppUserRoleStrategy.java
new file mode 100644
index 0000000..3e6fb52
--- /dev/null
+++ b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/rolestrategy/AppUserRoleStrategy.java
@@ -0,0 +1,7 @@
+package com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser.rolestrategy;
+
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser.AppUser;
+
+interface AppUserRoleStrategy {
+ void addRolesForUser(AppUser user);
+}
diff --git a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/rolestrategy/AppUserRoleStrategyFacade.java b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/rolestrategy/AppUserRoleStrategyFacade.java
new file mode 100644
index 0000000..ed8ee56
--- /dev/null
+++ b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/appuser/rolestrategy/AppUserRoleStrategyFacade.java
@@ -0,0 +1,82 @@
+package com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser.rolestrategy;
+
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser.AppUser;
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser.dto.CreateAppUserAdminDTO;
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser.dto.CreateAppUserUserDTO;
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.appuser.dto.ReplaceAppUserAllDetailsDTO;
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.role.RoleService;
+import com.github.WeeiaEduTeam.InfinityFinanceAPI.role.RoleType;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+
+/*
+ * Class adds roles based on JSON input
+ * the highest role is taken and the rest
+ * of the roles are added for example:
+ * - if we have ROLE_ADMIN in name of the
+ * json request it adds also ROLE_USER
+ * - if we have ROLE_USER it adds just
+ * ROLE_USER.
+ *
+ * If you want to add new roles just add
+ * another object cast in factory
+ * and add create new strategy file.
+ */
+@Component
+@Slf4j
+public class AppUserRoleStrategyFacade {
+
+ private final RoleService roleService;
+
+ public AppUserRoleStrategyFacade(RoleService roleService) {
+ this.roleService = roleService;
+ }
+
+ public void addRolesForUser(AppUser user, T objectDTO) {
+ createStrategy(objectDTO).addRolesForUser(user);
+ }
+
+ private AppUserRoleStrategy createStrategy(T objectDTO) {
+ if(isAdmin(objectDTO)) {
+ return AppUserAddAdminRole.getInstance(roleService);
+ } else if(isDefaultUser(objectDTO)) {
+ return AppUserAddUserRole.getInstance(roleService);
+ }
+
+ throw new IllegalArgumentException("Error during create strategy occurred.");
+ }
+
+ private boolean isDefaultUser(T objectDTO) {
+ return isCreateAppUserUserDTO(objectDTO);
+ }
+
+
+ private boolean isAdmin(T objectDTO) {
+
+ /* Also catches ReplaceAppUserAllDetailsDTO due to inheritance. */
+ if(isReplaceAppUserAllDetailsDTO(objectDTO)) {
+ return ((ReplaceAppUserAllDetailsDTO) objectDTO).hasRole(RoleType.ROLE_ADMIN.getName());
+ } else if(isCreateAppUserAdminDTO(objectDTO)) {
+ return ((CreateAppUserAdminDTO) objectDTO).hasRole(RoleType.ROLE_ADMIN.getName());
+ }
+
+ return false;
+ }
+
+ private boolean isReplaceAppUserAllDetailsDTO(T objectDTO) {
+ return objectDTO instanceof ReplaceAppUserAllDetailsDTO;
+ }
+
+ private boolean isCreateAppUserUserDTO(T objectDTO) {
+ return objectDTO instanceof CreateAppUserUserDTO;
+ }
+
+ private boolean isCreateAppUserAdminDTO(T objectDTO) {
+ return objectDTO instanceof CreateAppUserAdminDTO;
+ }
+
+ public void removeRoles(AppUser user) {
+ AppUserRoleRemover.getInstance(roleService).deleteRolesForUser(user);
+ }
+}
diff --git a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/category/Category.java b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/category/Category.java
index 5935a77..7ccf5ca 100644
--- a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/category/Category.java
+++ b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/category/Category.java
@@ -3,6 +3,7 @@
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.github.WeeiaEduTeam.InfinityFinanceAPI.transaction.Transaction;
+import junit.runner.Version;
import lombok.*;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.UpdateTimestamp;
@@ -23,12 +24,10 @@ public class Category {
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "category_id")
private Long id;
-
- //@Column(unique = true)
private String name;
@JsonIgnore
- @OneToMany(mappedBy = "category")
+ @OneToMany(mappedBy = "category", orphanRemoval = true, fetch = FetchType.LAZY)
private List transactions = new ArrayList<>();
@CreationTimestamp
@@ -38,4 +37,8 @@ public class Category {
@UpdateTimestamp
@Temporal(TemporalType.TIMESTAMP)
private Date updated;
+
+ public Category(String categoryName) {
+ this.name = categoryName;
+ }
}
diff --git a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/category/CategoryController.java b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/category/CategoryController.java
new file mode 100644
index 0000000..e8d08ba
--- /dev/null
+++ b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/category/CategoryController.java
@@ -0,0 +1,25 @@
+package com.github.WeeiaEduTeam.InfinityFinanceAPI.category;
+
+import lombok.RequiredArgsConstructor;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@RestController
+@RequiredArgsConstructor
+@RequestMapping(path = "/api/v1")
+class CategoryController {
+
+ private final CategoryService categoryService;
+
+ @GetMapping("/catgories")
+ public ResponseEntity> getAllCategories(){
+
+ var categories = categoryService.getAllCategories();
+
+ return ResponseEntity.ok(categories);
+ }
+}
diff --git a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/category/CategoryRepository.java b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/category/CategoryRepository.java
index 956f183..be23d42 100644
--- a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/category/CategoryRepository.java
+++ b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/category/CategoryRepository.java
@@ -2,6 +2,6 @@
import org.springframework.data.jpa.repository.JpaRepository;
-public interface CategoryRepository extends JpaRepository {
+interface CategoryRepository extends JpaRepository {
Category findByName(String categoryName);
}
diff --git a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/category/CategoryService.java b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/category/CategoryService.java
index 10d0c0a..9ecd4f7 100644
--- a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/category/CategoryService.java
+++ b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/category/CategoryService.java
@@ -1,11 +1,11 @@
package com.github.WeeiaEduTeam.InfinityFinanceAPI.category;
-import com.github.WeeiaEduTeam.InfinityFinanceAPI.category.dto.CategoryDTO;
import lombok.RequiredArgsConstructor;
-import org.springframework.beans.factory.annotation.Autowired;
+import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
-import java.util.Optional;
+import java.util.List;
+
@Service
@RequiredArgsConstructor
@@ -13,14 +13,48 @@ public class CategoryService {
private final CategoryRepository categoryRepository;
- public Optional getCategoryByName(String categoryName) {
+ private final CategoryUtil categoryUtil;
+
+ public Category getCategoryByName(String categoryName) {
+
+ return categoryRepository.findByName(categoryName);
+ }
+
+ public Category createCategory(String categoryName) {
+ Category category = new Category(categoryName);
- return Optional.ofNullable(categoryRepository.findByName(categoryName));
+ return saveCategory(category);
}
- public Category createCategory(Category category) {
- var savedCategory = categoryRepository.save(category);
+ @NotNull
+ private Category saveCategory(Category category) {
+ return categoryRepository.save(category);
+ }
+
+ public void checkAndDeleteCategoryIfNotRelated(Long id) {
+ var foundCategory = getCategoryById(id);
+
+ deleteCategoryIfNotRelated(foundCategory);
+ }
+
+ private void deleteCategoryIfNotRelated(Category foundCategory) {
+ if (!isNumberPositive(foundCategory.getTransactions().size()))
+ deleteCategoryById(foundCategory.getId());
+ }
+
+ private Category getCategoryById(long id) {
+ return categoryRepository.findById(id).orElseThrow(() -> new RuntimeException("Category not found in database"));
+ }
+
+ private boolean isNumberPositive(int value) {
+ return categoryUtil.isNumberPositive(value);
+ }
+
+ private void deleteCategoryById(Long id) {
+ categoryRepository.deleteById(id);
+ }
- return savedCategory;
+ public List getAllCategories() {
+ return categoryRepository.findAll();
}
}
diff --git a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/category/CategoryUtils.java b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/category/CategoryUtil.java
similarity index 50%
rename from src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/category/CategoryUtils.java
rename to src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/category/CategoryUtil.java
index ade1167..8f15988 100644
--- a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/category/CategoryUtils.java
+++ b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/category/CategoryUtil.java
@@ -1,15 +1,22 @@
package com.github.WeeiaEduTeam.InfinityFinanceAPI.category;
import com.github.WeeiaEduTeam.InfinityFinanceAPI.category.dto.CategoryDTO;
-import com.github.WeeiaEduTeam.InfinityFinanceAPI.transaction.Transaction;
-import com.github.WeeiaEduTeam.InfinityFinanceAPI.transaction.dto.CreateTransactionDTO;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Component
-public class CategoryUtils {
- public CategoryDTO mapCategoryToCategoryDTO(Category category) {
+@Slf4j
+@RequiredArgsConstructor
+class CategoryUtil {
+
+ public CategoryDTO mapToCategoryDTO(Category category) {
return CategoryDTO.builder()
.name(category.getName())
.build();
}
+
+ public boolean isNumberPositive(int value) {
+ return value > 0 ? Boolean.TRUE : Boolean.FALSE;
+ }
}
diff --git a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/exception/GlobalExceptionHandler.java b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/exception/GlobalExceptionHandler.java
new file mode 100644
index 0000000..9a33d75
--- /dev/null
+++ b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/exception/GlobalExceptionHandler.java
@@ -0,0 +1,77 @@
+package com.github.WeeiaEduTeam.InfinityFinanceAPI.exception;
+
+import lombok.extern.slf4j.Slf4j;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.dao.DataIntegrityViolationException;
+import org.springframework.dao.InvalidDataAccessApiUsageException;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.validation.FieldError;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import javax.validation.ConstraintViolationException;
+import java.util.HashMap;
+import java.util.Map;
+
+@Slf4j
+@RestControllerAdvice(basePackages = "com.github.WeeiaEduTeam.InfinityFinanceAPI")
+class GlobalExceptionHandler {
+
+ @ExceptionHandler({MethodArgumentNotValidException.class})
+ public ResponseEntity>> handleMethodArgumentNotValidException(MethodArgumentNotValidException exception) {
+
+ Map errors = new HashMap<>();
+
+ exception.getBindingResult().getAllErrors().forEach((error) -> {
+ String fieldName = ((FieldError) error).getField();
+ String errorMessage = error.getDefaultMessage();
+
+ errors.put(fieldName, errorMessage);
+ });
+
+ log.error("Validation failed: {}", errors);
+
+ return Result.failedValidation(errors);
+ }
+
+
+ @ExceptionHandler({ConstraintViolationException.class, DataIntegrityViolationException.class})
+ public ResponseEntity>> handleConstraintViolationException(ConstraintViolationException exception) {
+
+ Map errors = new HashMap<>();
+ errors.put("repository", exception.getMessage());
+
+ log.error("Constraint violation: {}", errors);
+
+ return Result.constraintViolation(errors);
+ }
+
+ @ExceptionHandler({ResourceNotFoundException.class, InvalidDataAccessApiUsageException.class})
+ public @NotNull ResponseEntity> handleUnknownResourceError(RuntimeException exception) {
+
+ log.error(exception.getMessage());
+
+ return Result.resourceNotFound();
+ }
+
+ @ExceptionHandler({UsernameNotFoundException.class})
+ public @NotNull ResponseEntity> handleForbiddenError(RuntimeException exception) {
+
+ log.error(exception.getMessage());
+
+ return Result.forbidden();
+ }
+
+ @ExceptionHandler({Exception.class})
+ public @NotNull ResponseEntity> handleUnknownError(Exception exception) {
+
+ log.error(exception.getMessage());
+ exception.printStackTrace();
+
+ return Result.unknownError();
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/exception/ResourceNotFoundException.java b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/exception/ResourceNotFoundException.java
new file mode 100644
index 0000000..ce3df73
--- /dev/null
+++ b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/exception/ResourceNotFoundException.java
@@ -0,0 +1,21 @@
+package com.github.WeeiaEduTeam.InfinityFinanceAPI.exception;
+
+
+public class ResourceNotFoundException extends RuntimeException {
+
+ public static ResourceNotFoundException createWith(String errorMessage) {
+ return new ResourceNotFoundException(errorMessage);
+ }
+
+ public static ResourceNotFoundException createWith(long id) {
+ return new ResourceNotFoundException(id);
+ }
+
+ private ResourceNotFoundException(long id) {
+ super(String.format("Resource with id: %s not found", id));
+ }
+
+ private ResourceNotFoundException(String errorMessage) {
+ super(errorMessage);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/exception/Response.java b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/exception/Response.java
new file mode 100644
index 0000000..fbd0d5a
--- /dev/null
+++ b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/exception/Response.java
@@ -0,0 +1,41 @@
+package com.github.WeeiaEduTeam.InfinityFinanceAPI.exception;
+
+import org.springframework.http.HttpStatus;
+
+enum Response {
+ UNSUPPORTED_OPERATION(HttpStatus.NOT_IMPLEMENTED, HttpStatus.NOT_IMPLEMENTED.getReasonPhrase()),
+ SUCCESS(HttpStatus.OK, HttpStatus.OK.getReasonPhrase()),
+ VALIDATE_FAILED(HttpStatus.BAD_REQUEST, "Validation failed"),
+
+ CONSTRAINT_VIOLATION(HttpStatus.CONFLICT, "The request could not be completed due to a conflict with the current state of the resource"),
+ NOT_FOUND(HttpStatus.NOT_FOUND, "Resource not found"),
+ FORBIDDEN(HttpStatus.FORBIDDEN, HttpStatus.FORBIDDEN.getReasonPhrase()),
+ ;
+
+ private final Integer code;
+ private final String message;
+ private final HttpStatus httpStatus;
+
+ Response(HttpStatus httpStatus, String message) {
+ this.httpStatus = httpStatus;
+ this.code = httpStatus.value();
+ this.message = message;
+ }
+
+ Response(int code, String message) {
+ this.httpStatus = HttpStatus.I_AM_A_TEAPOT;
+ this.code = code;
+ this.message = message;
+ }
+
+ public Integer getCode() {
+ return code;
+ }
+ public HttpStatus getStatus() {
+ return httpStatus;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+}
diff --git a/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/exception/ResponseAdvice.java b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/exception/ResponseAdvice.java
new file mode 100644
index 0000000..a9a3ef0
--- /dev/null
+++ b/src/main/java/com/github/WeeiaEduTeam/InfinityFinanceAPI/exception/ResponseAdvice.java
@@ -0,0 +1,35 @@
+package com.github.WeeiaEduTeam.InfinityFinanceAPI.exception;
+
+import lombok.extern.slf4j.Slf4j;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.core.MethodParameter;
+import org.springframework.http.MediaType;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
+
+@Slf4j
+@RestControllerAdvice(basePackages = "com.github.WeeiaEduTeam.InfinityFinanceAPI")
+class ResponseAdvice implements ResponseBodyAdvice