@@ -73,6 +73,11 @@ dependencies {
|
||||
|
||||
implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.7.0")
|
||||
implementation("org.springframework.boot:spring-boot-starter-web")
|
||||
|
||||
|
||||
implementation 'org.springframework.cloud:spring-cloud-starter-openfeign'
|
||||
implementation 'io.github.resilience4j:resilience4j-spring-boot3'
|
||||
implementation 'org.springframework.boot:spring-boot-starter-aop'
|
||||
}
|
||||
|
||||
tasks.named('test') {
|
||||
|
||||
@@ -2,6 +2,9 @@ package ru.soune.nocopy.dto.user;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
import ru.soune.nocopy.entity.user.SubscriptionType;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
@Data
|
||||
public class UserAdditionalInfoBody {
|
||||
@@ -17,4 +20,37 @@ public class UserAdditionalInfoBody {
|
||||
|
||||
@JsonProperty("user_agent")
|
||||
private String userAgent;
|
||||
|
||||
@JsonProperty("page")
|
||||
private int page = 0;
|
||||
|
||||
@JsonProperty("size")
|
||||
private int size = 5;
|
||||
|
||||
@JsonProperty("sort_by")
|
||||
private String sortBy;
|
||||
|
||||
@JsonProperty("sort_direction")
|
||||
private String sortDirection = "desc";
|
||||
|
||||
@JsonProperty("full_name")
|
||||
private String fullName;
|
||||
|
||||
@JsonProperty("email")
|
||||
private String email;
|
||||
|
||||
@JsonProperty("is_active")
|
||||
private Boolean isActive;
|
||||
|
||||
@JsonProperty("email_verified")
|
||||
private Boolean emailVerified;
|
||||
|
||||
@JsonProperty("sub_type")
|
||||
private SubscriptionType subscriptionType;
|
||||
|
||||
@JsonProperty("date_from")
|
||||
private LocalDate dateFrom;
|
||||
|
||||
@JsonProperty("date_to")
|
||||
private LocalDate dateTo;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,11 @@ package ru.soune.nocopy.handler;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
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.stereotype.Component;
|
||||
import ru.soune.nocopy.dto.BaseRequest;
|
||||
import ru.soune.nocopy.dto.BaseResponse;
|
||||
@@ -10,11 +15,14 @@ import ru.soune.nocopy.dto.BaseResponse;
|
||||
import ru.soune.nocopy.dto.MessageCode;
|
||||
import ru.soune.nocopy.dto.user.UserAdditionalInfoBody;
|
||||
|
||||
import ru.soune.nocopy.entity.user.User;
|
||||
import ru.soune.nocopy.entity.user.UserAdditionalInfo;
|
||||
import ru.soune.nocopy.entity.user.UserAdditionalInfoAnswer;
|
||||
import ru.soune.nocopy.entity.user.UserAdditionalInfoListAnswer;
|
||||
import ru.soune.nocopy.exception.UserAdditionalInfoNotFound;
|
||||
import ru.soune.nocopy.repository.UserRepository;
|
||||
import ru.soune.nocopy.service.user.AdditionalInfoService;
|
||||
import ru.soune.nocopy.service.user.UserSpecifications;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
@@ -28,8 +36,11 @@ import java.util.stream.Collectors;
|
||||
public class UserInfoHandler implements RequestHandler {
|
||||
|
||||
private final AdditionalInfoService additionalInfoService;
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
private final UserRepository userRepository;
|
||||
|
||||
@Override
|
||||
public BaseResponse handle(BaseRequest request) throws Exception {
|
||||
try {
|
||||
@@ -40,6 +51,7 @@ public class UserInfoHandler implements RequestHandler {
|
||||
|
||||
return switch (body.getAction()) {
|
||||
case "getAll" -> getAllAdditionalInfos(request);
|
||||
case "getAllWithPagination" -> getAllAdditionalInfoWithPagination(request, body);
|
||||
case "getById" -> getAdditionalInfoById(request, body.getUserId());
|
||||
case "update" -> updateAdditionalInfo(request, body);
|
||||
case "delete" -> deleteAdditionalInfo(request, body.getUserId());
|
||||
@@ -96,6 +108,44 @@ public class UserInfoHandler implements RequestHandler {
|
||||
);
|
||||
}
|
||||
|
||||
private BaseResponse getAllAdditionalInfoWithPagination(BaseRequest request, UserAdditionalInfoBody req) {
|
||||
Sort.Direction direction =
|
||||
Sort.Direction.fromString(req.getSortDirection() != null ? req.getSortDirection() : "desc");
|
||||
String sortBy = req.getSortBy() != null ? req.getSortBy() : "createdAt";
|
||||
|
||||
Pageable pageable = PageRequest.of(req.getPage(), req.getSize(), Sort.by(direction, sortBy));
|
||||
|
||||
Specification<User> spec = (root, query, cb) -> cb.conjunction();
|
||||
|
||||
if (req.getFullName() != null) {
|
||||
spec = spec.and(UserSpecifications.byFullName(req.getFullName()));
|
||||
}
|
||||
if (req.getEmail() != null) {
|
||||
spec = spec.and(UserSpecifications.byEmail(req.getEmail()));
|
||||
}
|
||||
if (req.getIsActive() != null) {
|
||||
spec = spec.and(UserSpecifications.byIsActive(req.getIsActive()));
|
||||
}
|
||||
if (req.getEmailVerified() != null) {
|
||||
spec = spec.and(UserSpecifications.byEmailVerified(req.getEmailVerified()));
|
||||
}
|
||||
if (req.getSubscriptionType() != null) {
|
||||
spec = spec.and(UserSpecifications.bySubscriptionType(req.getSubscriptionType()));
|
||||
}
|
||||
if (req.getDateFrom() != null || req.getDateTo() != null) {
|
||||
spec = spec.and(UserSpecifications.byCreatedAtRange(req.getDateFrom(), req.getDateTo()));
|
||||
}
|
||||
|
||||
Page<User> allUsers = userRepository.findAll(spec, pageable);
|
||||
|
||||
return new BaseResponse(
|
||||
request.getMsgId(),
|
||||
MessageCode.SUCCESS.getCode(),
|
||||
MessageCode.SUCCESS.getDescription(),
|
||||
allUsers);
|
||||
}
|
||||
|
||||
|
||||
private BaseResponse getAdditionalInfoById(BaseRequest request, Long userId) {
|
||||
log.info("Getting additional info for user: {}", userId);
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package ru.soune.nocopy.repository;
|
||||
|
||||
import jakarta.validation.constraints.Size;
|
||||
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.JpaSpecificationExecutor;
|
||||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.data.repository.query.Param;
|
||||
import ru.soune.nocopy.entity.tarif.TariffInfo;
|
||||
@@ -10,12 +13,17 @@ import ru.soune.nocopy.entity.user.User;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public interface UserRepository extends JpaRepository<User, Long> {
|
||||
public interface UserRepository extends JpaRepository<User, Long>, JpaSpecificationExecutor<User> {
|
||||
User findByEmail(String email);
|
||||
|
||||
boolean existsByEmail(String email);
|
||||
|
||||
boolean existsByPhone(@Size(min = 11, max = 14) String phone);
|
||||
|
||||
List<User> findByCompanyId(String companyId);
|
||||
|
||||
long countByCompanyId(String companyId);
|
||||
|
||||
User findByPersonalTariffInfo(TariffInfo tariffInfo);
|
||||
|
||||
@Query("SELECT COUNT(u.Id) FROM User u")
|
||||
@@ -48,4 +56,7 @@ public interface UserRepository extends JpaRepository<User, Long> {
|
||||
|
||||
@Query("SELECT u.email FROM User u WHERE u.company.id = :company")
|
||||
List<String> emailsByCompany(@Param("company") String company);
|
||||
|
||||
@Query("SELECT u FROM User u LEFT JOIN u.personalTariffInfo t")
|
||||
Page<User> findAllWithTariff(Pageable pageable);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
package ru.soune.nocopy.service.user;
|
||||
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import ru.soune.nocopy.entity.user.SubscriptionType;
|
||||
import ru.soune.nocopy.entity.user.User;
|
||||
|
||||
import java.time.LocalDate;
|
||||
|
||||
public class UserSpecifications {
|
||||
|
||||
public static Specification<User> byFullName(String fullName) {
|
||||
return (root, query, cb) -> {
|
||||
if (fullName == null || fullName.isEmpty()) return null;
|
||||
return cb.like(cb.lower(root.get("fullName")), "%" + fullName.toLowerCase() + "%");
|
||||
};
|
||||
}
|
||||
|
||||
public static Specification<User> byEmail(String email) {
|
||||
return (root, query, cb) -> {
|
||||
if (email == null || email.isEmpty()) return null;
|
||||
return cb.like(cb.lower(root.get("email")), "%" + email.toLowerCase() + "%");
|
||||
};
|
||||
}
|
||||
|
||||
public static Specification<User> byIsActive(Boolean isActive) {
|
||||
return (root, query, cb) -> {
|
||||
if (isActive == null) return null;
|
||||
return cb.equal(root.get("isActive"), isActive);
|
||||
};
|
||||
}
|
||||
|
||||
public static Specification<User> byEmailVerified(Boolean emailVerified) {
|
||||
return (root, query, cb) -> {
|
||||
if (emailVerified == null) return null;
|
||||
return cb.equal(root.get("emailVerified"), emailVerified);
|
||||
};
|
||||
}
|
||||
|
||||
public static Specification<User> bySubscriptionType(SubscriptionType type) {
|
||||
return (root, query, cb) -> {
|
||||
if (type == null) return null;
|
||||
return cb.equal(root.get("subscriptionType"), type);
|
||||
};
|
||||
}
|
||||
|
||||
public static Specification<User> byCreatedAtRange(LocalDate from, LocalDate to) {
|
||||
return (root, query, cb) -> {
|
||||
if (from == null && to == null) return null;
|
||||
if (from != null && to != null) {
|
||||
return cb.between(root.get("createdAt"),
|
||||
from.atStartOfDay(), to.atTime(23, 59, 59));
|
||||
} else if (from != null) {
|
||||
return cb.greaterThanOrEqualTo(root.get("createdAt"), from.atStartOfDay());
|
||||
} else {
|
||||
return cb.lessThanOrEqualTo(root.get("createdAt"), to.atTime(23, 59, 59));
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user