dev add token spent logic
Test Workflow / test (push) Successful in 4s

This commit is contained in:
vladp
2026-04-10 20:13:59 +07:00
parent c1360fce87
commit aa6c0c1b94
18 changed files with 820 additions and 9 deletions
@@ -11,6 +11,7 @@ import ru.soune.nocopy.dto.MessageCode;
import ru.soune.nocopy.dto.file.ImageSearchRequest;
import ru.soune.nocopy.dto.file.YandexSearchResponse;
import ru.soune.nocopy.entity.file.FileEntity;
import ru.soune.nocopy.entity.tokenoperation.OperationType;
import ru.soune.nocopy.exception.NotValidFieldException;
import ru.soune.nocopy.repository.FileEntityRepository;
import ru.soune.nocopy.service.file.CheckCounterService;
@@ -117,7 +118,8 @@ public class ImageFoundRequestHandler implements RequestHandler {
log.info("Results only from Yandex: {} images", allUniqueImages.size());
}
tariffInfoService.writeOffTokens(fileEntity.getUserId(), TariffConstants.TOKEN_VALUE_FOR_SEARCH);
tariffInfoService.writeOffTokens(fileEntity.getUserId(), TariffConstants.TOKEN_VALUE_FOR_SEARCH,
OperationType.SEARCH);
checkCounterService.incrementCheckCount(fileEntity.getUserId(), fileEntity.getMimeType());
int page = imageSearchRequest.getPage() != null ? imageSearchRequest.getPage() : 1;
@@ -15,6 +15,7 @@ import ru.soune.nocopy.dto.complaint.PaginatedResponse;
import ru.soune.nocopy.entity.complaint.LawCase;
import ru.soune.nocopy.entity.complaint.LawCasePriority;
import ru.soune.nocopy.entity.complaint.LawCaseType;
import ru.soune.nocopy.entity.tokenoperation.OperationType;
import ru.soune.nocopy.entity.user.User;
import ru.soune.nocopy.exception.NotValidFieldException;
import ru.soune.nocopy.exception.TariffNotFoundException;
@@ -114,7 +115,7 @@ public class LawCaseHandler implements RequestHandler {
private BaseResponse createLawCase(Long userId, LawCaseRequest lawCaseRequest, BaseRequest request) {
try {
tariffInfoService.writeOffTokens(userId, TariffConstants.LEGAL_COST);
tariffInfoService.writeOffTokens(userId, TariffConstants.LEGAL_COST, OperationType.CREATE_LEGAL_CASE);
} catch (TariffNotFoundException e) {
return new BaseResponse(request.getMsgId(), MessageCode.USER_NOT_HAVE_TOKEN.getCode(),
MessageCode.USER_NOT_HAVE_TOKEN.getDescription(),
@@ -0,0 +1,472 @@
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.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.tokenoperation.TokenOperationPageDto;
import ru.soune.nocopy.dto.tokenoperation.TokenOperationRequest;
import ru.soune.nocopy.entity.tokenoperation.OperationType;
import ru.soune.nocopy.entity.tokenoperation.TokenOperation;
import ru.soune.nocopy.service.register.AuthService;
import ru.soune.nocopy.service.tokenoperation.TokenOperationService;
import java.util.HashMap;
import java.util.Map;
@Slf4j
@Component
@RequiredArgsConstructor
public class TokenOperationHandler implements RequestHandler {
private final TokenOperationService tokenOperationService;
private final ObjectMapper objectMapper;
private final AuthService authService;
@Override
public BaseResponse handle(BaseRequest request) throws Exception {
log.info("Handling TokenOperation request: msg_id={}, version={}",
request.getMsgId(), request.getVersion());
try {
TokenOperationRequest tokenRequest = objectMapper.convertValue(
request.getMessageBody(),
TokenOperationRequest.class
);
String action = tokenRequest.getAction();
if (action == null) {
return new BaseResponse(
request.getMsgId(),
MessageCode.INVALID_ACTION.getCode(),
MessageCode.INVALID_ACTION.getDescription(),
Map.of("error", "Action is required")
);
}
switch (action.toLowerCase()) {
case "get_list":
return handleGetList(request.getMsgId(), tokenRequest);
case "get_by_id":
return handleGetById(request.getMsgId(), tokenRequest);
case "get_by_user":
return handleGetByUser(request.getMsgId(), tokenRequest);
case "create":
return handleCreate(request.getMsgId(), tokenRequest);
case "update":
return handleUpdate(request.getMsgId(), tokenRequest);
case "delete":
return handleDelete(request.getMsgId(), tokenRequest);
case "delete_all_by_user":
return handleDeleteAllByUser(request.getMsgId(), tokenRequest);
case "get_stats":
return handleGetStats(request.getMsgId(), tokenRequest);
case "filter":
return handleFilter(request.getMsgId(), tokenRequest);
default:
return new BaseResponse(
request.getMsgId(),
MessageCode.INVALID_ACTION.getCode(),
MessageCode.INVALID_ACTION.getDescription(),
Map.of("available_actions",
"get_list, get_by_id, get_by_user, create, update, " +
"delete, delete_all_by_user, get_stats, filter")
);
}
} catch (Exception e) {
log.error("Error handling TokenOperation request", e);
return new BaseResponse(
request.getMsgId(),
MessageCode.INTERNAL_ERROR.getCode(),
MessageCode.INTERNAL_ERROR.getDescription(),
Map.of("error", e.getMessage())
);
}
}
private BaseResponse handleGetList(Integer msgId, TokenOperationRequest request) {
if (request.getToken() == null) {
return new BaseResponse(
msgId,
MessageCode.USER_NOT_FOUND.getCode(),
MessageCode.USER_NOT_FOUND.getDescription(),
Map.of("error", "User ID is required")
);
}
Long userId = authService.useUserAuthToken(request.getToken());
try {
Page<TokenOperation> page = tokenOperationService.findByUserId(
userId,
request.getPage() != null ? request.getPage() : 0,
request.getSize() != null ? request.getSize() : 20
);
TokenOperationPageDto pageDto = TokenOperationPageDto.builder()
.content(page.getContent())
.pageNumber(page.getNumber())
.pageSize(page.getSize())
.totalElements(page.getTotalElements())
.totalPages(page.getTotalPages())
.last(page.isLast())
.first(page.isFirst())
.build();
Map<String, Object> responseData = new HashMap<>();
responseData.put("operations", pageDto);
responseData.put("total_elements", page.getTotalElements());
responseData.put("total_pages", page.getTotalPages());
responseData.put("current_page", page.getNumber());
responseData.put("page_size", page.getSize());
return new BaseResponse(
msgId,
MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(),
responseData
);
} catch (Exception e) {
log.error("Error getting token operations list", e);
return new BaseResponse(
msgId,
MessageCode.INTERNAL_ERROR.getCode(),
MessageCode.INTERNAL_ERROR.getDescription(),
Map.of("error", "Error getting operations: " + e.getMessage())
);
}
}
private BaseResponse handleGetById(Integer msgId, TokenOperationRequest request) {
log.info("Getting token operation by id: {}", request.getOperationId());
if (request.getOperationId() == null) {
return new BaseResponse(
msgId,
MessageCode.OPERATION_NOT_FOUND.getCode(),
MessageCode.OPERATION_NOT_FOUND.getDescription(),
Map.of("error", "Operation ID is required")
);
}
try {
TokenOperation operation = tokenOperationService.findById(request.getOperationId());
return new BaseResponse(
msgId,
MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(),
operation
);
} catch (jakarta.persistence.EntityNotFoundException e) {
return new BaseResponse(
msgId,
MessageCode.NOT_FOUND.getCode(),
MessageCode.NOT_FOUND.getDescription(),
Map.of("error", "Operation not found with id: " + request.getOperationId())
);
} catch (Exception e) {
log.error("Error getting token operation by id", e);
return new BaseResponse(
msgId,
MessageCode.INTERNAL_ERROR.getCode(),
MessageCode.INTERNAL_ERROR.getDescription(),
Map.of("error", e.getMessage())
);
}
}
private BaseResponse handleGetByUser(Integer msgId, TokenOperationRequest request) {
return handleGetList(msgId, request);
}
private BaseResponse handleCreate(Integer msgId, TokenOperationRequest request) {
if (request.getToken() == null) {
return new BaseResponse(
msgId,
MessageCode.AUTH_TOKEN_NOT_FOUND.getCode(),
MessageCode.AUTH_TOKEN_NOT_FOUND.getDescription(),
Map.of("error", "User ID is required")
);
}
Long userId = authService.useUserAuthToken(request.getToken());
try {
TokenOperation operation = tokenOperationService.create(
request.getOperationType(),
userId,
request.getSpent()
);
return new BaseResponse(
msgId,
MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(),
operation
);
} catch (Exception e) {
log.error("Error creating token operation", e);
return new BaseResponse(
msgId,
MessageCode.INTERNAL_ERROR.getCode(),
MessageCode.INTERNAL_ERROR.getDescription(),
Map.of("error", "Error creating operation: " + e.getMessage())
);
}
}
private BaseResponse handleUpdate(Integer msgId, TokenOperationRequest request) {
log.info("Updating token operation: {}", request.getOperationId());
if (request.getOperationId() == null) {
return new BaseResponse(
msgId,
MessageCode.OPERATION_NOT_FOUND.getCode(),
MessageCode.OPERATION_NOT_FOUND.getDescription(),
Map.of("error", "Operation ID is required")
);
}
try {
TokenOperation existing = tokenOperationService.findById(request.getOperationId());
if (request.getOperationType() != null) {
existing.setOperationType(request.getOperationType());
}
if (request.getSpent() != null) {
existing.setSpent(request.getSpent());
}
TokenOperation updated = tokenOperationService.update(request.getOperationId(), existing);
return new BaseResponse(
msgId,
MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(),
updated
);
} catch (jakarta.persistence.EntityNotFoundException e) {
return new BaseResponse(
msgId,
MessageCode.NOT_FOUND.getCode(),
MessageCode.NOT_FOUND.getDescription(),
Map.of("error", "Operation not found with id: " + request.getOperationId())
);
} catch (Exception e) {
log.error("Error updating token operation", e);
return new BaseResponse(
msgId,
MessageCode.INTERNAL_ERROR.getCode(),
MessageCode.INTERNAL_ERROR.getDescription(),
Map.of("error", "Error updating operation: " + e.getMessage())
);
}
}
private BaseResponse handleDelete(Integer msgId, TokenOperationRequest request) {
log.info("Deleting token operation: {}", request.getOperationId());
if (request.getOperationId() == null) {
return new BaseResponse(
msgId,
MessageCode.OPERATION_NOT_FOUND.getCode(),
MessageCode.OPERATION_NOT_FOUND.getDescription(),
Map.of("error", "Operation ID is required")
);
}
try {
tokenOperationService.deleteById(request.getOperationId());
return new BaseResponse(
msgId,
MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(),
Map.of("message", "Operation deleted successfully",
"operation_id", request.getOperationId())
);
} catch (jakarta.persistence.EntityNotFoundException e) {
return new BaseResponse(
msgId,
MessageCode.NOT_FOUND.getCode(),
MessageCode.NOT_FOUND.getDescription(),
Map.of("error", "Operation not found with id: " + request.getOperationId())
);
} catch (Exception e) {
log.error("Error deleting token operation", e);
return new BaseResponse(
msgId,
MessageCode.INTERNAL_ERROR.getCode(),
MessageCode.INTERNAL_ERROR.getDescription(),
Map.of("error", "Error deleting operation: " + e.getMessage())
);
}
}
private BaseResponse handleDeleteAllByUser(Integer msgId, TokenOperationRequest request) {
if (request.getToken() == null) {
return new BaseResponse(
msgId,
MessageCode.AUTH_TOKEN_NOT_FOUND.getCode(),
MessageCode.AUTH_TOKEN_NOT_FOUND.getDescription(),
Map.of("error", "User ID is required")
);
}
Long userId = authService.useUserAuthToken(request.getToken());
try {
tokenOperationService.deleteByUserId(userId);
return new BaseResponse(
msgId,
MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(),
Map.of("message", "All operations deleted successfully for user",
"user_id", userId)
);
} catch (Exception e) {
log.error("Error deleting all operations for user", e);
return new BaseResponse(
msgId,
MessageCode.INTERNAL_ERROR.getCode(),
MessageCode.INTERNAL_ERROR.getDescription(),
Map.of("error", "Error deleting operations: " + e.getMessage())
);
}
}
private BaseResponse handleGetStats(Integer msgId, TokenOperationRequest request) {
if (request.getToken() == null) {
return new BaseResponse(
msgId,
MessageCode.AUTH_TOKEN_NOT_FOUND.getCode(),
MessageCode.AUTH_TOKEN_NOT_FOUND.getDescription(),
Map.of("error", "User ID is required")
);
}
Long userId = authService.useUserAuthToken(request.getToken());
if (userId == null) {
return new BaseResponse(
msgId,
MessageCode.USER_NOT_FOUND.getCode(),
MessageCode.USER_NOT_FOUND.getDescription(),
Map.of("error", "User ID is required")
);
}
try {
Map<String, Long> statsByType = new HashMap<>();
long totalSpent = 0L;
for (OperationType type : OperationType.values()) {
Long spent = tokenOperationService.getTotalSpentByUserAndType(userId, type);
statsByType.put(type.name().toLowerCase(), spent != null ? spent : 0L);
totalSpent += spent != null ? spent : 0L;
}
Map<String, Object> statistics = new HashMap<>();
statistics.put("user_id", userId);
statistics.put("total_spent", totalSpent);
statistics.put("total_operations", tokenOperationService.countByUserId(userId));
statistics.put("stats_by_type", statsByType);
return new BaseResponse(
msgId,
MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(),
statistics
);
} catch (Exception e) {
log.error("Error getting statistics", e);
return new BaseResponse(
msgId,
MessageCode.INTERNAL_ERROR.getCode(),
MessageCode.INTERNAL_ERROR.getDescription(),
Map.of("error", "Error getting statistics: " + e.getMessage())
);
}
}
private BaseResponse handleFilter(Integer msgId, TokenOperationRequest request) {
if (request.getToken() == null) {
return new BaseResponse(
msgId,
MessageCode.AUTH_TOKEN_NOT_FOUND.getCode(),
MessageCode.AUTH_TOKEN_NOT_FOUND.getDescription(),
Map.of("error", "User ID is required")
);
}
Long userId = authService.useUserAuthToken(request.getToken());
try {
Page<TokenOperation> page = tokenOperationService.findByFilters(
userId,
request.getOperationType(),
request.getMinSpent(),
request.getMaxSpent(),
request.getPage() != null ? request.getPage() : 0,
request.getSize() != null ? request.getSize() : 20,
request.getSortBy() != null ? request.getSortBy() : "createdAt",
request.getSortDirection() != null ? request.getSortDirection() : "desc"
);
TokenOperationPageDto pageDto = TokenOperationPageDto.builder()
.content(page.getContent())
.pageNumber(page.getNumber())
.pageSize(page.getSize())
.totalElements(page.getTotalElements())
.totalPages(page.getTotalPages())
.last(page.isLast())
.first(page.isFirst())
.build();
Map<String, Object> responseData = new HashMap<>();
responseData.put("operations", pageDto);
responseData.put("total_elements", page.getTotalElements());
responseData.put("total_pages", page.getTotalPages());
responseData.put("current_page", page.getNumber());
responseData.put("page_size", page.getSize());
responseData.put("applied_filters", Map.of(
"user_id",userId != null ? userId : "all",
"operation_type", request.getOperationType() != null ? request.getOperationType() : "all",
"min_spent", request.getMinSpent() != null ? request.getMinSpent() : "none",
"max_spent", request.getMaxSpent() != null ? request.getMaxSpent() : "none"
));
return new BaseResponse(
msgId,
MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(),
responseData
);
} catch (Exception e) {
log.error("Error filtering operations", e);
return new BaseResponse(
msgId,
MessageCode.INTERNAL_ERROR.getCode(),
MessageCode.INTERNAL_ERROR.getDescription(),
Map.of("error", "Error filtering operations: " + e.getMessage())
);
}
}
}