dev add statistic files protected
Test Workflow / test (push) Successful in 3s

This commit is contained in:
vladp
2026-04-15 18:12:32 +07:00
parent 1b921b525a
commit 2d80b40b27
12 changed files with 467 additions and 1 deletions
@@ -0,0 +1,118 @@
package ru.soune.nocopy.service.statistic;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import ru.soune.nocopy.dto.statistic.ProtectedFilesStatisticResponse;
import ru.soune.nocopy.repository.FileEntityRepository;
import ru.soune.nocopy.util.PercentileCalculator;
import java.util.List;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
@Slf4j
public class ProtectedFilesStatisticService {
private static final int PERCENTILE_5 = 5;
private static final int PERCENTILE_50 = 50;
private static final int PERCENTILE_95 = 95;
private static final double BYTES_TO_MB = 1048576.0;
private static final double BYTES_TO_GB = 1073741824.0;
private final FileEntityRepository fileEntityRepository;
public ProtectedFilesStatisticResponse getProtectedFilesStatistics() {
List<Object[]> totalStats = fileEntityRepository.getProtectedFilesTotalStats();
Long totalFiles = extractTotalFiles(totalStats);
Long totalSize = extractTotalSize(totalStats);
List<Object[]> userStats = fileEntityRepository.getProtectedFilesPerUserStats();
List<Long> fileCounts = extractFileCounts(userStats);
List<Long> fileSizes = extractFileSizes(userStats);
PercentileCalculator.PercentilesResult filesPercentiles =
PercentileCalculator.calculatePercentiles(fileCounts, PERCENTILE_5, PERCENTILE_50, PERCENTILE_95);
PercentileCalculator.PercentilesResult sizePercentiles =
PercentileCalculator.calculatePercentiles(fileSizes, PERCENTILE_5, PERCENTILE_50, PERCENTILE_95);
return buildResponse(totalFiles, totalSize, filesPercentiles, sizePercentiles);
}
private Long extractTotalFiles(List<Object[]> totalStats) {
if (totalStats.isEmpty() || totalStats.get(0) == null) {
return 0L;
}
Object[] row = totalStats.get(0);
return row[0] != null ? ((Number) row[0]).longValue() : 0L;
}
private Long extractTotalSize(List<Object[]> totalStats) {
if (totalStats.isEmpty() || totalStats.get(0) == null) {
return 0L;
}
Object[] row = totalStats.get(0);
return row[1] != null ? ((Number) row[1]).longValue() : 0L;
}
private List<Long> extractFileCounts(List<Object[]> userStats) {
return userStats.stream()
.map(row -> row[1] != null ? ((Number) row[1]).longValue() : 0L)
.collect(Collectors.toList());
}
private List<Long> extractFileSizes(List<Object[]> userStats) {
return userStats.stream()
.map(row -> row[2] != null ? ((Number) row[2]).longValue() : 0L)
.collect(Collectors.toList());
}
private ProtectedFilesStatisticResponse buildResponse(
Long totalFiles,
Long totalSize,
PercentileCalculator.PercentilesResult filesPercentiles,
PercentileCalculator.PercentilesResult sizePercentiles) {
ProtectedFilesStatisticResponse.Percentiles filesPerUser =
new ProtectedFilesStatisticResponse.Percentiles(
filesPercentiles.getP5(),
filesPercentiles.getP50(),
filesPercentiles.getP95());
ProtectedFilesStatisticResponse.SizePercentiles sizePerUser =
new ProtectedFilesStatisticResponse.SizePercentiles(
sizePercentiles.getP5(),
sizePercentiles.getP50(),
sizePercentiles.getP95(),
convertBytesToMb(sizePercentiles.getP5()),
convertBytesToMb(sizePercentiles.getP50()),
convertBytesToMb(sizePercentiles.getP95()));
return ProtectedFilesStatisticResponse.builder()
.totalFiles(totalFiles)
.totalSizeBytes(totalSize)
.totalSizeGb(convertBytesToGb(totalSize))
.filesPerUser(filesPerUser)
.sizePerUser(sizePerUser)
.build();
}
private Double convertBytesToMb(Long bytes) {
if (bytes == null || bytes == 0) {
return 0.0;
}
return bytes / BYTES_TO_MB;
}
private Double convertBytesToGb(Long bytes) {
if (bytes == null || bytes == 0) {
return 0.0;
}
return bytes / BYTES_TO_GB;
}
}
@@ -0,0 +1,46 @@
package ru.soune.nocopy.service.statistic;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import ru.soune.nocopy.dto.statistic.UserDynamicStatisticResponse;
import ru.soune.nocopy.repository.UserRepository;
@Service
@RequiredArgsConstructor
@Slf4j
public class UserDynamicStatisticService {
private final UserRepository userRepository;
public UserDynamicStatisticResponse getUserDynamicStatistics() {
Long totalUsers = userRepository.getTotalUsersCount();
Long newLast30Days = userRepository.getNewUsersCount(30);
Long totalUpTo60Days = userRepository.getNewUsersCount(60);
Long newPrevious30Days = totalUpTo60Days - newLast30Days;
Double growthPercent = calculateGrowthPercent(newLast30Days, newPrevious30Days);
Long newCurrentMonth = userRepository.getNewUsersCurrentMonth();
Long newPreviousMonth = userRepository.getNewUsersPreviousMonth();
Double monthGrowthPercent = calculateGrowthPercent(newCurrentMonth, newPreviousMonth);
return UserDynamicStatisticResponse.builder()
.totalUsers(totalUsers != null ? totalUsers : 0L)
.newLast30Days(newLast30Days != null ? newLast30Days : 0L)
.newPrevious30Days(newPrevious30Days != null ? newPrevious30Days : 0L)
.growthPercent(growthPercent)
.newCurrentMonth(newCurrentMonth != null ? newCurrentMonth : 0L)
.newPreviousMonth(newPreviousMonth != null ? newPreviousMonth : 0L)
.monthGrowthPercent(monthGrowthPercent)
.build();
}
private Double calculateGrowthPercent(Long current, Long previous) {
if (previous == null || previous == 0) {
return current != null && current > 0 ? 100.0 : 0.0;
}
double percent = ((current - previous) * 100.0) / previous;
return Math.round(percent * 100.0) / 100.0;
}
}