325 lines
12 KiB
Java
325 lines
12 KiB
Java
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;
|
|
|
|
import ru.soune.nocopy.dto.MessageCode;
|
|
import ru.soune.nocopy.dto.user.UserAdditionalInfoBody;
|
|
|
|
import ru.soune.nocopy.dto.user.UserDTO;
|
|
import ru.soune.nocopy.entity.tarif.TariffInfo;
|
|
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.UserService;
|
|
import ru.soune.nocopy.service.user.UserSpecifications;
|
|
|
|
|
|
import java.util.LinkedHashMap;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Optional;
|
|
import java.util.stream.Collectors;
|
|
|
|
@Component
|
|
@Slf4j
|
|
@RequiredArgsConstructor
|
|
public class UserInfoHandler implements RequestHandler {
|
|
|
|
private final AdditionalInfoService additionalInfoService;
|
|
|
|
private final ObjectMapper objectMapper;
|
|
|
|
private final UserRepository userRepository;
|
|
|
|
private final UserService userService;
|
|
|
|
@Override
|
|
public BaseResponse handle(BaseRequest request) throws Exception {
|
|
try {
|
|
UserAdditionalInfoBody body = objectMapper.convertValue(request.getMessageBody(),
|
|
UserAdditionalInfoBody.class);
|
|
|
|
log.info("Processing UserInfoHandler with action: {}", body.getAction());
|
|
|
|
return switch (body.getAction()) {
|
|
case "getAll" -> getAllAdditionalInfos(request);
|
|
case "getAllWithPagination" -> getAllAdditionalInfoWithPagination(request, body);
|
|
case "getById" -> getAdditionalInfoById(request, body.getUserId());
|
|
case "getIngoById" -> getInfoById(request, body.getUserId());
|
|
case "update" -> updateAdditionalInfo(request, body);
|
|
case "delete" -> deleteAdditionalInfo(request, body.getUserId());
|
|
default -> new BaseResponse(
|
|
request.getMsgId(),
|
|
MessageCode.INVALID_ACTION.getCode(),
|
|
"Invalid action: " + body.getAction(),
|
|
null
|
|
);
|
|
};
|
|
} catch (IllegalArgumentException e) {
|
|
log.error("Validation error in UserInfoHandler", e);
|
|
return new BaseResponse(
|
|
request.getMsgId(),
|
|
MessageCode.VALIDATION_ERROR.getCode(),
|
|
e.getMessage(),
|
|
null);
|
|
} catch (UserAdditionalInfoNotFound e) {
|
|
log.error("User additional info not found", e);
|
|
return new BaseResponse(
|
|
request.getMsgId(),
|
|
MessageCode.NOT_FOUND.getCode(),
|
|
e.getMessage(),
|
|
null);
|
|
} catch (Exception e) {
|
|
log.error("Unexpected error in UserInfoHandler", e);
|
|
return new BaseResponse(
|
|
request.getMsgId(),
|
|
MessageCode.INTERNAL_ERROR.getCode(),
|
|
"Internal server error: " + e.getMessage(),
|
|
null);
|
|
}
|
|
}
|
|
|
|
private BaseResponse getAllAdditionalInfos(BaseRequest request) {
|
|
log.info("Getting all additional infos");
|
|
|
|
List<UserAdditionalInfo> infos = additionalInfoService.getAllAdditionalInfos();
|
|
|
|
List<UserAdditionalInfoAnswer> answerItems = infos.stream()
|
|
.map(this::convertToAnswer)
|
|
.collect(Collectors.toList());
|
|
|
|
UserAdditionalInfoListAnswer listAnswer = UserAdditionalInfoListAnswer.builder()
|
|
.items(answerItems)
|
|
.count(answerItems.size())
|
|
.build();
|
|
|
|
return new BaseResponse(
|
|
request.getMsgId(),
|
|
MessageCode.SUCCESS.getCode(),
|
|
MessageCode.SUCCESS.getDescription(),
|
|
listAnswer
|
|
);
|
|
}
|
|
|
|
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";
|
|
|
|
String sortField = switch (sortBy) {
|
|
case "fullName" -> "fullName";
|
|
case "email" -> "email";
|
|
case "createdAt" -> "createdAt";
|
|
case "verificationStatus" -> "verificationStatus";
|
|
case "tariff" -> "personalTariffInfo.status";
|
|
case "tokens" -> "personalTariffInfo.tokens";
|
|
default -> "createdAt";
|
|
};
|
|
|
|
Pageable pageable = PageRequest.of(req.getPage(), req.getSize(), Sort.by(direction, sortField));
|
|
|
|
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);
|
|
|
|
Page<Map<String, Object>> dtoPage = allUsers.map(user -> {
|
|
Map<String, Object> map = new LinkedHashMap<>();
|
|
map.put("id", user.getId());
|
|
map.put("fullName", user.getFullName());
|
|
map.put("email", user.getEmail());
|
|
map.put("verificationStatus", user.getVerificationStatus() != null ? user.getVerificationStatus().name() : null);
|
|
map.put("createdAt", user.getCreatedAt() != null ? user.getCreatedAt().toString() : null);
|
|
|
|
TariffInfo tariff = user.getActiveTariffInfo();
|
|
if (tariff != null) {
|
|
map.put("tariff", tariff.getStatus() != null ? tariff.getStatus().name() : null);
|
|
map.put("tokens", tariff.getTokens() != null ? tariff.getTokens() : 0);
|
|
} else {
|
|
map.put("tariff", null);
|
|
map.put("tokens", 0);
|
|
}
|
|
|
|
return map;
|
|
});
|
|
|
|
Map<String, Object> response = new LinkedHashMap<>();
|
|
response.put("content", dtoPage.getContent());
|
|
response.put("totalElements", allUsers.getTotalElements());
|
|
response.put("totalPages", allUsers.getTotalPages());
|
|
response.put("number", allUsers.getNumber());
|
|
response.put("size", allUsers.getSize());
|
|
|
|
return new BaseResponse(
|
|
request.getMsgId(),
|
|
MessageCode.SUCCESS.getCode(),
|
|
MessageCode.SUCCESS.getDescription(),
|
|
response);
|
|
}
|
|
|
|
|
|
private BaseResponse getAdditionalInfoById(BaseRequest request, Long userId) {
|
|
log.info("Getting additional info for user: {}", userId);
|
|
|
|
if (userId == null) {
|
|
throw new IllegalArgumentException("User ID is required for getById action");
|
|
}
|
|
|
|
UserAdditionalInfo info = additionalInfoService.getAdditionalInfoByUser(userId);
|
|
|
|
if (info == null) {
|
|
throw new UserAdditionalInfoNotFound(
|
|
String.format("User additional info not found for userId: %d", userId)
|
|
);
|
|
}
|
|
|
|
UserAdditionalInfoAnswer answer = convertToAnswer(info);
|
|
|
|
return new BaseResponse(
|
|
request.getMsgId(),
|
|
MessageCode.SUCCESS.getCode(),
|
|
MessageCode.SUCCESS.getDescription(),
|
|
answer
|
|
);
|
|
}
|
|
|
|
private BaseResponse getInfoById(BaseRequest request, Long userId) {
|
|
log.info("Getting info for user: {}", userId);
|
|
|
|
if (userId == null) {
|
|
throw new IllegalArgumentException("User Id is required for getById action");
|
|
}
|
|
|
|
UserDTO userInfo = userService.getUserInfo(userId);
|
|
|
|
return new BaseResponse(
|
|
request.getMsgId(),
|
|
MessageCode.SUCCESS.getCode(),
|
|
MessageCode.SUCCESS.getDescription(),
|
|
userInfo);
|
|
}
|
|
|
|
private BaseResponse updateAdditionalInfo(BaseRequest request, UserAdditionalInfoBody body) {
|
|
log.info("Updating additional info for user: {}", body.getUserId());
|
|
|
|
if (body.getUserId() == null) {
|
|
throw new IllegalArgumentException("User ID is required for update action");
|
|
}
|
|
|
|
validateIpAddress(body.getIpAddress());
|
|
validateUserAgent(body.getUserAgent());
|
|
|
|
Optional<UserAdditionalInfo> updatedInfo = additionalInfoService.updateAdditionalInfo(
|
|
body.getUserId(),
|
|
body.getIpAddress(),
|
|
body.getUserAgent()
|
|
);
|
|
|
|
if (updatedInfo.isEmpty()) {
|
|
throw new UserAdditionalInfoNotFound(
|
|
String.format("User additional info not found for userId: %d", body.getUserId())
|
|
);
|
|
}
|
|
|
|
UserAdditionalInfoAnswer answer = convertToAnswer(updatedInfo.get());
|
|
|
|
return new BaseResponse(
|
|
request.getMsgId(),
|
|
MessageCode.SUCCESS.getCode(),
|
|
MessageCode.SUCCESS.getDescription(),
|
|
answer
|
|
);
|
|
}
|
|
|
|
private BaseResponse deleteAdditionalInfo(BaseRequest request, Long userId) {
|
|
log.info("Deleting additional info for user: {}", userId);
|
|
|
|
if (userId == null) {
|
|
throw new IllegalArgumentException("User ID is required for delete action");
|
|
}
|
|
|
|
UserAdditionalInfo existingInfo = additionalInfoService.getAdditionalInfoByUser(userId);
|
|
|
|
if (existingInfo == null) {
|
|
throw new UserAdditionalInfoNotFound(
|
|
String.format("User additional info not found for userId: %d", userId)
|
|
);
|
|
}
|
|
|
|
additionalInfoService.deleteAdditionalInfo(userId);
|
|
|
|
return new BaseResponse(
|
|
request.getMsgId(),
|
|
MessageCode.SUCCESS.getCode(),
|
|
MessageCode.SUCCESS.getDescription(),
|
|
Map.of("deleted", true, "user_id", userId)
|
|
);
|
|
}
|
|
|
|
private UserAdditionalInfoAnswer convertToAnswer(UserAdditionalInfo info) {
|
|
return UserAdditionalInfoAnswer.builder()
|
|
.id(info.getId())
|
|
.userId(info.getUser() != null ? info.getUser().getId() : null)
|
|
.ipAddress(info.getIpAddress())
|
|
.userAgent(info.getUserAgent())
|
|
.registrationDate(info.getRegistrationDate())
|
|
.build();
|
|
}
|
|
|
|
private void validateIpAddress(String ip) {
|
|
if (ip == null || ip.trim().isEmpty()) {
|
|
throw new IllegalArgumentException("IP address is required for update action");
|
|
}
|
|
|
|
String ipv4Pattern =
|
|
"^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$";
|
|
|
|
if (!ip.trim().matches(ipv4Pattern)) {
|
|
log.warn("Invalid IP address format: {}", ip);
|
|
throw new IllegalArgumentException("Invalid IP address format");
|
|
}
|
|
}
|
|
|
|
private void validateUserAgent(String userAgent) {
|
|
if (userAgent == null || userAgent.trim().isEmpty()) {
|
|
throw new IllegalArgumentException("User agent is required for update action");
|
|
}
|
|
|
|
if (userAgent.length() > 500) {
|
|
throw new IllegalArgumentException("User agent must not exceed 500 characters");
|
|
}
|
|
}
|
|
}
|