Skip to content

Commit

Permalink
Merge pull request #47 from onesimus-wiafe/SCRUM-55-user-service-add-…
Browse files Browse the repository at this point in the history
…filtering-options-to-get-users-endpoint

SCRUM-55-user-service-add-filtering-options-to-get-users-endpoint
  • Loading branch information
djangbahevans authored Jul 31, 2024
2 parents 1a3b821 + a17c7b8 commit c777ce7
Show file tree
Hide file tree
Showing 9 changed files with 167 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.List;

import org.springframework.data.domain.Page;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
Expand All @@ -14,7 +15,9 @@
import org.springframework.web.bind.annotation.RestController;

import com.joe.trading.user_management.dtos.CreateUserRequestDto;
import com.joe.trading.user_management.dtos.PaginatedResponseDto;
import com.joe.trading.user_management.dtos.UpdateUserDto;
import com.joe.trading.user_management.dtos.UserFilterRequestDto;
import com.joe.trading.user_management.dtos.UserResponseDto;
import com.joe.trading.user_management.entities.User;
import com.joe.trading.user_management.enums.AccountType;
Expand Down Expand Up @@ -43,16 +46,24 @@ public ResponseEntity<UserResponseDto> createUser(

@GetMapping("{id}")
@PreAuthorize("hasRole('ADMIN') or principal.id == #userId")
public ResponseEntity<UserResponseDto> getUserById(@PathVariable("id") Long userId) throws ResourceNotFoundException {
public ResponseEntity<UserResponseDto> getUserById(@PathVariable("id") Long userId)
throws ResourceNotFoundException {
User user = userService.getUserById(userId);
return ResponseEntity.ok(userMapper.userToUserResponseDto(user));
}

@GetMapping
@PreAuthorize("hasRole('ADMIN')")
public ResponseEntity<List<UserResponseDto>> getAllUsers() {
List<User> users = userService.getAllUsers();
return ResponseEntity.ok(userMapper.usersToUserResponseDtos(users));
public ResponseEntity<PaginatedResponseDto<UserResponseDto>> getAllUsers(UserFilterRequestDto filterRequestDto) {
Page<User> pagedUsers = userService.getUsers(filterRequestDto);

List<UserResponseDto> userResponseDtos = userMapper.usersToUserResponseDtos(pagedUsers.getContent());
PaginatedResponseDto<UserResponseDto> userListResponseDto = new PaginatedResponseDto<>(
userResponseDtos,
pagedUsers.getTotalPages(),
pagedUsers.getTotalElements(), pagedUsers.getNumber());

return ResponseEntity.ok(userListResponseDto);
}

@PutMapping("{id}")
Expand All @@ -64,7 +75,8 @@ public ResponseEntity<UserResponseDto> updateUser(@PathVariable("id") Long userI
var principal = auth.getPrincipal();
if (principal instanceof User) {
var user = (User) principal;
if (user.getAccountType().equals(AccountType.USER) && updatedUser.getAccountType().equals(AccountType.ADMIN)) {
if (user.getAccountType().equals(AccountType.USER)
&& updatedUser.getAccountType().equals(AccountType.ADMIN)) {
throw new IllegalArgumentException("You are not authorized to update user to admin");
}
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,15 @@
import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class CreateUserRequestDto {
@NotEmpty(message = "Name is required")
private String name;
Expand All @@ -28,11 +32,4 @@ public class CreateUserRequestDto {

@NotNull(message = "Account type is required")
private AccountType accountType;

public CreateUserRequestDto() {
this.name = null;
this.email = null;
this.password = null;
this.accountType = null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.joe.trading.user_management.dtos;

import java.util.List;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class PaginatedResponseDto<T> {
private List<T> data;
private int totalPages;
private long totalElements;
private int currentPage;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package com.joe.trading.user_management.dtos;

import java.time.LocalDateTime;

import com.joe.trading.user_management.enums.AccountType;

import jakarta.validation.constraints.Min;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class UserFilterRequestDto {
private String name;
private String email;
private Boolean pendingDelete;
private LocalDateTime createdFrom;
private LocalDateTime createdTo;
private AccountType accountType;

@Min(value = 1, message = "Page number must be greater than 0")
private int page = 1;

@Min(value = 1, message = "Page size must be greater than 0")
private int size = 10;
private String sortBy = "id";

private String sortDir = "asc";
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,14 @@

import java.util.Optional;

import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaRepository;

import com.joe.trading.user_management.entities.User;

public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByEmail(String email);
Page<User> findAll(Specification<User> spec, Pageable pageable);
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
package com.joe.trading.user_management.services;

import java.util.List;
import org.springframework.data.domain.Page;

import com.joe.trading.user_management.dtos.CreateUserRequestDto;
import com.joe.trading.user_management.dtos.UpdateUserDto;
import com.joe.trading.user_management.dtos.UserFilterRequestDto;
import com.joe.trading.user_management.entities.User;
import com.joe.trading.user_management.exceptions.ResourceNotFoundException;

public interface UserService {
User createUser(CreateUserRequestDto createUserDto);

User getUserById(Long userId) throws ResourceNotFoundException;
List<User> getAllUsers();
User updateUser(Long userId, UpdateUserDto updatedUser) throws ResourceNotFoundException;

Page<User> getUsers(UserFilterRequestDto filterRequestDto);

User updateUser(Long userId, UpdateUserDto updatedUser) throws ResourceNotFoundException;
}
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
package com.joe.trading.user_management.services.impl;

import java.util.List;

import com.joe.trading.user_management.entities.Portfolio;
import com.joe.trading.user_management.repository.PortfolioRepository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import com.joe.trading.user_management.dtos.CreateUserRequestDto;
import com.joe.trading.user_management.dtos.UpdateUserDto;
import com.joe.trading.user_management.dtos.UserFilterRequestDto;
import com.joe.trading.user_management.entities.User;
import com.joe.trading.user_management.exceptions.EmailAlreadyExistsException;
import com.joe.trading.user_management.exceptions.ResourceNotFoundException;
import com.joe.trading.user_management.repository.UserRepository;
import com.joe.trading.user_management.services.UserService;
import com.joe.trading.user_management.specifications.UserSpecifications;

import lombok.AllArgsConstructor;
import org.springframework.transaction.annotation.Transactional;

@Service
@AllArgsConstructor
public class UserServiceImpl implements UserService {
private UserRepository userRepository;
private PortfolioRepository portfolioRepository;
private PasswordEncoder passwordEncoder;

public User getUserById(Long userId) throws ResourceNotFoundException {
Expand All @@ -48,9 +49,35 @@ public User createUser(CreateUserRequestDto createUserDto) {
return userRepository.save(user);
}

public List<User> getAllUsers() {
List<User> users = userRepository.findAll();
return users;
public Page<User> getUsers(UserFilterRequestDto filterRequestDto) {

Specification<User> spec = Specification.where(null);

if (filterRequestDto.getName() != null) {
spec = spec.and(UserSpecifications.hasName(filterRequestDto.getName()));
}
if (filterRequestDto.getEmail() != null) {
spec = spec.and(UserSpecifications.hasEmail(filterRequestDto.getEmail()));
}
if (filterRequestDto.getPendingDelete() != null) {
spec = spec.and(UserSpecifications.pendingDelete(filterRequestDto.getPendingDelete()));
}
if (filterRequestDto.getCreatedFrom() != null && filterRequestDto.getCreatedTo() != null) {
spec = spec.and(UserSpecifications.createdAtBetween(filterRequestDto.getCreatedFrom(),
filterRequestDto.getCreatedTo()));
}
if (filterRequestDto.getAccountType() != null) {
spec = spec.and(UserSpecifications.accountType(filterRequestDto.getAccountType()));
}

Pageable pageable = PageRequest.of(
filterRequestDto.getPage() - 1,
filterRequestDto.getSize(),
filterRequestDto.getSortDir().equalsIgnoreCase("desc")
? Sort.by(filterRequestDto.getSortBy()).descending()
: Sort.by(filterRequestDto.getSortBy()).ascending());

return userRepository.findAll(spec, pageable);
}

@Override
Expand All @@ -69,5 +96,4 @@ public User updateUser(Long userId, UpdateUserDto updatedUser) throws ResourceNo

return existingUser;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.joe.trading.user_management.specifications;

import java.time.LocalDateTime;

import org.springframework.data.jpa.domain.Specification;

import com.joe.trading.user_management.entities.User;
import com.joe.trading.user_management.enums.AccountType;

import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;
import jakarta.persistence.criteria.Root;

public class UserSpecifications {
private UserSpecifications() {
}

public static Specification<User> hasName(String name) {
return (Root<User> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) -> criteriaBuilder
.like(root.get("name"), "%" + name + "%");
}

public static Specification<User> hasEmail(String email) {
return (Root<User> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) -> criteriaBuilder
.equal(root.get("email"), email);
}

public static Specification<User> pendingDelete(Boolean pendingDelete) {
return (Root<User> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) -> criteriaBuilder
.equal(root.get("pendingDelete"), pendingDelete);
}

public static Specification<User> createdAtBetween(LocalDateTime start, LocalDateTime end) {
return (Root<User> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) -> criteriaBuilder
.between(root.get("createdAt"), start, end);
}

public static Specification<User> accountType(AccountType accountType) {
return (Root<User> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) -> criteriaBuilder
.equal(root.get("accountType"), accountType);
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.joe.trading.user_management.utils;

import com.joe.trading.user_management.dtos.CreateUserRequestDto;
import com.joe.trading.user_management.dtos.UserFilterRequestDto;
import com.joe.trading.user_management.enums.AccountType;
import com.joe.trading.user_management.services.UserService;

Expand All @@ -16,7 +17,7 @@ public class UserSeeder {

@PostConstruct
public void seedUsers() {
var allUsers = userService.getAllUsers();
var allUsers = userService.getUsers(new UserFilterRequestDto());
if (allUsers.isEmpty()) {
var user = new CreateUserRequestDto("Admin", "admin@admin.com", "password", AccountType.ADMIN);
userService.createUser(user);
Expand Down

0 comments on commit c777ce7

Please sign in to comment.