@@ -51,9 +51,6 @@ public class FileEntityRequest {
|
|||||||
@JsonProperty("date_filter")
|
@JsonProperty("date_filter")
|
||||||
private String dateFilter;
|
private String dateFilter;
|
||||||
|
|
||||||
@JsonProperty("moderation_reason_id")
|
|
||||||
private Long moderationReasonId;
|
|
||||||
|
|
||||||
@JsonProperty("comment")
|
@JsonProperty("comment")
|
||||||
private String comment;
|
private String comment;
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ public class FileModerationInfo {
|
|||||||
private String ownerEmail;
|
private String ownerEmail;
|
||||||
private FileStatus currentStatus;
|
private FileStatus currentStatus;
|
||||||
private LocalDateTime uploadDate;
|
private LocalDateTime uploadDate;
|
||||||
private String moderationReason;
|
|
||||||
private Boolean hasActiveAppeal;
|
private Boolean hasActiveAppeal;
|
||||||
private AppealInfo activeAppeal;
|
private AppealInfo activeAppeal;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import ru.soune.nocopy.entity.file.FileStatus;
|
|||||||
public class ModerationActionRequest {
|
public class ModerationActionRequest {
|
||||||
private String fileId;
|
private String fileId;
|
||||||
private FileStatus newStatus;
|
private FileStatus newStatus;
|
||||||
private Long moderationReasonId;
|
|
||||||
private String comment;
|
private String comment;
|
||||||
private String token;
|
private String token;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
package ru.soune.nocopy.dto.file;
|
|
||||||
|
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@Builder
|
|
||||||
public class ModerationReasonRequest {
|
|
||||||
private String action;
|
|
||||||
private String token;
|
|
||||||
private Long reasonId;
|
|
||||||
private String reasonText;
|
|
||||||
private Integer page;
|
|
||||||
private Integer pageSize;
|
|
||||||
private String searchQuery;
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
package ru.soune.nocopy.dto.file;
|
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Data;
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@Builder
|
|
||||||
public class ModerationReasonResponse {
|
|
||||||
private Long id;
|
|
||||||
private String reasonText;
|
|
||||||
private LocalDateTime createdAt;
|
|
||||||
private LocalDateTime updatedAt;
|
|
||||||
private Boolean isUsed;
|
|
||||||
private Long usageCount;
|
|
||||||
}
|
|
||||||
@@ -52,9 +52,6 @@ public class FileAppeal {
|
|||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
private FileStatus moderationBeforeStatus;
|
private FileStatus moderationBeforeStatus;
|
||||||
|
|
||||||
@Column(name = "moderation_reason_id")
|
|
||||||
private Long moderationReasonId;
|
|
||||||
|
|
||||||
@Column(name = "resolved_at")
|
@Column(name = "resolved_at")
|
||||||
private LocalDateTime resolvedAt;
|
private LocalDateTime resolvedAt;
|
||||||
|
|
||||||
|
|||||||
@@ -87,9 +87,6 @@ public class FileEntity {
|
|||||||
@Column(name = "medium_path")
|
@Column(name = "medium_path")
|
||||||
private String mediumPath;
|
private String mediumPath;
|
||||||
|
|
||||||
@Column(name = "moderation_reason_id")
|
|
||||||
private Long moderationReasonId;
|
|
||||||
|
|
||||||
@OneToOne(mappedBy = "file", cascade = CascadeType.ALL, orphanRemoval = true)
|
@OneToOne(mappedBy = "file", cascade = CascadeType.ALL, orphanRemoval = true)
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
private ImageHashEntity imageHash;
|
private ImageHashEntity imageHash;
|
||||||
|
|||||||
@@ -44,9 +44,6 @@ public class ModerationLog {
|
|||||||
@Column(name = "reason", columnDefinition = "TEXT")
|
@Column(name = "reason", columnDefinition = "TEXT")
|
||||||
private String reason;
|
private String reason;
|
||||||
|
|
||||||
@Column(name = "moderation_reason_id")
|
|
||||||
private Long moderationReasonId;
|
|
||||||
|
|
||||||
@Column(name = "comment", columnDefinition = "TEXT")
|
@Column(name = "comment", columnDefinition = "TEXT")
|
||||||
private String comment;
|
private String comment;
|
||||||
|
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
package ru.soune.nocopy.entity.file.moderation;
|
|
||||||
|
|
||||||
import jakarta.persistence.*;
|
|
||||||
import lombok.*;
|
|
||||||
import org.springframework.data.annotation.CreatedDate;
|
|
||||||
import org.springframework.data.annotation.LastModifiedDate;
|
|
||||||
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
|
|
||||||
|
|
||||||
import java.time.LocalDateTime;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@Builder
|
|
||||||
@NoArgsConstructor
|
|
||||||
@AllArgsConstructor
|
|
||||||
@Entity
|
|
||||||
@Table(name = "moderation_reasons")
|
|
||||||
@EntityListeners(AuditingEntityListener.class)
|
|
||||||
public class ModerationReason {
|
|
||||||
|
|
||||||
@Id
|
|
||||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
|
||||||
private Long id;
|
|
||||||
|
|
||||||
@Column(name = "reason_text", nullable = false, columnDefinition = "TEXT")
|
|
||||||
private String reasonText;
|
|
||||||
|
|
||||||
@CreatedDate
|
|
||||||
@Column(name = "created_at", updatable = false)
|
|
||||||
private LocalDateTime createdAt;
|
|
||||||
|
|
||||||
@LastModifiedDate
|
|
||||||
@Column(name = "updated_at")
|
|
||||||
private LocalDateTime updatedAt;
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
package ru.soune.nocopy.exception;
|
|
||||||
|
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
public class ModerationReasonInUseException extends RuntimeException {
|
|
||||||
private final Long reasonId;
|
|
||||||
private final Long usageCount;
|
|
||||||
|
|
||||||
public ModerationReasonInUseException(Long reasonId, Long usageCount) {
|
|
||||||
super(String.format("Cannot delete moderation reason %d because it is used by %d files",
|
|
||||||
reasonId, usageCount));
|
|
||||||
this.reasonId = reasonId;
|
|
||||||
this.usageCount = usageCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
package ru.soune.nocopy.exception;
|
|
||||||
|
|
||||||
public class ModerationReasonNotFoundException extends RuntimeException {
|
|
||||||
public ModerationReasonNotFoundException(Long id) {
|
|
||||||
super("Moderation reason not found with id: " + id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -16,7 +16,6 @@ import ru.soune.nocopy.exception.*;
|
|||||||
import ru.soune.nocopy.repository.FileAppealRepository;
|
import ru.soune.nocopy.repository.FileAppealRepository;
|
||||||
import ru.soune.nocopy.repository.FileEntityRepository;
|
import ru.soune.nocopy.repository.FileEntityRepository;
|
||||||
import ru.soune.nocopy.repository.ModerationLogRepository;
|
import ru.soune.nocopy.repository.ModerationLogRepository;
|
||||||
import ru.soune.nocopy.service.file.moderation.ModerationReasonService;
|
|
||||||
import ru.soune.nocopy.service.file.moderation.ModerationService;
|
import ru.soune.nocopy.service.file.moderation.ModerationService;
|
||||||
import ru.soune.nocopy.service.register.AuthService;
|
import ru.soune.nocopy.service.register.AuthService;
|
||||||
import ru.soune.nocopy.service.file.FileEntityService;
|
import ru.soune.nocopy.service.file.FileEntityService;
|
||||||
@@ -47,8 +46,6 @@ public class FileEntityHandler implements RequestHandler {
|
|||||||
|
|
||||||
private final ModerationLogRepository moderationLogRepository;
|
private final ModerationLogRepository moderationLogRepository;
|
||||||
|
|
||||||
private final ModerationReasonService moderationReasonService;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BaseResponse handle(BaseRequest request) {
|
public BaseResponse handle(BaseRequest request) {
|
||||||
try {
|
try {
|
||||||
@@ -86,14 +83,6 @@ public class FileEntityHandler implements RequestHandler {
|
|||||||
return handleGetUserAppeals(request, fileRequest);
|
return handleGetUserAppeals(request, fileRequest);
|
||||||
case "files_for_moderation":
|
case "files_for_moderation":
|
||||||
return handleGetFilesForModeration(request, fileRequest);
|
return handleGetFilesForModeration(request, fileRequest);
|
||||||
case "get_moderation_reason":
|
|
||||||
return handleGetModerationReason(request, fileRequest);
|
|
||||||
case "create_moderation_reason":
|
|
||||||
return handleCreateModerationReason(request, fileRequest);
|
|
||||||
case "update_moderation_reason":
|
|
||||||
return handleUpdateModerationReason(request, fileRequest);
|
|
||||||
case "delete_moderation_reason":
|
|
||||||
return handleDeleteModerationReason(request, fileRequest);
|
|
||||||
default:
|
default:
|
||||||
ActionResponse response = ActionResponse.builder()
|
ActionResponse response = ActionResponse.builder()
|
||||||
.action(action)
|
.action(action)
|
||||||
@@ -629,7 +618,6 @@ public class FileEntityHandler implements RequestHandler {
|
|||||||
ModerationActionRequest moderationRequest = ModerationActionRequest.builder()
|
ModerationActionRequest moderationRequest = ModerationActionRequest.builder()
|
||||||
.fileId(fileRequest.getFileId())
|
.fileId(fileRequest.getFileId())
|
||||||
.newStatus(fileRequest.getFileStatus())
|
.newStatus(fileRequest.getFileStatus())
|
||||||
.moderationReasonId(fileRequest.getModerationReasonId())
|
|
||||||
.comment(fileRequest.getComment())
|
.comment(fileRequest.getComment())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
@@ -736,9 +724,6 @@ public class FileEntityHandler implements RequestHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Получение списка апелляций пользователя
|
|
||||||
*/
|
|
||||||
private BaseResponse handleGetUserAppeals(BaseRequest request, FileEntityRequest fileRequest) {
|
private BaseResponse handleGetUserAppeals(BaseRequest request, FileEntityRequest fileRequest) {
|
||||||
try {
|
try {
|
||||||
Long userId = authService.useUserAuthToken(fileRequest.getToken());
|
Long userId = authService.useUserAuthToken(fileRequest.getToken());
|
||||||
@@ -774,9 +759,6 @@ public class FileEntityHandler implements RequestHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Получение списка файлов на модерации
|
|
||||||
*/
|
|
||||||
private BaseResponse handleGetFilesForModeration(BaseRequest request, FileEntityRequest fileRequest) {
|
private BaseResponse handleGetFilesForModeration(BaseRequest request, FileEntityRequest fileRequest) {
|
||||||
try {
|
try {
|
||||||
//TODO
|
//TODO
|
||||||
@@ -843,9 +825,6 @@ public class FileEntityHandler implements RequestHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Получение детальной информации о файле для модерации
|
|
||||||
*/
|
|
||||||
private BaseResponse handleGetFileModerationInfo(BaseRequest request, FileEntityRequest fileRequest) {
|
private BaseResponse handleGetFileModerationInfo(BaseRequest request, FileEntityRequest fileRequest) {
|
||||||
try {
|
try {
|
||||||
// TODO
|
// TODO
|
||||||
@@ -907,9 +886,6 @@ public class FileEntityHandler implements RequestHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Получение истории модерации файла
|
|
||||||
*/
|
|
||||||
private List<Map<String, Object>> getModerationHistory(String fileId) {
|
private List<Map<String, Object>> getModerationHistory(String fileId) {
|
||||||
List<ModerationLog> logs = moderationLogRepository.findByFileIdOrderByCreatedAtDesc(fileId);
|
List<ModerationLog> logs = moderationLogRepository.findByFileIdOrderByCreatedAtDesc(fileId);
|
||||||
if (logs == null || logs.isEmpty()) {
|
if (logs == null || logs.isEmpty()) {
|
||||||
@@ -931,9 +907,6 @@ public class FileEntityHandler implements RequestHandler {
|
|||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Получение всех апелляций файла
|
|
||||||
*/
|
|
||||||
private List<Map<String, Object>> getFileAppeals(String fileId) {
|
private List<Map<String, Object>> getFileAppeals(String fileId) {
|
||||||
List<FileAppeal> appeals = fileAppealRepository.findByFileId(fileId);
|
List<FileAppeal> appeals = fileAppealRepository.findByFileId(fileId);
|
||||||
if (appeals == null || appeals.isEmpty()) {
|
if (appeals == null || appeals.isEmpty()) {
|
||||||
@@ -957,214 +930,6 @@ public class FileEntityHandler implements RequestHandler {
|
|||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Получение списка причин модерации
|
|
||||||
*/
|
|
||||||
private BaseResponse handleGetModerationReasons(BaseRequest request, FileEntityRequest fileRequest) {
|
|
||||||
try {
|
|
||||||
// TODO
|
|
||||||
// authService.useAdminAuthToken(fileRequest.getToken());
|
|
||||||
|
|
||||||
int page = fileRequest.getPage() != null ? fileRequest.getPage() : 1;
|
|
||||||
int pageSize = fileRequest.getPageSize() != null ? fileRequest.getPageSize() : 20;
|
|
||||||
String searchQuery = fileRequest.getSearchQuery();
|
|
||||||
|
|
||||||
Page<ModerationReasonResponse> reasons = moderationReasonService.getAllReasons(
|
|
||||||
page - 1, pageSize, searchQuery);
|
|
||||||
|
|
||||||
Map<String, Object> response = new HashMap<>();
|
|
||||||
response.put("reasons", reasons.getContent());
|
|
||||||
response.put("totalCount", reasons.getTotalElements());
|
|
||||||
response.put("totalPages", reasons.getTotalPages());
|
|
||||||
response.put("currentPage", page);
|
|
||||||
response.put("pageSize", pageSize);
|
|
||||||
|
|
||||||
return new BaseResponse(request.getMsgId(),
|
|
||||||
MessageCode.SUCCESS.getCode(),
|
|
||||||
MessageCode.SUCCESS.getDescription(),
|
|
||||||
response);
|
|
||||||
|
|
||||||
} catch (SecurityException e) {
|
|
||||||
return new BaseResponse(request.getMsgId(),
|
|
||||||
MessageCode.ACCESS_DENIED.getCode(),
|
|
||||||
"Admin access required",
|
|
||||||
null);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Error getting moderation reasons", e);
|
|
||||||
return new BaseResponse(request.getMsgId(),
|
|
||||||
MessageCode.INVALID_FIELD.getCode(),
|
|
||||||
"Failed to get reasons: " + e.getMessage(),
|
|
||||||
null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Получение конкретной причины модерации
|
|
||||||
*/
|
|
||||||
private BaseResponse handleGetModerationReason(BaseRequest request, FileEntityRequest fileRequest) {
|
|
||||||
try {
|
|
||||||
// TODO
|
|
||||||
// authService.useAdminAuthToken(fileRequest.getToken());
|
|
||||||
|
|
||||||
Long reasonId = fileRequest.getModerationReasonId();
|
|
||||||
if (reasonId == null) {
|
|
||||||
return new BaseResponse(request.getMsgId(),
|
|
||||||
MessageCode.INVALID_FIELD.getCode(),
|
|
||||||
"reasonId is required",
|
|
||||||
null);
|
|
||||||
}
|
|
||||||
|
|
||||||
ModerationReasonResponse reason = moderationReasonService.getReasonById(reasonId);
|
|
||||||
|
|
||||||
return new BaseResponse(request.getMsgId(),
|
|
||||||
MessageCode.SUCCESS.getCode(),
|
|
||||||
MessageCode.SUCCESS.getDescription(),
|
|
||||||
reason);
|
|
||||||
|
|
||||||
} catch (ModerationReasonNotFoundException e) {
|
|
||||||
return new BaseResponse(request.getMsgId(),
|
|
||||||
MessageCode.NOT_FOUND.getCode(),
|
|
||||||
e.getMessage(),
|
|
||||||
null);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Error getting moderation reason", e);
|
|
||||||
return new BaseResponse(request.getMsgId(),
|
|
||||||
MessageCode.INVALID_FIELD.getCode(),
|
|
||||||
"Failed to get reason: " + e.getMessage(),
|
|
||||||
null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Создание новой причины модерации
|
|
||||||
*/
|
|
||||||
private BaseResponse handleCreateModerationReason(BaseRequest request, FileEntityRequest fileRequest) {
|
|
||||||
try {
|
|
||||||
// TODO
|
|
||||||
// authService.useAdminAuthToken(fileRequest.getToken());
|
|
||||||
|
|
||||||
String reasonText = fileRequest.getReasonText();
|
|
||||||
if (reasonText == null || reasonText.trim().isEmpty()) {
|
|
||||||
return new BaseResponse(request.getMsgId(),
|
|
||||||
MessageCode.INVALID_FIELD.getCode(),
|
|
||||||
"reasonText is required",
|
|
||||||
null);
|
|
||||||
}
|
|
||||||
|
|
||||||
ModerationReasonResponse reason = moderationReasonService.createReason(reasonText);
|
|
||||||
|
|
||||||
return new BaseResponse(request.getMsgId(),
|
|
||||||
MessageCode.SUCCESS.getCode(),
|
|
||||||
"Moderation reason created successfully",
|
|
||||||
reason);
|
|
||||||
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
return new BaseResponse(request.getMsgId(),
|
|
||||||
MessageCode.INVALID_FIELD.getCode(),
|
|
||||||
e.getMessage(),
|
|
||||||
null);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Error creating moderation reason", e);
|
|
||||||
return new BaseResponse(request.getMsgId(),
|
|
||||||
MessageCode.INVALID_FIELD.getCode(),
|
|
||||||
"Failed to create reason: " + e.getMessage(),
|
|
||||||
null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Обновление причины модерации
|
|
||||||
*/
|
|
||||||
private BaseResponse handleUpdateModerationReason(BaseRequest request, FileEntityRequest fileRequest) {
|
|
||||||
try {
|
|
||||||
// TODO
|
|
||||||
// authService.useAdminAuthToken(fileRequest.getToken());
|
|
||||||
|
|
||||||
Long reasonId = fileRequest.getModerationReasonId();
|
|
||||||
String reasonText = fileRequest.getReasonText();
|
|
||||||
|
|
||||||
if (reasonId == null) {
|
|
||||||
return new BaseResponse(request.getMsgId(),
|
|
||||||
MessageCode.INVALID_FIELD.getCode(),
|
|
||||||
"reasonId is required",
|
|
||||||
null);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reasonText == null || reasonText.trim().isEmpty()) {
|
|
||||||
return new BaseResponse(request.getMsgId(),
|
|
||||||
MessageCode.INVALID_FIELD.getCode(),
|
|
||||||
"reasonText is required",
|
|
||||||
null);
|
|
||||||
}
|
|
||||||
|
|
||||||
ModerationReasonResponse reason = moderationReasonService.updateReason(reasonId, reasonText);
|
|
||||||
|
|
||||||
return new BaseResponse(request.getMsgId(),
|
|
||||||
MessageCode.SUCCESS.getCode(),
|
|
||||||
"Moderation reason updated successfully",
|
|
||||||
reason);
|
|
||||||
|
|
||||||
} catch (ModerationReasonNotFoundException e) {
|
|
||||||
return new BaseResponse(request.getMsgId(),
|
|
||||||
MessageCode.NOT_FOUND.getCode(),
|
|
||||||
e.getMessage(),
|
|
||||||
null);
|
|
||||||
} catch (IllegalArgumentException e) {
|
|
||||||
return new BaseResponse(request.getMsgId(),
|
|
||||||
MessageCode.INVALID_FIELD.getCode(),
|
|
||||||
e.getMessage(),
|
|
||||||
null);
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Error updating moderation reason", e);
|
|
||||||
return new BaseResponse(request.getMsgId(),
|
|
||||||
MessageCode.INVALID_FIELD.getCode(),
|
|
||||||
"Failed to update reason: " + e.getMessage(),
|
|
||||||
null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Удаление причины модерации
|
|
||||||
*/
|
|
||||||
private BaseResponse handleDeleteModerationReason(BaseRequest request, FileEntityRequest fileRequest) {
|
|
||||||
try {
|
|
||||||
// TODO
|
|
||||||
// authService.useAdminAuthToken(fileRequest.getToken());
|
|
||||||
|
|
||||||
Long reasonId = fileRequest.getModerationReasonId();
|
|
||||||
if (reasonId == null) {
|
|
||||||
return new BaseResponse(request.getMsgId(),
|
|
||||||
MessageCode.INVALID_FIELD.getCode(),
|
|
||||||
"reasonId is required",
|
|
||||||
null);
|
|
||||||
}
|
|
||||||
|
|
||||||
moderationReasonService.deleteReason(reasonId);
|
|
||||||
|
|
||||||
return new BaseResponse(request.getMsgId(),
|
|
||||||
MessageCode.SUCCESS.getCode(),
|
|
||||||
"Moderation reason deleted successfully",
|
|
||||||
Map.of("reasonId", reasonId));
|
|
||||||
|
|
||||||
} catch (ModerationReasonNotFoundException e) {
|
|
||||||
return new BaseResponse(request.getMsgId(),
|
|
||||||
MessageCode.NOT_FOUND.getCode(),
|
|
||||||
e.getMessage(),
|
|
||||||
null);
|
|
||||||
} catch (ModerationReasonInUseException e) {
|
|
||||||
return new BaseResponse(request.getMsgId(),
|
|
||||||
MessageCode.INVALID_FIELD.getCode(),
|
|
||||||
e.getMessage(),
|
|
||||||
Map.of("usageCount", e.getUsageCount()));
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Error deleting moderation reason", e);
|
|
||||||
return new BaseResponse(request.getMsgId(),
|
|
||||||
MessageCode.INVALID_FIELD.getCode(),
|
|
||||||
"Failed to delete reason: " + e.getMessage(),
|
|
||||||
null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private String formatFileSize(long size) {
|
private String formatFileSize(long size) {
|
||||||
if (size < 1024) return size + " B";
|
if (size < 1024) return size + " B";
|
||||||
int exp = (int) (Math.log(size) / Math.log(1024));
|
int exp = (int) (Math.log(size) / Math.log(1024));
|
||||||
|
|||||||
@@ -72,8 +72,4 @@ public interface FileEntityRepository extends JpaRepository<FileEntity, String>
|
|||||||
Page<FileEntity> findByStatusIn(List<FileStatus> statuses, Pageable pageable);
|
Page<FileEntity> findByStatusIn(List<FileStatus> statuses, Pageable pageable);
|
||||||
|
|
||||||
List<FileEntity> findByUserIdAndStatusIn(Long userId, List<FileStatus> statuses);
|
List<FileEntity> findByUserIdAndStatusIn(Long userId, List<FileStatus> statuses);
|
||||||
|
|
||||||
@Query("SELECT COUNT(f) FROM FileEntity f WHERE f.moderationReasonId = :reasonId AND f.status IN :statuses")
|
|
||||||
long countByModerationReasonIdAndStatusIn(@Param("reasonId") Long reasonId,
|
|
||||||
@Param("statuses") List<FileStatus> statuses);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
package ru.soune.nocopy.repository;
|
|
||||||
|
|
||||||
import org.springframework.data.domain.Page;
|
|
||||||
import org.springframework.data.domain.Pageable;
|
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
|
||||||
import org.springframework.data.jpa.repository.Query;
|
|
||||||
import org.springframework.data.repository.query.Param;
|
|
||||||
import ru.soune.nocopy.entity.file.moderation.ModerationReason;
|
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
public interface ModerationReasonRepository extends JpaRepository<ModerationReason, Long> {
|
|
||||||
Optional<ModerationReason> findByReasonText(String reasonText);
|
|
||||||
|
|
||||||
Page<ModerationReason> findAll(Pageable pageable);
|
|
||||||
|
|
||||||
@Query("SELECT mr FROM ModerationReason mr WHERE mr.reasonText LIKE %:search%")
|
|
||||||
Page<ModerationReason> searchByText(@Param("search") String search, Pageable pageable);
|
|
||||||
|
|
||||||
@Query("SELECT COUNT(mr) FROM ModerationReason mr")
|
|
||||||
long countAllReasons();
|
|
||||||
}
|
|
||||||
@@ -1,184 +0,0 @@
|
|||||||
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.deleteById(reasonId);
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -57,14 +57,13 @@ public class ModerationService {
|
|||||||
.oldStatus(file.getStatus())
|
.oldStatus(file.getStatus())
|
||||||
.newStatus(request.getNewStatus())
|
.newStatus(request.getNewStatus())
|
||||||
.reason(request.getComment())
|
.reason(request.getComment())
|
||||||
.moderationReasonId(request.getModerationReasonId())
|
|
||||||
.comment(request.getComment())
|
.comment(request.getComment())
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
moderationLogRepository.save(log);
|
moderationLogRepository.save(log);
|
||||||
|
|
||||||
file.setStatus(request.getNewStatus());
|
file.setStatus(request.getNewStatus());
|
||||||
file.setModerationReasonId(request.getModerationReasonId());
|
|
||||||
fileEntityRepository.save(file);
|
fileEntityRepository.save(file);
|
||||||
|
|
||||||
if (request.getNewStatus() == FileStatus.BLOCKED ||
|
if (request.getNewStatus() == FileStatus.BLOCKED ||
|
||||||
@@ -107,7 +106,6 @@ public class ModerationService {
|
|||||||
.additionalInfo(request.getAdditionalInfo())
|
.additionalInfo(request.getAdditionalInfo())
|
||||||
.status(AppealStatus.PENDING)
|
.status(AppealStatus.PENDING)
|
||||||
.moderationBeforeStatus(file.getStatus())
|
.moderationBeforeStatus(file.getStatus())
|
||||||
.moderationReasonId(file.getModerationReasonId())
|
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
FileAppeal saved = fileAppealRepository.save(appeal);
|
FileAppeal saved = fileAppealRepository.save(appeal);
|
||||||
@@ -137,7 +135,6 @@ public class ModerationService {
|
|||||||
|
|
||||||
if (approve) {
|
if (approve) {
|
||||||
file.setStatus(FileStatus.ACTIVE);
|
file.setStatus(FileStatus.ACTIVE);
|
||||||
file.setModerationReasonId(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ModerationLog log = ModerationLog.builder()
|
ModerationLog log = ModerationLog.builder()
|
||||||
|
|||||||
Reference in New Issue
Block a user