Files
no-copy/src/main/java/ru/soune/nocopy/handler/FileEntityHandler.java
T
backdev 646d6fa11d
Test Workflow / test (push) Has been cancelled
dev add complaint all info with pagination
2026-05-26 14:47:56 +07:00

941 lines
39 KiB
Java

package ru.soune.nocopy.handler;
import com.fasterxml.jackson.databind.ObjectMapper;
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.Component;
import org.springframework.transaction.annotation.Transactional;
import ru.soune.nocopy.dto.*;
import ru.soune.nocopy.dto.file.*;
import ru.soune.nocopy.entity.file.*;
import ru.soune.nocopy.entity.file.moderation.ModerationLog;
import ru.soune.nocopy.entity.file.permission.PermissionType;
import ru.soune.nocopy.entity.monitoring.FileMonitoringEntity;
import ru.soune.nocopy.exception.*;
import ru.soune.nocopy.repository.*;
import ru.soune.nocopy.service.file.cloud.CloudStorageService;
import ru.soune.nocopy.service.file.moderation.ModerationService;
import ru.soune.nocopy.service.file.permission.FileAccessService;
import ru.soune.nocopy.service.register.AuthService;
import ru.soune.nocopy.service.file.FileEntityService;
import ru.soune.nocopy.service.file.FileStatsService;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;
@Slf4j
@Component
@RequiredArgsConstructor
public class FileEntityHandler implements RequestHandler {
private final FileEntityService fileEntityService;
private final AuthService authService;
private final FileStatsService fileStatsService;
private final ObjectMapper objectMapper;
private final FileEntityRepository fileEntityRepository;
private final FileMonitoringRepository fileMonitoringRepository;
private final CloudStorageService cloudStorageService;
private final ModerationService moderationService;
private final FileAppealRepository fileAppealRepository;
private final ModerationLogRepository moderationLogRepository;
private final ImageHashRepository imageHashRepository;
private final FileAccessService fileAccessService;
@Override
public BaseResponse handle(BaseRequest request) {
try {
FileEntityRequest fileRequest = objectMapper.convertValue(
request.getMessageBody(), FileEntityRequest.class);
String action = fileRequest.getAction();
switch (action) {
case "file_info":
return handleGetFileInfo(request, fileRequest);
case "user_files_info":
return handleGetFilesUserInfo(request, fileRequest);
case "file_by_session":
return handleGetFileBySession(request, fileRequest);
case "user_files":
return handleGetUserFiles(request, fileRequest);
case "search_files":
return handleSearchFiles(request, fileRequest);
case "storage_usage":
return handleGetStorageUsage(request, fileRequest);
case "check_protected":
return handleProtectFile(request, fileRequest);
case "delete_file":
return handleDeleteFile(request, fileRequest);
case "delete_files":
return handleDeleteFiles(request, fileRequest);
case "submit_appeal":
return handleSubmitAppeal(request, fileRequest);
case "user_appeals":
return handleGetUserAppeals(request, fileRequest);
case "change_permission":
return handleChangePermission(request, fileRequest);
default:
ActionResponse response = ActionResponse.builder()
.action(action)
.availableActions(Arrays.asList(
"file_info", "file_by_session", "user_files",
"search_files", "storage_usage", "delete_file",
"user_files_info"))
.build();
return new BaseResponse(request.getMsgId(),
MessageCode.INVALID_ACTION.getCode(),
"Invalid action: " + action,
response);
}
} catch (Exception e) {
log.error("Error in FileEntityHandler", e);
return new BaseResponse(request.getMsgId(),
MessageCode.FILE_UPLOAD_ERROR.getCode(),
"Handler error: " + e.getMessage(),
null);
}
}
private BaseResponse handleGetFilesUserInfo(BaseRequest request, FileEntityRequest fileRequest) {
Long userId = authService.useUserAuthToken(fileRequest.getToken());
FileInfoUserResponse userFileStats = fileStatsService.getUserFileStats(userId);
return new BaseResponse(request.getMsgId(),
MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(),
userFileStats);
}
private BaseResponse handleGetFileInfo(BaseRequest request, FileEntityRequest fileRequest) {
try {
Long userId = authService.useUserAuthToken(fileRequest.getToken());
FileEntityResponse fileInfo = fileEntityService.getById(fileRequest.getFileId(), request.getVersion());
if (!fileInfo.getUserId().equals(userId)) {
return new BaseResponse(request.getMsgId(),
MessageCode.ACCESS_DENIED.getCode(),
"Access denied",
null);
}
return new BaseResponse(request.getMsgId(),
MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(),
fileInfo);
} catch (NotFoundAuthToken e) {
return new BaseResponse(request.getMsgId(),
MessageCode.INVALID_TOKEN.getCode(),
"Authentication required",
null);
} catch (Exception e) {
log.error("Error getting file info", e);
return new BaseResponse(request.getMsgId(),
MessageCode.FILE_UPLOAD_ERROR.getCode(),
"Failed to get file info: " + e.getMessage(),
null);
}
}
private BaseResponse handleChangePermission(BaseRequest request, FileEntityRequest fileRequest) {
try {
Long userId = authService.useUserAuthToken(fileRequest.getToken());
FileEntityResponse fileInfo = fileEntityService.getById(fileRequest.getFileId(), request.getVersion());
if (!fileInfo.getUserId().equals(userId)) {
return new BaseResponse(request.getMsgId(),
MessageCode.ACCESS_DENIED.getCode(),
"Access denied",
null);
}
Map<String, Boolean> permissions = fileRequest.getPermissions();
if (!PermissionType.areAllValid(permissions)) {
return new BaseResponse(request.getMsgId(),
MessageCode.PERMISSION_NOT_VALID.getCode(),
MessageCode.PERMISSION_NOT_VALID.getDescription(),
null);
}
for (Map.Entry<String, Boolean> entry: permissions.entrySet()) {
try {
fileAccessService.changePermission(fileInfo.getId(), PermissionType.valueOf(entry.getKey()),
entry.getValue());
} catch (FileEntityNotFoundException e) {
return new BaseResponse(request.getMsgId(),
MessageCode.FILE_NOT_FOUND.getCode(),
MessageCode.FILE_NOT_FOUND.getDescription(),
null);
}
}
return new BaseResponse(request.getMsgId(),
MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(),
fileInfo);
} catch (NotFoundAuthToken e) {
return new BaseResponse(request.getMsgId(),
MessageCode.INVALID_TOKEN.getCode(),
"Authentication required",
null);
} catch (Exception e) {
log.error("Error getting file info", e);
return new BaseResponse(request.getMsgId(),
MessageCode.FILE_UPLOAD_ERROR.getCode(),
"Failed to get file info: " + e.getMessage(),
null);
}
}
private BaseResponse handleGetFileBySession(BaseRequest request, FileEntityRequest fileRequest) {
try {
Long userId = authService.useUserAuthToken(fileRequest.getToken());
FileEntityResponse fileInfo = fileEntityService.getByUploadSessionId(fileRequest.getUploadSessionId(),
request.getVersion());
if (!fileInfo.getUserId().equals(userId)) {
return new BaseResponse(request.getMsgId(),
MessageCode.ACCESS_DENIED.getCode(),
"Access denied",
null);
}
return new BaseResponse(request.getMsgId(),
MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(),
fileInfo);
} catch (NotFoundAuthToken e) {
return new BaseResponse(request.getMsgId(),
MessageCode.INVALID_TOKEN.getCode(),
"Authentication required",
null);
} catch (Exception e) {
log.error("Error getting file by session", e);
return new BaseResponse(request.getMsgId(),
MessageCode.FILE_UPLOAD_ERROR.getCode(),
"Failed to get file: " + e.getMessage(),
null);
}
}
private BaseResponse handleGetUserFiles(BaseRequest request, FileEntityRequest fileRequest) {
try {
Long userId = authService.useUserAuthToken(fileRequest.getToken());
int page = fileRequest.getPage() != null ? fileRequest.getPage() : 1;
int pageSize = fileRequest.getPageSize() != null ? fileRequest.getPageSize() : 20;
FileResponse files = fileEntityService.getUserFiles(userId, page, pageSize, request.getVersion());
return new BaseResponse(request.getMsgId(),
MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(),
files);
} catch (NotFoundAuthToken e) {
return new BaseResponse(request.getMsgId(),
MessageCode.INVALID_TOKEN.getCode(),
"Authentication required",
null);
} catch (Exception e) {
log.error("Error getting user files", e);
return new BaseResponse(request.getMsgId(),
MessageCode.FILE_UPLOAD_ERROR.getCode(),
"Failed to get files: " + e.getMessage(),
null);
}
}
private BaseResponse handleSearchFiles(BaseRequest request, FileEntityRequest fileRequest) {
try {
Long userId = authService.useUserAuthToken(fileRequest.getToken());
int page = fileRequest.getPage() != null ? fileRequest.getPage() : 1;
int pageSize = fileRequest.getPageSize() != null ? fileRequest.getPageSize() : 20;
String sortBy = fileRequest.getSortBy() != null ? fileRequest.getSortBy() : "fileName";
SortOrder sortOrder = SortOrder.fromString(fileRequest.getSortOrder());
FileResponse allFiles = fileEntityService.getUserFiles(userId, 1, 1000, request.getVersion());
String searchQuery = fileRequest.getQuery() != null ? fileRequest.getQuery().toLowerCase().trim() : "";
String[] searchTerms = searchQuery.split("\\s+");
String filterType = fileRequest.getType();
String dateFilter = fileRequest.getDateFilter();
List<FileEntityResponse> filteredFiles = allFiles.getFiles().stream()
.filter(f -> matchesSearch(f, searchTerms, searchQuery, filterType))
.filter(f -> matchesDateFilter(f, dateFilter))
.collect(Collectors.toList());
Comparator<FileEntityResponse> comparator = getComparator(sortBy, sortOrder);
filteredFiles.sort(comparator);
int start = (page - 1) * pageSize;
int end = Math.min(start + pageSize, filteredFiles.size());
if (start >= filteredFiles.size()) {
return createEmptyResponse(request, page, pageSize, sortBy, sortOrder.getValue());
}
List<FileEntityResponse> paginatedFiles = filteredFiles.subList(start, end);
long totalSize = paginatedFiles.stream()
.mapToLong(FileEntityResponse::getFileSize)
.sum();
FileListResponse response = FileListResponse.builder()
.files(paginatedFiles)
.totalCount(filteredFiles.size())
.totalSize(totalSize)
.formattedTotalSize(fileEntityService.formatFileSize(totalSize))
.page(page)
.pageSize(pageSize)
.sortBy(sortBy)
.sortOrder(sortOrder.getValue())
.build();
return new BaseResponse(request.getMsgId(),
MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(),
response);
} catch (NotFoundAuthToken e) {
return new BaseResponse(request.getMsgId(),
MessageCode.INVALID_TOKEN.getCode(),
"Authentication required", null);
} catch (Exception e) {
log.error("Error searching files", e);
return new BaseResponse(request.getMsgId(),
MessageCode.FILE_UPLOAD_ERROR.getCode(),
"Failed to search files: " + e.getMessage(), null);
}
}
private boolean matchesDateFilter(FileEntityResponse file, String dateFilter) {
if (dateFilter == null || dateFilter.isEmpty()) {
return true;
}
LocalDate fileDate = file.getCreatedAt().toLocalDate();
LocalDate now = LocalDate.now();
switch (dateFilter.toLowerCase()) {
case "today":
return fileDate.equals(now);
case "week":
return fileDate.isAfter(now.minusWeeks(1)) && !fileDate.isAfter(now);
case "month":
return fileDate.isAfter(now.minusMonths(1)) && !fileDate.isAfter(now);
default:
return true;
}
}
private boolean matchesSearch(FileEntityResponse file, String[] searchTerms, String fullQuery, String type) {
String fileName = getSafeString(file.getFileName());
String originalFileName = getSafeString(file.getOriginalFileName());
String mimeType = getSafeString(file.getMimeType());
String fileFormat = getSafeString(file.getFileFormat());
String fullFileName = fileName + " " + originalFileName;
boolean matchesType = true;
if (type != null && !type.isEmpty()) {
matchesType = matchesMimeType(mimeType, type);
}
if (!matchesType) {
return false;
}
if (fullQuery != null && !fullQuery.isEmpty()) {
if (fullFileName.toLowerCase().contains(fullQuery)) {
return true;
}
for (String term : searchTerms) {
if (term.length() < 2) continue;
if (fullFileName.toLowerCase().contains(term)) {
return true;
}
}
if (fileFormat.toLowerCase().contains(fullQuery)) {
return true;
}
if (mimeType.toLowerCase().contains(fullQuery)) {
return true;
}
if (!fileFormat.isEmpty() && !fileName.toLowerCase().endsWith("." + fileFormat.toLowerCase())) {
String fileNameWithExtension = fileName + "." + fileFormat;
if (fileNameWithExtension.toLowerCase().contains(fullQuery)) {
return true;
}
}
return false;
}
return true;
}
private boolean matchesMimeType(String mimeType, String filterType) {
if (filterType == null || filterType.isEmpty()) return true;
String mimeTypeLower = mimeType.toLowerCase();
String filterTypeLower = filterType.toLowerCase().trim();
return mimeTypeLower.equals(filterTypeLower);
}
private String getSafeString(String value) {
return value != null ? value : "";
}
private Comparator<FileEntityResponse> getComparator(String sortBy, SortOrder sortOrder) {
Comparator<FileEntityResponse> comparator;
switch (sortBy) {
case "fileSize":
comparator = Comparator.comparingLong(
FileEntityResponse::getFileSize
);
break;
case "fileType":
comparator = Comparator.comparing(
FileEntityResponse::getMimeType);
break;
case "createdAt":
comparator = Comparator.comparing(
FileEntityResponse::getCreatedAt,
Comparator.nullsLast(Comparator.naturalOrder())
);
break;
case "updatedAt":
comparator = Comparator.comparing(
FileEntityResponse::getUpdatedAt,
Comparator.nullsLast(Comparator.naturalOrder())
);
break;
case "fileName":
comparator = Comparator.comparing(
f -> getSafeString(f.getFileName()).toLowerCase(),
Comparator.nullsLast(Comparator.naturalOrder())
);
break;
case "protectStatus":
comparator = Comparator.comparing(
f -> getSafeString(f.getProtectStatus()).toLowerCase(),
Comparator.nullsLast(Comparator.naturalOrder())
);
break;
case "supportId":
comparator = Comparator.comparing(
FileEntityResponse::getSupportId,
Comparator.nullsLast(Comparator.naturalOrder())
);
break;
case "monitoring":
Map<String, Integer> monitoringOrder = Map.of(
"MONITORING_DAILY", 1,
"MONITORING_WEEKLY", 2,
"MONITORING_MONTHLY", 3
);
comparator = Comparator.comparing(
response -> monitoringOrder.getOrDefault(response.getMonitoring(),
Integer.MAX_VALUE), Comparator.nullsLast(Comparator.naturalOrder())
);
break;
default:
comparator = Comparator.comparing(
f -> getSafeString(f.getFileName()).toLowerCase(),
Comparator.nullsLast(Comparator.naturalOrder())
);
break;
}
return sortOrder == SortOrder.DESC ? comparator.reversed() : comparator;
}
private BaseResponse createEmptyResponse(BaseRequest request, int page, int pageSize,
String sortBy, String sortOrder) {
FileListResponse emptyResponse = FileListResponse.builder()
.files(Collections.emptyList())
.totalCount(0)
.totalSize(0L)
.formattedTotalSize("0 B")
.page(page)
.pageSize(pageSize)
.sortBy(sortBy)
.sortOrder(sortOrder)
.build();
return new BaseResponse(request.getMsgId(),
MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(),
emptyResponse);
}
private BaseResponse handleGetUserFilesWithSort(BaseRequest request, FileEntityRequest fileRequest,
String sortBy, SortOrder sortOrder) {
try {
Long userId = authService.useUserAuthToken(fileRequest.getToken());
int page = fileRequest.getPage() != null ? fileRequest.getPage() : 1;
int pageSize = fileRequest.getPageSize() != null ? fileRequest.getPageSize() : 20;
FileResponse allFiles = fileEntityService.getUserFiles(userId, 1, 1000, request.getVersion());
List<FileEntityResponse> files = new ArrayList<>(allFiles.getFiles());
Comparator<FileEntityResponse> comparator = getComparator(sortBy, sortOrder);
files.sort(comparator);
int start = (page - 1) * pageSize;
int end = Math.min(start + pageSize, files.size());
if (start >= files.size()) {
return createEmptyResponse(request, page, pageSize, sortBy, sortOrder.getValue());
}
List<FileEntityResponse> paginatedFiles = files.subList(start, end);
long totalSize = paginatedFiles.stream()
.mapToLong(FileEntityResponse::getFileSize)
.sum();
FileListResponse response = FileListResponse.builder()
.files(paginatedFiles)
.totalCount(files.size())
.totalSize(totalSize)
.formattedTotalSize(fileEntityService.formatFileSize(totalSize))
.page(page)
.pageSize(pageSize)
.sortBy(sortBy)
.sortOrder(sortOrder.getValue())
.build();
return new BaseResponse(request.getMsgId(),
MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(),
response);
} catch (NotFoundAuthToken e) {
return new BaseResponse(request.getMsgId(),
MessageCode.INVALID_TOKEN.getCode(),
"Authentication required", null);
} catch (Exception e) {
log.error("Error getting user files with sort", e);
return new BaseResponse(request.getMsgId(),
MessageCode.FILE_UPLOAD_ERROR.getCode(),
"Failed to get files: " + e.getMessage(),
null);
}
}
private BaseResponse handleGetStorageUsage(BaseRequest request, FileEntityRequest fileRequest) {
try {
Long userId = authService.useUserAuthToken(fileRequest.getToken());
long usage = fileEntityService.getUserStorageUsed(userId);
StorageUsageResponse response = StorageUsageResponse.builder()
.userId(userId)
.storageUsed(usage)
.formattedStorageUsed(formatFileSize(usage))
.build();
return new BaseResponse(request.getMsgId(),
MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(),
response);
} catch (NotFoundAuthToken e) {
return new BaseResponse(request.getMsgId(),
MessageCode.INVALID_TOKEN.getCode(),
"Authentication required",
null);
} catch (Exception e) {
log.error("Error getting storage usage", e);
return new BaseResponse(request.getMsgId(),
MessageCode.FILE_UPLOAD_ERROR.getCode(),
"Failed to get storage usage: " + e.getMessage(),
null);
}
}
private BaseResponse handleProtectFile(BaseRequest request, FileEntityRequest fileRequest) {
String fileId = fileRequest.getFileId();
Optional<FileEntity> optionalFileEntity = fileEntityRepository.findById(fileId);
if (optionalFileEntity.isEmpty()) {
return new BaseResponse(request.getMsgId(),
MessageCode.FILE_NOT_FOUND.getCode(),
"File not found exception: " + fileRequest.getFileId(),
null);
}
FileEntity fileEntity = optionalFileEntity.get();
ProtectionStatus protectionStatus = fileEntity.getProtectionStatus();
Integer code = protectionStatus == ProtectionStatus.PROTECTED ? MessageCode.FILE_IS_PROTECTED.getCode():
MessageCode.FILE_IS_NOT_PROTECTED.getCode();
String message = protectionStatus == ProtectionStatus.PROTECTED ? MessageCode.FILE_IS_PROTECTED.getDescription():
MessageCode.FILE_IS_NOT_PROTECTED.getDescription();
return new BaseResponse(request.getMsgId(), code, message, fileEntityService.getById(fileId,
request.getVersion()));
}
@Transactional
public BaseResponse handleDeleteFiles(BaseRequest request, FileEntityRequest fileRequest) {
List<String> fileIds = fileRequest.getFileIds();
List<String> deletedIds = new ArrayList<>();
List<String> failedIds = new ArrayList<>();
for (String fileId : fileIds) {
try {
FileEntity fileEntity = fileEntityRepository.findById(fileId)
.orElseThrow(() -> new FileEntityNotFoundException(fileId));
deleteFileIfExists(fileEntity.getFilePath());
deleteFileIfExists(fileEntity.getProtectedFilePath());
deleteFileIfExists(fileEntity.getThumbnailPath());
deleteFileIfExists(fileEntity.getMediumPath());
deletedIds.add(fileId);
log.info("Physical files deleted for entity: {}", fileId);
} catch (Exception e) {
failedIds.add(fileId);
log.error("Failed to delete files for entity: {}", fileId, e);
}
}
if (!deletedIds.isEmpty()) {
fileMonitoringRepository.deleteAllByFileIdIn(deletedIds);
moderationLogRepository.deleteAllByFileIdIn(deletedIds);
imageHashRepository.deleteAllByFileIdIn(deletedIds);
fileAppealRepository.deleteAllByFileIdIn(deletedIds);
fileEntityRepository.deleteAllByIdIn(deletedIds);
log.info("Deleted {} entities from database", deletedIds.size());
}
return new BaseResponse(
request.getMsgId(),
MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(),
failedIds
);
}
private void deleteFileIfExists(String filePath) {
if (filePath != null && !filePath.isEmpty()) {
try {
Path path = Paths.get(filePath);
boolean deleted = Files.deleteIfExists(path);
if (deleted) {
log.debug("Deleted file: {}", filePath);
}
} catch (IOException e) {
log.warn("Failed to delete file: {}", filePath, e);
throw new RuntimeException("Failed to delete file: " + filePath, e);
}
}
}
private BaseResponse handleDeleteFile(BaseRequest request, FileEntityRequest fileRequest) {
try {
Long userId = authService.useUserAuthToken(fileRequest.getToken());
String fileId = fileRequest.getFileId();
FileEntityResponse fileInfo = fileEntityService.getById(fileId, request.getVersion());
DeleteFileResponse response;
if (!fileInfo.getUserId().equals(userId)) {
return new BaseResponse(request.getMsgId(),
MessageCode.ACCESS_DENIED.getCode(),
"Access denied",
null);
}
FileEntity fileEntity = fileEntityRepository.findById(fileId)
.orElseThrow(() -> new FileEntityNotFoundException(fileId));
int fullDelete = fileRequest.getFullDelete() == null ? 0 : fileRequest.getFullDelete();
if (fileEntity.getStatus().equals(FileStatus.DELETED) || fullDelete == 1) {
cloudStorageService.deleteFromStorageDisk(fileEntity);
response = DeleteFileResponse.builder()
.fileId(fileRequest.getFileId())
.message("File deleted from disk")
.build();
} else {
fileEntityService.softDeleteFileWithHash(fileEntity);
response = DeleteFileResponse.builder()
.fileId(fileRequest.getFileId())
.message("File marked as deleted")
.build();
}
return new BaseResponse(request.getMsgId(),
MessageCode.SUCCESS.getCode(),
"File marked as deleted",
response);
} catch (NotFoundAuthToken e) {
return new BaseResponse(request.getMsgId(),
MessageCode.INVALID_TOKEN.getCode(),
"Authentication required",
null);
} catch (Exception e) {
log.error("Error deleting file", e);
return new BaseResponse(request.getMsgId(),
MessageCode.FILE_UPLOAD_ERROR.getCode(),
"Failed to delete file: " + e.getMessage(),
null);
}
}
private BaseResponse handleModerateFile(BaseRequest request, FileEntityRequest fileRequest) {
try {
//TODO добавить проверку на админа
// Long moderatorId = authService.useAdminAuthToken(fileRequest.getToken());
ModerationActionRequest moderationRequest = ModerationActionRequest.builder()
.fileId(fileRequest.getFileId())
.newStatus(fileRequest.getFileStatus())
.comment(fileRequest.getComment())
.build();
//TODO set moderator ID
moderationService.moderateFile(moderationRequest, 0L);
return new BaseResponse(request.getMsgId(),
MessageCode.SUCCESS_MODERATION.getCode(),
MessageCode.SUCCESS_MODERATION.getDescription(),
FileEntityResponse.builder().id(fileRequest.getFileId()).build());
} catch (SecurityException e) {
return new BaseResponse(request.getMsgId(),
MessageCode.ACCESS_DENIED.getCode(),
MessageCode.ACCESS_DENIED.getDescription(),
FileEntityResponse.builder().id(fileRequest.getFileId()).build());
} catch (FileEntityNotFoundException e) {
return new BaseResponse(request.getMsgId(),
MessageCode.FILE_NOT_FOUND.getCode(),
MessageCode.FILE_NOT_FOUND.getDescription(),
FileEntityResponse.builder()
.id(fileRequest.getFileId()).build());
} catch (IllegalStateException e) {
return new BaseResponse(request.getMsgId(),
MessageCode.ILLEGAL_STATE.getCode(),
MessageCode.ILLEGAL_STATE.getDescription(),
FileEntityResponse.builder()
.status(fileRequest.getFileStatus()).build());
}
}
private BaseResponse handleSubmitAppeal(BaseRequest request, FileEntityRequest fileRequest) {
try {
Long userId = authService.useUserAuthToken(fileRequest.getToken());
AppealRequest appealRequest = AppealRequest.builder()
.fileId(fileRequest.getFileId())
.appealReason(fileRequest.getAppealReason())
.additionalInfo(fileRequest.getAdditionalInfo())
.build();
AppealResponse response = moderationService.submitAppeal(appealRequest, userId);
return new BaseResponse(request.getMsgId(),
MessageCode.SUCCESS.getCode(),
"Appeal submitted successfully",
response);
} catch (InvalidAppealException e) {
return new BaseResponse(request.getMsgId(),
MessageCode.INVALID_FIELD.getCode(),
e.getMessage(),
null);
} catch (Exception e) {
return new BaseResponse(request.getMsgId(),
MessageCode.INVALID_FIELD.getCode(),
"Failed to submit appeal: " + e.getMessage(),
null);
}
}
private BaseResponse handleGetUserAppeals(BaseRequest request, FileEntityRequest fileRequest) {
try {
Long userId = authService.useUserAuthToken(fileRequest.getToken());
int page = fileRequest.getPage() != null ? fileRequest.getPage() : 1;
int pageSize = fileRequest.getPageSize() != null ? fileRequest.getPageSize() : 20;
Page<AppealResponse> appeals = moderationService.getUserAppeals(userId, page - 1, pageSize);
Map<String, Object> response = Map.of(
"appeals", appeals.getContent(),
"totalCount", appeals.getTotalElements(),
"totalPages", appeals.getTotalPages(),
"currentPage", page,
"pageSize", pageSize);
return new BaseResponse(request.getMsgId(),
MessageCode.SUCCESS.getCode(),
MessageCode.SUCCESS.getDescription(),
response);
} catch (SecurityException e) {
return new BaseResponse(request.getMsgId(),
MessageCode.INVALID_TOKEN.getCode(),
"Authentication required",
null);
} catch (Exception e) {
log.error("Error getting user appeals", e);
return new BaseResponse(request.getMsgId(),
MessageCode.INVALID_FIELD.getCode(),
"Failed to get appeals: " + e.getMessage(),
null);
}
}
private BaseResponse handleGetFileModerationInfo(BaseRequest request, FileEntityRequest fileRequest) {
try {
// TODO
// authService.useAdminAuthToken(fileRequest.getToken());
String fileId = fileRequest.getFileId();
if (fileId == null) {
return new BaseResponse(request.getMsgId(),
MessageCode.INVALID_FIELD.getCode(),
"fileId is required",
null);
}
FileModerationInfo moderationInfo = moderationService.getFileModerationInfo(fileId);
FileEntity file = fileEntityRepository.findById(fileId)
.orElseThrow(() -> new FileEntityNotFoundException(fileId));
Map<String, Object> fileInfoMap = new HashMap<>();
fileInfoMap.put("id", file.getId());
fileInfoMap.put("fileName", file.getOriginalFileName());
fileInfoMap.put("storedFileName", file.getStoredFileName());
fileInfoMap.put("fileSize", file.getFileSize());
fileInfoMap.put("formattedSize", fileEntityService.formatFileSize(file.getFileSize()));
fileInfoMap.put("mimeType", file.getMimeType());
fileInfoMap.put("fileExtension", file.getFileExtension());
fileInfoMap.put("checksum", file.getChecksum());
fileInfoMap.put("status", file.getStatus() != null ? file.getStatus().name() : null);
fileInfoMap.put("createdAt", file.getCreatedAt());
fileInfoMap.put("updatedAt", file.getUpdatedAt());
Map<String, Object> response = new HashMap<>();
response.put("fileInfo", fileInfoMap);
response.put("moderationInfo", moderationInfo != null ? moderationInfo : new HashMap<>());
response.put("moderationHistory", getModerationHistory(fileId));
response.put("appeals", getFileAppeals(fileId));
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 (FileEntityNotFoundException e) {
return new BaseResponse(request.getMsgId(),
MessageCode.FILE_NOT_FOUND.getCode(),
e.getMessage(),
null);
} catch (Exception e) {
log.error("Error getting file moderation info", e);
return new BaseResponse(request.getMsgId(),
MessageCode.INVALID_FIELD.getCode(),
"Failed to get file info: " + e.getMessage(),
null);
}
}
private List<Map<String, Object>> getModerationHistory(String fileId) {
List<ModerationLog> logs = moderationLogRepository.findByFileIdOrderByCreatedAtDesc(fileId);
if (logs == null || logs.isEmpty()) {
return Collections.emptyList();
}
return logs.stream()
.map(log -> {
Map<String, Object> logMap = new HashMap<>();
logMap.put("id", log.getId());
logMap.put("moderatorId", log.getModeratorId());
logMap.put("oldStatus", log.getOldStatus() != null ? log.getOldStatus().name() : null);
logMap.put("newStatus", log.getNewStatus() != null ? log.getNewStatus().name() : null);
logMap.put("reason", log.getReason());
logMap.put("comment", log.getComment());
logMap.put("createdAt", log.getCreatedAt());
return logMap;
})
.collect(Collectors.toList());
}
private List<Map<String, Object>> getFileAppeals(String fileId) {
List<FileAppeal> appeals = fileAppealRepository.findByFileId(fileId);
if (appeals == null || appeals.isEmpty()) {
return Collections.emptyList();
}
return appeals.stream()
.map(appeal -> {
Map<String, Object> appealMap = new HashMap<>();
appealMap.put("id", appeal.getId());
appealMap.put("userId", appeal.getUserId());
appealMap.put("appealReason", appeal.getAppealReason());
appealMap.put("additionalInfo", appeal.getAdditionalInfo());
appealMap.put("status", appeal.getStatus() != null ? appeal.getStatus().name() : null);
appealMap.put("adminComment", appeal.getAdminComment());
appealMap.put("moderatorId", appeal.getModeratorId());
appealMap.put("createdAt", appeal.getCreatedAt());
appealMap.put("resolvedAt", appeal.getResolvedAt());
return appealMap;
})
.collect(Collectors.toList());
}
private String formatFileSize(long size) {
if (size < 1024) return size + " B";
int exp = (int) (Math.log(size) / Math.log(1024));
String pre = "KMGTPE".charAt(exp-1) + "";
return String.format("%.1f %sB", size / Math.pow(1024, exp), pre);
}
}