dev add check limits logic
Test Workflow / test (push) Successful in 3s

This commit is contained in:
vladp
2026-01-28 23:25:16 +07:00
parent 31fac0ab93
commit ec20d68261
12 changed files with 283 additions and 16 deletions
@@ -0,0 +1,79 @@
package ru.soune.nocopy.service.file;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.orm.ObjectOptimisticLockingFailureException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import ru.soune.nocopy.dto.file.CheckIncrementResult;
import ru.soune.nocopy.dto.file.CheckStatus;
import ru.soune.nocopy.entity.user.ProtectedFileCheck;
import ru.soune.nocopy.entity.user.User;
import ru.soune.nocopy.exception.RetryableException;
import ru.soune.nocopy.repository.ProtectedFileCheckRepository;
@Service
@RequiredArgsConstructor
@Slf4j
public class CheckCounterService {
private final ProtectedFileCheckRepository protectedFileCheckRepository;
@Transactional
public void incrementCheckCount(Long userId) {
try {
ProtectedFileCheck check = protectedFileCheckRepository.findByUser_Id(userId)
.orElseThrow(NullPointerException::new);
boolean success = check.incrementCheck();
if (success) {
protectedFileCheckRepository.save(check);
log.info("Check count incremented for user {}: count={}, limit={}",
userId, check.getCountChecked(), check.getLimitCheck());
CheckIncrementResult.success(check.getCountChecked(), check.getLimitCheck());
} else {
log.warn("Check limit exceeded for user {}", userId);
CheckIncrementResult.limitExceeded(check.getLimitCheck());
}
} catch (ObjectOptimisticLockingFailureException e) {
log.warn("Optimistic lock failure for user {}, retrying...", userId);
throw new RetryableException("Please try again");
}
}
@Transactional(readOnly = true)
public CheckStatus getCurrentStatus(Long userId) {
ProtectedFileCheck check = protectedFileCheckRepository.findByUser_Id(userId)
.orElseThrow(NullPointerException::new);
return CheckStatus.builder()
.userId(userId)
.countChecked(check.getCountChecked())
.remainingLimit(check.getLimitCheck())
.lastCheckAt(check.getLastCheckAt())
.build();
}
public void initProtectCheckLimit(User user, Integer checked, Integer limit) {
ProtectedFileCheck check = ProtectedFileCheck.builder()
.user(user)
.limitCheck(limit)
.countChecked(checked)
.build();
protectedFileCheckRepository.save(check);
}
@Transactional
public ProtectedFileCheck updateLimit(User user, Integer limit) {
ProtectedFileCheck check = ProtectedFileCheck.builder()
.user(user)
.limitCheck(limit)
.build();
return protectedFileCheckRepository.save(check);
}
}
@@ -1,7 +1,6 @@
package ru.soune.nocopy.service.register;
import lombok.RequiredArgsConstructor;
import org.springframework.context.MessageSource;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -15,6 +14,7 @@ import ru.soune.nocopy.exception.NotFoundAuthToken;
import ru.soune.nocopy.exception.NotValidFieldException;
import ru.soune.nocopy.repository.AuthTokenRepository;
import ru.soune.nocopy.repository.UserRepository;
import ru.soune.nocopy.service.file.CheckCounterService;
import java.security.SecureRandom;
import java.time.LocalDateTime;
@@ -30,7 +30,7 @@ public class AuthService {
private final PasswordEncoder passwordEncoder;
private final MessageSource messageSource;
private final CheckCounterService checkCounterService;
private final SecureRandom secureRandom = new SecureRandom();
@@ -55,6 +55,8 @@ public class AuthService {
AuthToken authToken = genereateAuthToken(savedUser);
checkCounterService.initProtectCheckLimit(user, 0, 10);
return authTokenRepository.save(authToken);
}
@@ -46,13 +46,7 @@ public class YandexSearchService {
objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
}
public YandexSearchResponse searchByFileEntity(String fileId) throws IOException {
FileEntity fileEntity = fileEntityRepository.findById(fileId)
.orElseThrow(() -> {
throw new NotValidFieldException("File not found", new BaseResponse(20007,
MessageCode.FILE_NOT_FOUND.getCode(), MessageCode.FILE_NOT_FOUND.getDescription(),
Map.of("fileId",fileId)));
});
public YandexSearchResponse searchByFileEntity(FileEntity fileEntity) throws IOException {
byte[] fileBytes;
if (!isImageFile(fileEntity)) {
@@ -67,7 +61,7 @@ public class YandexSearchService {
} catch (IOException e) {
throw new NotValidFieldException("File not found or cannot read file", new BaseResponse(20007,
MessageCode.FILE_NOT_FOUND.getCode(), MessageCode.FILE_NOT_FOUND.getDescription(),
Map.of("fileId", fileId,
Map.of("fileId", fileEntity.getId(),
"filePath", fileEntity.getFilePath())));
}