@@ -0,0 +1,187 @@
|
||||
package ru.soune.nocopy.service.file.moderation;
|
||||
|
||||
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.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import ru.soune.nocopy.dto.file.ModerationReasonResponse;
|
||||
import ru.soune.nocopy.entity.file.FileStatus;
|
||||
import ru.soune.nocopy.entity.file.moderation.ModerationReason;
|
||||
import ru.soune.nocopy.exception.ModerationReasonInUseException;
|
||||
import ru.soune.nocopy.exception.ModerationReasonNotFoundException;
|
||||
import ru.soune.nocopy.repository.FileEntityRepository;
|
||||
import ru.soune.nocopy.repository.ModerationReasonRepository;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ModerationReasonService {
|
||||
|
||||
private final ModerationReasonRepository moderationReasonRepository;
|
||||
private final FileEntityRepository fileEntityRepository;
|
||||
|
||||
private static final List<FileStatus> BLOCKED_STATUSES = Arrays.asList(
|
||||
FileStatus.BLOCKED,
|
||||
FileStatus.VIOLATION,
|
||||
FileStatus.MODERATION
|
||||
);
|
||||
|
||||
/**
|
||||
* Создание новой причины модерации
|
||||
*/
|
||||
@Transactional
|
||||
public ModerationReasonResponse createReason(String reasonText) {
|
||||
if (reasonText == null || reasonText.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("Reason text cannot be empty");
|
||||
}
|
||||
|
||||
// Проверяем на дубликат
|
||||
if (moderationReasonRepository.findByReasonText(reasonText.trim()).isPresent()) {
|
||||
throw new IllegalArgumentException("Reason with this text already exists");
|
||||
}
|
||||
|
||||
ModerationReason reason = ModerationReason.builder()
|
||||
.reasonText(reasonText.trim())
|
||||
.build();
|
||||
|
||||
ModerationReason saved = moderationReasonRepository.save(reason);
|
||||
|
||||
log.info("Created new moderation reason: id={}, text={}", saved.getId(), saved.getReasonText());
|
||||
|
||||
return convertToResponse(saved, false, 0L);
|
||||
}
|
||||
|
||||
/**
|
||||
* Обновление причины модерации
|
||||
*/
|
||||
@Transactional
|
||||
public ModerationReasonResponse updateReason(Long reasonId, String newReasonText) {
|
||||
ModerationReason reason = moderationReasonRepository.findById(reasonId)
|
||||
.orElseThrow(() -> new ModerationReasonNotFoundException(reasonId));
|
||||
|
||||
if (newReasonText == null || newReasonText.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("Reason text cannot be empty");
|
||||
}
|
||||
|
||||
// Проверяем на дубликат (исключая текущую запись)
|
||||
moderationReasonRepository.findByReasonText(newReasonText.trim())
|
||||
.ifPresent(existingReason -> {
|
||||
if (!existingReason.getId().equals(reasonId)) {
|
||||
throw new IllegalArgumentException("Reason with this text already exists");
|
||||
}
|
||||
});
|
||||
|
||||
String oldText = reason.getReasonText();
|
||||
reason.setReasonText(newReasonText.trim());
|
||||
|
||||
ModerationReason updated = moderationReasonRepository.save(reason);
|
||||
|
||||
log.info("Updated moderation reason: id={}, oldText={}, newText={}",
|
||||
reasonId, oldText, newReasonText);
|
||||
|
||||
long usageCount = getReasonUsageCount(reasonId);
|
||||
|
||||
return convertToResponse(updated, usageCount > 0, usageCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Удаление причины модерации
|
||||
*/
|
||||
@Transactional
|
||||
public void deleteReason(Long reasonId) {
|
||||
ModerationReason reason = moderationReasonRepository.findById(reasonId)
|
||||
.orElseThrow(() -> new ModerationReasonNotFoundException(reasonId));
|
||||
|
||||
// Проверяем, используется ли причина в активных блокировках
|
||||
long usageCount = getReasonUsageCount(reasonId);
|
||||
|
||||
if (usageCount > 0) {
|
||||
throw new ModerationReasonInUseException(reasonId, usageCount);
|
||||
}
|
||||
|
||||
moderationReasonRepository.delete(reason);
|
||||
|
||||
log.info("Deleted moderation reason: id={}, text={}", reasonId, reason.getReasonText());
|
||||
}
|
||||
|
||||
/**
|
||||
* Получение причины по ID
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public ModerationReasonResponse getReasonById(Long reasonId) {
|
||||
ModerationReason reason = moderationReasonRepository.findById(reasonId)
|
||||
.orElseThrow(() -> new ModerationReasonNotFoundException(reasonId));
|
||||
|
||||
long usageCount = getReasonUsageCount(reasonId);
|
||||
|
||||
return convertToResponse(reason, usageCount > 0, usageCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* Получение всех причин с пагинацией
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public Page<ModerationReasonResponse> getAllReasons(int page, int size, String searchQuery) {
|
||||
Pageable pageable = PageRequest.of(page, size, Sort.by("createdAt").descending());
|
||||
|
||||
Page<ModerationReason> reasonsPage;
|
||||
|
||||
if (searchQuery != null && !searchQuery.trim().isEmpty()) {
|
||||
reasonsPage = moderationReasonRepository.searchByText(searchQuery.trim(), pageable);
|
||||
} else {
|
||||
reasonsPage = moderationReasonRepository.findAll(pageable);
|
||||
}
|
||||
|
||||
return reasonsPage.map(reason -> {
|
||||
long usageCount = getReasonUsageCount(reason.getId());
|
||||
return convertToResponse(reason, usageCount > 0, usageCount);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Получение списка всех причин (без пагинации, для выпадающих списков)
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public List<ModerationReasonResponse> getAllReasonsList() {
|
||||
List<ModerationReason> reasons = moderationReasonRepository.findAll(Sort.by("reasonText").ascending());
|
||||
|
||||
return reasons.stream()
|
||||
.map(reason -> {
|
||||
long usageCount = getReasonUsageCount(reason.getId());
|
||||
return convertToResponse(reason, usageCount > 0, usageCount);
|
||||
})
|
||||
.collect(java.util.stream.Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Подсчет количества файлов, заблокированных по данной причине
|
||||
*/
|
||||
private long getReasonUsageCount(Long reasonId) {
|
||||
return fileEntityRepository.countByModerationReasonIdAndStatusIn(reasonId, BLOCKED_STATUSES);
|
||||
}
|
||||
|
||||
/**
|
||||
* Проверка, используется ли причина в активных блокировках
|
||||
*/
|
||||
public boolean isReasonInUse(Long reasonId) {
|
||||
return getReasonUsageCount(reasonId) > 0;
|
||||
}
|
||||
|
||||
private ModerationReasonResponse convertToResponse(ModerationReason reason, boolean isUsed, long usageCount) {
|
||||
return ModerationReasonResponse.builder()
|
||||
.id(reason.getId())
|
||||
.reasonText(reason.getReasonText())
|
||||
.createdAt(reason.getCreatedAt())
|
||||
.updatedAt(reason.getUpdatedAt())
|
||||
.isUsed(isUsed)
|
||||
.usageCount(usageCount)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user