Files
no-copy/src/main/java/ru/soune/nocopy/service/violation/ViolationService.java
T
backdev 3f0a514660
Test Workflow / test (push) Has been cancelled
dev fix sort
2026-04-24 14:14:04 +07:00

248 lines
10 KiB
Java

package ru.soune.nocopy.service.violation;
import lombok.AllArgsConstructor;
import org.apache.commons.codec.digest.DigestUtils;
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.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import ru.soune.nocopy.dto.file.YandexSearchResponse;
import ru.soune.nocopy.dto.violation.FileViolationSummaryDTO;
import ru.soune.nocopy.dto.violation.ViolationStatisticsResponse;
import ru.soune.nocopy.entity.file.FileEntity;
import ru.soune.nocopy.entity.search.GlobalSearchResult;
import ru.soune.nocopy.entity.violation.Violation;
import ru.soune.nocopy.repository.FileEntityRepository;
import ru.soune.nocopy.repository.ViolationRepository;
import ru.soune.nocopy.service.file.FileEntityService;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
@Service
@AllArgsConstructor
public class ViolationService {
private final ViolationRepository violationRepository;
private final FileEntityRepository fileEntityRepository;
private final FileEntityService fileEntityService;
public void processViolation(YandexSearchResponse.ImageResult imageResult, FileEntity file,
GlobalSearchResult result) {
String url = imageResult.getUrl();
String urlHash = DigestUtils.sha256Hex(url);
if (!violationRepository.existsByUrlHash(urlHash)) {
Violation violation = new Violation();
if (result != null) {
violation.setGlobalSearchResult(result);
}
violation.setHost(imageResult.getHost());
violation.setUrl(url);
violation.setUrlHash(urlHash);
violation.setPageUrl(imageResult.getPageUrl());
violation.setPageTitle(imageResult.getPageTitle());
violation.setFileEntity(file);
violation.setStatus(ViolationStatus.NEW.name());
violationRepository.save(violation);
}
}
public Violation getById(Long violationId) {
return violationRepository.findById(violationId).orElse(null);
}
public List<FileViolationSummaryDTO> getFileViolationsSummary(Long userId) {
List<FileEntity> userFiles = fileEntityService.getAllUserFiles(userId);
List<Violation> violations = violationRepository.findByFileEntityInAndStatusNot(userFiles,
ViolationStatus.NOT_OWNER_FILE.name());
Map<String, List<Violation>> violationsByFileId = violations.stream()
.collect(Collectors.groupingBy(v -> v.getFileEntity().getId()));
return userFiles.stream()
.map(file -> {
List<Violation> fileViolations = violationsByFileId.getOrDefault(file.getId(),
Collections.emptyList());
if (fileViolations.isEmpty()) {
return null;
}
LocalDateTime latestDate = fileViolations.stream()
.map(Violation::getCreatedDate)
.max(LocalDateTime::compareTo)
.orElse(null);
return FileViolationSummaryDTO.builder()
.fileId(file.getId())
.supportId(file.getSupportId())
.fileName(file.getOriginalFileName())
.fileSize(file.getFileSize())
.mimeType(file.getMimeType())
.status(file.getStatus())
.createdAt(file.getCreatedAt())
.violationCount(fileViolations.size())
.latestViolationDate(latestDate)
.build();
})
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
@Transactional
public void changeStatus(ViolationStatus status, Long violationId) {
Violation violation = violationRepository.findById(violationId).orElseThrow();
violation.setStatus(status.name());
violationRepository.save(violation);
}
public Page<Violation> getViolationsByFiles(List<FileEntity> files, int page, int size, String sortDirection) {
Sort sort = Sort.by(sortDirection.equalsIgnoreCase("desc") ? Sort.Direction.DESC : Sort.Direction.ASC,
"createdDate");
Pageable pageable = PageRequest.of(page, size, sort);
return violationRepository.findByFileEntityInAndStatusNot(files, ViolationStatus.NOT_OWNER_FILE.name(), pageable);
}
public Page<Violation> getViolationsByFilesAndStatus(List<FileEntity> files, String status, int page, int size, String sortDirection) {
Sort sort = Sort.by(sortDirection.equalsIgnoreCase("desc") ? Sort.Direction.DESC : Sort.Direction.ASC,
"createdDate");
Pageable pageable = PageRequest.of(page, size, sort);
return violationRepository.findByFileEntityInAndStatus(files, status, pageable);
}
public Page<Violation> getViolationsByFilesAndDateRange(List<FileEntity> files, LocalDateTime startDate, LocalDateTime endDate,
int page, int size, String sortDirection) {
Sort sort = Sort.by(sortDirection.equalsIgnoreCase("desc") ? Sort.Direction.DESC : Sort.Direction.ASC,
"createdDate");
Pageable pageable = PageRequest.of(page, size, sort);
return violationRepository.findByFileEntityInAndStatusNotAndCreatedDateBetween(files,
ViolationStatus.NOT_OWNER_FILE.name(), startDate, endDate, pageable);
}
public Map<String, Long> getGroupedViolations(List<FileEntity> files, String groupBy, String status,
LocalDateTime startDate, LocalDateTime endDate,
String sortDirection) {
List<Violation> violations;
if (status != null && !status.isEmpty() && startDate != null && endDate != null) {
violations = violationRepository.findByFileEntityInAndStatusAndCreatedDateBetween(files, status,
startDate, endDate);
} else if (status != null && !status.isEmpty()) {
violations = violationRepository.findByFileEntityInAndStatus(files, status);
} else if (startDate != null && endDate != null) {
violations = violationRepository.findByFileEntityInAndCreatedDateBetweenAndStatusNot(files, startDate,
endDate, ViolationStatus.NOT_OWNER_FILE.name());
} else {
violations = violationRepository.findByFileEntityInAndStatusNot(files,
ViolationStatus.NOT_OWNER_FILE.name());
}
Map<String, Long> grouped = violations.stream()
.collect(Collectors.groupingBy(
v -> extractGroupKey(v.getPageUrl(), groupBy),
Collectors.counting()));
return grouped.entrySet().stream()
.sorted((e1, e2) -> {
if (sortDirection.equalsIgnoreCase("desc")) {
return e2.getValue().compareTo(e1.getValue());
} else {
return e1.getValue().compareTo(e2.getValue());
}
})
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(e1, e2) -> e1,
LinkedHashMap::new));
}
public ViolationStatisticsResponse getViolationStatistics(Long userId, String fileId,
LocalDateTime startDate, LocalDateTime endDate) {
List<FileEntity> userFiles;
if (fileId != null && !fileId.isEmpty()) {
FileEntity file = fileEntityRepository.findById(fileId)
.orElseThrow(() -> new IllegalArgumentException("File not found with id: " + fileId));
if (!file.getUserId().equals(userId)) {
throw new IllegalArgumentException("File does not belong to user");
}
userFiles = List.of(file);
} else {
userFiles = fileEntityService.getAllUserFiles(userId);
}
if (userFiles.isEmpty()) {
return ViolationStatisticsResponse.builder()
.totalViolations(0)
.newViolations(0)
.inProgressViolations(0)
.resolvedViolations(0)
.build();
}
List<Violation> violations;
if (startDate != null && endDate != null) {
violations = violationRepository.findByFileEntityInAndCreatedDateBetweenAndStatusNot(userFiles,
startDate, endDate, ViolationStatus.NOT_OWNER_FILE.name());
} else {
violations = violationRepository.findByFileEntityInAndStatusNot(userFiles,
ViolationStatus.NOT_OWNER_FILE.name());
}
Set<String> inProgressStatuses = Set.of(
ViolationStatus.LEGAL_IN_WORK.name(),
ViolationStatus.COMPLAINT_IN_WORK.name(),
ViolationStatus.COMPLAINT_AND_LEGAL_IN_WORK.name()
);
long newViolations = violations.stream()
.filter(v -> v.getStatus().equals(ViolationStatus.NEW.name()))
.count();
long inProgressViolations = violations.stream()
.filter(v -> inProgressStatuses.contains(v.getStatus()))
.count();
long resolvedViolations = violations.stream()
.filter(v -> v.getStatus().equals(ViolationStatus.AUTHORIZED_USE.name()))
.count();
return ViolationStatisticsResponse.builder()
.totalViolations(violations.size())
.newViolations(newViolations)
.inProgressViolations(inProgressViolations)
.resolvedViolations(resolvedViolations)
.build();
}
private String extractGroupKey(String url, String groupBy) {
try {
String domain = url.replaceAll("https?://(www\\.)?", "").split("/")[0];
if ("tld".equalsIgnoreCase(groupBy)) {
int lastDot = domain.lastIndexOf('.');
return lastDot > 0 ? domain.substring(lastDot + 1) : domain;
}
return domain;
} catch (Exception e) {
return "unknown";
}
}
}