Merge branch 'dev' into NCBACK-35
# Conflicts: # README.md # src/main/java/ru/soune/nocopy/controller/ApiController.java # src/main/java/ru/soune/nocopy/handler/FileEntityHandler.java # src/main/java/ru/soune/nocopy/service/file/FileCleanupService.java # src/main/java/ru/soune/nocopy/service/file/FileEntityService.java # src/main/java/ru/soune/nocopy/service/file/impl/FileUploadServiceImpl.java # src/main/java/ru/soune/nocopy/service/file/impl/ProtectionFileProviderImpl.java
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
package ru.soune.nocopy.handler;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.stereotype.Component;
|
||||
import ru.soune.nocopy.dto.BaseRequest;
|
||||
import ru.soune.nocopy.dto.BaseResponse;
|
||||
import ru.soune.nocopy.dto.MessageCode;
|
||||
import ru.soune.nocopy.dto.complaint.ComplaintRequest;
|
||||
import ru.soune.nocopy.dto.complaint.ComplaintResponse;
|
||||
import ru.soune.nocopy.entity.complaint.ComplaintStatus;
|
||||
import ru.soune.nocopy.service.complaint.ComplaintEntityService;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class ComplaintEntityHandler implements RequestHandler {
|
||||
private final ComplaintEntityService complaintService;
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
@Override
|
||||
public BaseResponse handle(BaseRequest request) throws Exception {
|
||||
Integer msgId = request.getMsgId();
|
||||
ComplaintRequest complaintRequest = objectMapper.convertValue(request.getMessageBody(), ComplaintRequest.class);
|
||||
String action = complaintRequest.getAction();
|
||||
|
||||
try {
|
||||
switch (action.toLowerCase()) {
|
||||
case "create":
|
||||
return handleCreate(msgId, complaintRequest);
|
||||
case "get":
|
||||
return handleGet(msgId, complaintRequest);
|
||||
case "get_all":
|
||||
return handleGetAll(msgId, complaintRequest);
|
||||
case "get_by_violation":
|
||||
return handleGetByViolation(msgId, complaintRequest);
|
||||
case "update_status":
|
||||
return handleUpdateStatus(msgId, complaintRequest);
|
||||
case "update":
|
||||
return handleUpdate(msgId, complaintRequest);
|
||||
case "delete":
|
||||
return handleDelete(msgId, complaintRequest);
|
||||
default:
|
||||
return errorResponse(msgId, MessageCode.MSG_ID_NOT_FOUND.getCode(), "Unknown action: " + action);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Error handling complaint request", e);
|
||||
return errorResponse(msgId, MessageCode.INVALID_JSON_BODY.getCode(), e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private BaseResponse handleCreate(Integer msgId, ComplaintRequest req) {
|
||||
if (req.getViolationId() == null) return errorResponse(msgId, MessageCode.NOT_FOUND.getCode(),
|
||||
"violation_id is required");
|
||||
if (req.getComplaintText() == null) return errorResponse(msgId, MessageCode.NOT_FOUND.getCode(),
|
||||
"text is required");
|
||||
|
||||
ComplaintResponse response = complaintService.createComplaint(req);
|
||||
|
||||
return successResponse(msgId, "Complaint created successfully", response);
|
||||
}
|
||||
|
||||
private BaseResponse handleGet(Integer msgId, ComplaintRequest req) {
|
||||
if (req.getId() == null) return errorResponse(msgId, MessageCode.NOT_FOUND.getCode(), "id is required");
|
||||
|
||||
ComplaintResponse response = complaintService.getComplaintById(req.getId());
|
||||
return successResponse(msgId, "Complaint retrieved successfully", response);
|
||||
}
|
||||
|
||||
private BaseResponse handleGetAll(Integer msgId, ComplaintRequest req) {
|
||||
Pageable pageable = PageRequest.of(
|
||||
req.getPage() != null ? req.getPage() : 0,
|
||||
req.getSize() != null ? req.getSize() : 20,
|
||||
Sort.by(Sort.Direction.fromString(req.getSortDirection() != null ? req.getSortDirection() : "desc"),
|
||||
req.getSortBy() != null ? req.getSortBy() : "createdAt")
|
||||
);
|
||||
|
||||
var page = complaintService.getAllComplaints(pageable);
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("content", page.getContent());
|
||||
data.put("page", page.getNumber());
|
||||
data.put("size", page.getSize());
|
||||
data.put("totalElements", page.getTotalElements());
|
||||
data.put("totalPages", page.getTotalPages());
|
||||
|
||||
return successResponse(msgId, "Complaints retrieved successfully", data);
|
||||
}
|
||||
|
||||
private BaseResponse handleGetByViolation(Integer msgId, ComplaintRequest req) {
|
||||
if (req.getViolationId() == null) return errorResponse(msgId, MessageCode.NOT_FOUND.getCode(),
|
||||
"violation_id is required");
|
||||
|
||||
var complaints = complaintService.getComplaintsByViolationId(req.getViolationId());
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("content", complaints);
|
||||
data.put("totalElements", complaints.size());
|
||||
|
||||
return successResponse(msgId, "Complaints retrieved successfully", data);
|
||||
}
|
||||
|
||||
private BaseResponse handleUpdateStatus(Integer msgId, ComplaintRequest req) {
|
||||
if (req.getId() == null) return errorResponse(msgId, MessageCode.NOT_FOUND.getCode(), "id is required");
|
||||
if (req.getStatus() == null) return errorResponse(msgId, MessageCode.NOT_FOUND.getCode(), "status is required");
|
||||
|
||||
ComplaintStatus status = ComplaintStatus.valueOf(req.getStatus().toUpperCase());
|
||||
ComplaintResponse response = complaintService.updateComplaintStatus(req.getId(), status);
|
||||
return successResponse(msgId, "Status updated successfully", response);
|
||||
}
|
||||
|
||||
private BaseResponse handleUpdate(Integer msgId, ComplaintRequest req) {
|
||||
if (req.getId() == null) return errorResponse(msgId, MessageCode.NOT_FOUND.getCode(), "id is required");
|
||||
|
||||
ComplaintResponse response = complaintService.updateComplaint(req.getId(), req);
|
||||
|
||||
return successResponse(msgId, "Complaint updated successfully", response);
|
||||
}
|
||||
|
||||
private BaseResponse handleDelete(Integer msgId, ComplaintRequest req) {
|
||||
if (req.getId() == null) return errorResponse(msgId, MessageCode.NOT_FOUND.getCode(), "id is required");
|
||||
|
||||
ComplaintResponse response = complaintService.deleteComplaint(req.getId());
|
||||
return successResponse(msgId, "Complaint deleted successfully", response);
|
||||
}
|
||||
|
||||
private BaseResponse successResponse(Integer msgId, String message, Object data) {
|
||||
return new BaseResponse(msgId, MessageCode.SUCCESS.getCode(), message, data);
|
||||
}
|
||||
|
||||
private BaseResponse errorResponse(Integer msgId, Integer code, String message) {
|
||||
return new BaseResponse(msgId, code, message, new HashMap<>());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package ru.soune.nocopy.handler;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import ru.soune.nocopy.dto.BaseRequest;
|
||||
import ru.soune.nocopy.dto.BaseResponse;
|
||||
import ru.soune.nocopy.dto.MessageCode;
|
||||
import ru.soune.nocopy.dto.cost.CostRequest;
|
||||
import ru.soune.nocopy.dto.cost.CostResponse;
|
||||
import ru.soune.nocopy.entity.user.AuthToken;
|
||||
import ru.soune.nocopy.entity.user.User;
|
||||
import ru.soune.nocopy.repository.AuthTokenRepository;
|
||||
import ru.soune.nocopy.service.cost.CostService;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class CostHandler implements RequestHandler {
|
||||
|
||||
private final CostService costService;
|
||||
|
||||
private final AuthTokenRepository authTokenRepository;
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
private final Integer MAX_FILES_FOR_CHECK = 1000;
|
||||
|
||||
@Override
|
||||
public BaseResponse handle(BaseRequest request) throws Exception {
|
||||
CostRequest costRequest = objectMapper.convertValue(request.getMessageBody(), CostRequest.class);
|
||||
String action = costRequest.getAction();
|
||||
|
||||
return switch (action) {
|
||||
case "costFileProtect" -> handleFileProtectCost(costRequest, request);
|
||||
case "checkTokensForProtect" -> handleCheckTokensForFilesProtect(costRequest, request);
|
||||
default -> new BaseResponse(
|
||||
request.getMsgId(),
|
||||
MessageCode.INVALID_ACTION.getCode(),
|
||||
"Invalid action: " + action,
|
||||
null);
|
||||
};
|
||||
}
|
||||
|
||||
private BaseResponse handleFileProtectCost(CostRequest costRequest, BaseRequest request) {
|
||||
int cost = costService.protectFileCost(costRequest.getFileType());
|
||||
|
||||
if (cost == 0) {
|
||||
return new BaseResponse(request.getMsgId(), MessageCode.NOT_VALID_FILE_TYPE_OR_COUNT_FILE.getCode(),
|
||||
MessageCode.NOT_VALID_FILE_TYPE_OR_COUNT_FILE.getDescription(),
|
||||
CostResponse.builder()
|
||||
.cost(cost)
|
||||
.build());
|
||||
}
|
||||
|
||||
return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(),
|
||||
MessageCode.SUCCESS.getDescription(),
|
||||
CostResponse.builder()
|
||||
.cost(cost)
|
||||
.build());
|
||||
}
|
||||
|
||||
private BaseResponse handleCheckTokensForFilesProtect(CostRequest costRequest, BaseRequest request) {
|
||||
String authToken = costRequest.getAuthToken();
|
||||
Optional<AuthToken> token = authTokenRepository.findByToken(authToken);
|
||||
|
||||
if (token.isEmpty()) {
|
||||
return new BaseResponse(
|
||||
request.getMsgId(),
|
||||
MessageCode.AUTH_TOKEN_NOT_FOUND.getCode(),
|
||||
MessageCode.AUTH_TOKEN_NOT_FOUND.getDescription(),
|
||||
null);
|
||||
}
|
||||
|
||||
User user = token.get().getUser();
|
||||
Integer tokens = user.getActiveTariffInfo().getTokens();
|
||||
|
||||
int cost = costService.protectFileCost(costRequest.getFileType());
|
||||
int count = costRequest.getCountFilesForProtect();
|
||||
|
||||
if (cost == 0 || count <= 0 || count > MAX_FILES_FOR_CHECK) {
|
||||
return new BaseResponse(request.getMsgId(), MessageCode.NOT_VALID_FILE_TYPE_OR_COUNT_FILE.getCode(),
|
||||
MessageCode.NOT_VALID_FILE_TYPE_OR_COUNT_FILE.getDescription(),
|
||||
CostResponse.builder()
|
||||
.cost(cost)
|
||||
.countFile(count)
|
||||
.maxFilesForCheck(MAX_FILES_FOR_CHECK)
|
||||
.build());
|
||||
}
|
||||
|
||||
int totalCost = count * cost;
|
||||
boolean success = totalCost <= tokens;
|
||||
int needToken = success ? 0: tokens - totalCost;
|
||||
|
||||
CostResponse costResponse = CostResponse.builder()
|
||||
.cost(totalCost)
|
||||
.success(totalCost <= tokens)
|
||||
.needTokensCount(Math.abs(needToken))
|
||||
.build();
|
||||
|
||||
return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(),
|
||||
MessageCode.SUCCESS.getDescription(), costResponse);
|
||||
}
|
||||
}
|
||||
@@ -3,23 +3,28 @@ 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.stereotype.Component;
|
||||
import ru.soune.nocopy.dto.*;
|
||||
import ru.soune.nocopy.dto.file.*;
|
||||
import ru.soune.nocopy.entity.file.FileAppeal;
|
||||
import ru.soune.nocopy.entity.file.FileEntity;
|
||||
import ru.soune.nocopy.entity.file.FileStatus;
|
||||
import ru.soune.nocopy.entity.file.ProtectionStatus;
|
||||
import ru.soune.nocopy.exception.FileEntityNotFoundException;
|
||||
import ru.soune.nocopy.exception.NotFoundAuthToken;
|
||||
import ru.soune.nocopy.entity.file.moderation.ModerationLog;
|
||||
import ru.soune.nocopy.exception.*;
|
||||
import ru.soune.nocopy.repository.FileAppealRepository;
|
||||
import ru.soune.nocopy.repository.FileEntityRepository;
|
||||
import ru.soune.nocopy.service.file.cloud.CloudStorageService;
|
||||
import ru.soune.nocopy.repository.ModerationLogRepository;
|
||||
import ru.soune.nocopy.service.file.moderation.ModerationService;
|
||||
import ru.soune.nocopy.service.register.AuthService;
|
||||
import ru.soune.nocopy.service.file.FileEntityService;
|
||||
import ru.soune.nocopy.service.file.FileStatsService;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.time.LocalDate;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@@ -38,6 +43,12 @@ public class FileEntityHandler implements RequestHandler {
|
||||
|
||||
private final CloudStorageService cloudStorageService;
|
||||
|
||||
private final ModerationService moderationService;
|
||||
|
||||
private final FileAppealRepository fileAppealRepository;
|
||||
|
||||
private final ModerationLogRepository moderationLogRepository;
|
||||
|
||||
@Override
|
||||
public BaseResponse handle(BaseRequest request) {
|
||||
try {
|
||||
@@ -63,6 +74,18 @@ public class FileEntityHandler implements RequestHandler {
|
||||
return handleProtectFile(request, fileRequest);
|
||||
case "delete_file":
|
||||
return handleDeleteFile(request, fileRequest);
|
||||
case "change_file_status":
|
||||
return handleChangeStatus(request, fileRequest);
|
||||
case "moderate_file":
|
||||
return handleModerateFile(request, fileRequest);
|
||||
case "submit_appeal":
|
||||
return handleSubmitAppeal(request, fileRequest);
|
||||
case "review_appeal":
|
||||
return handleReviewAppeal(request, fileRequest);
|
||||
case "user_appeals":
|
||||
return handleGetUserAppeals(request, fileRequest);
|
||||
case "files_for_moderation":
|
||||
return handleGetFilesForModeration(request, fileRequest);
|
||||
default:
|
||||
ActionResponse response = ActionResponse.builder()
|
||||
.action(action)
|
||||
@@ -186,53 +209,306 @@ public class FileEntityHandler implements RequestHandler {
|
||||
}
|
||||
}
|
||||
|
||||
private BaseResponse handleChangeStatus(BaseRequest request, FileEntityRequest fileRequest) {
|
||||
FileStatus newStatus = fileRequest.getFileStatus();
|
||||
String fileId = fileRequest.getFileId();
|
||||
|
||||
try {
|
||||
fileEntityService.changeFileStatus(newStatus ,fileRequest.getFileId());
|
||||
} catch (FileEntityNotFoundException e) {
|
||||
return new BaseResponse(request.getMsgId(),
|
||||
MessageCode.FILE_NOT_FOUND.getCode(),
|
||||
MessageCode.FILE_NOT_FOUND.getDescription(),
|
||||
FileEntityResponse.builder().id(fileId).build());
|
||||
}
|
||||
|
||||
return new BaseResponse(request.getMsgId(),
|
||||
MessageCode.SUCCESS.getCode(),
|
||||
MessageCode.SUCCESS.getDescription(),
|
||||
FileEntityResponse.builder().status(newStatus).build());
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
if (fileRequest.getQuery() == null || fileRequest.getQuery().isBlank()) {
|
||||
return handleGetUserFiles(request, fileRequest);
|
||||
}
|
||||
String sortBy = fileRequest.getSortBy() != null ? fileRequest.getSortBy() : "fileName";
|
||||
SortOrder sortOrder = SortOrder.fromString(fileRequest.getSortOrder());
|
||||
|
||||
FileResponse allFiles = fileEntityService.getUserFiles(userId, 1, 1000, request.getVersion());
|
||||
|
||||
var filteredFiles = allFiles.getFiles().stream()
|
||||
.filter(f -> (f.getOriginalFileName() + f.getFileExtension()).toLowerCase()
|
||||
.contains(fileRequest.getQuery().toLowerCase()))
|
||||
.toList();
|
||||
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());
|
||||
List<FileEntityResponse> fileEntityResponses = filteredFiles.subList(start, Math.min(end, filteredFiles.size()));
|
||||
long sumSize = fileEntityResponses.stream()
|
||||
|
||||
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(fileEntityResponses)
|
||||
.files(paginatedFiles)
|
||||
.totalCount(filteredFiles.size())
|
||||
.totalSize(sumSize)
|
||||
.formattedTotalSize(fileEntityService.formatFileSize(sumSize))
|
||||
.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(),
|
||||
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(),
|
||||
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;
|
||||
|
||||
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());
|
||||
@@ -337,6 +613,326 @@ public class FileEntityHandler implements RequestHandler {
|
||||
}
|
||||
}
|
||||
|
||||
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 handleReviewAppeal(BaseRequest request, FileEntityRequest fileRequest) {
|
||||
try {
|
||||
// TODO
|
||||
// Long moderatorId = authService.useAdminAuthToken(fileRequest.getToken());
|
||||
|
||||
String appealId = fileRequest.getAppealId();
|
||||
Boolean approve = fileRequest.getApprove();
|
||||
String comment = fileRequest.getComment();
|
||||
|
||||
if (appealId == null || approve == null) {
|
||||
return new BaseResponse(request.getMsgId(),
|
||||
MessageCode.INVALID_FIELD.getCode(),
|
||||
"appealId and approve are required",
|
||||
null);
|
||||
}
|
||||
//TODO
|
||||
moderationService.reviewAppeal(appealId, approve, comment, 0L);
|
||||
|
||||
return new BaseResponse(request.getMsgId(),
|
||||
MessageCode.SUCCESS.getCode(),
|
||||
"Appeal reviewed successfully",
|
||||
Map.of(
|
||||
"appealId", appealId,
|
||||
"approved", approve,
|
||||
"comment", comment
|
||||
));
|
||||
|
||||
} catch (SecurityException e) {
|
||||
return new BaseResponse(request.getMsgId(),
|
||||
MessageCode.ACCESS_DENIED.getCode(),
|
||||
"Admin access required",
|
||||
null);
|
||||
} catch (IllegalStateException e) {
|
||||
return new BaseResponse(request.getMsgId(),
|
||||
MessageCode.INVALID_FIELD.getCode(),
|
||||
e.getMessage(),
|
||||
null);
|
||||
} catch (Exception e) {
|
||||
log.error("Error reviewing appeal", e);
|
||||
return new BaseResponse(request.getMsgId(),
|
||||
MessageCode.INVALID_FIELD.getCode(),
|
||||
"Failed to review 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 handleGetFilesForModeration(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;
|
||||
|
||||
Page<FileEntity> files = moderationService.getFilesForModeration(page - 1, pageSize);
|
||||
|
||||
List<Map<String, Object>> filesWithInfo = files.getContent().stream()
|
||||
.map(file -> {
|
||||
FileModerationInfo info = moderationService.getFileModerationInfo(file.getId());
|
||||
|
||||
Map<String, Object> fileMap = new HashMap<>();
|
||||
fileMap.put("fileId", file.getId());
|
||||
fileMap.put("fileName", file.getOriginalFileName());
|
||||
fileMap.put("userId", file.getUserId());
|
||||
fileMap.put("status", file.getStatus() != null ? file.getStatus().name() : null);
|
||||
|
||||
Map<String, Object> moderationInfoMap = new HashMap<>();
|
||||
moderationInfoMap.put("hasActiveAppeal", info != null && info.getHasActiveAppeal());
|
||||
|
||||
if (info != null && info.getActiveAppeal() != null) {
|
||||
Map<String, Object> appealInfoMap = new HashMap<>();
|
||||
appealInfoMap.put("appealId", info.getActiveAppeal().getAppealId());
|
||||
appealInfoMap.put("status", info.getActiveAppeal().getStatus());
|
||||
appealInfoMap.put("createdAt", info.getActiveAppeal().getCreatedAt());
|
||||
moderationInfoMap.put("appealInfo", appealInfoMap);
|
||||
} else {
|
||||
moderationInfoMap.put("appealInfo", null);
|
||||
}
|
||||
|
||||
fileMap.put("moderationInfo", moderationInfoMap);
|
||||
|
||||
return fileMap;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Map<String, Object> response = Map.of(
|
||||
"files", filesWithInfo,
|
||||
"totalCount", files.getTotalElements(),
|
||||
"totalPages", files.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.ACCESS_DENIED.getCode(),
|
||||
"Admin access required",
|
||||
null);
|
||||
} catch (Exception e) {
|
||||
log.error("Error getting files for moderation", e);
|
||||
return new BaseResponse(request.getMsgId(),
|
||||
MessageCode.INVALID_FIELD.getCode(),
|
||||
"Failed to get files: " + 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));
|
||||
|
||||
@@ -111,6 +111,7 @@ public class FileUploadHandler implements RequestHandler {
|
||||
fileRequest.getFileName(),
|
||||
fileRequest.getFileType(),
|
||||
fileRequest.getExtension(),
|
||||
fileRequest.getConvertTo(),
|
||||
fileRequest.getFileSize());
|
||||
|
||||
InitFileResponse fileResponse = InitFileResponse.builder()
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package ru.soune.nocopy.handler;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import ru.soune.nocopy.dto.BaseRequest;
|
||||
import ru.soune.nocopy.dto.BaseResponse;
|
||||
import ru.soune.nocopy.dto.search.GlobalSearchStatisticsRequest;
|
||||
import ru.soune.nocopy.dto.search.GlobalSearchStatisticsResponse;
|
||||
import ru.soune.nocopy.entity.user.AuthToken;
|
||||
import ru.soune.nocopy.repository.AuthTokenRepository;
|
||||
import ru.soune.nocopy.service.search.GlobalSearchStatisticsService;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class GlobalSearchHandler implements RequestHandler {
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
private final GlobalSearchStatisticsService statisticsService;
|
||||
|
||||
private final AuthTokenRepository authTokenRepository;
|
||||
|
||||
@Override
|
||||
public BaseResponse handle(BaseRequest request) throws Exception {
|
||||
GlobalSearchStatisticsRequest statRequest = objectMapper.convertValue(
|
||||
request.getMessageBody(), GlobalSearchStatisticsRequest.class);
|
||||
|
||||
if (statRequest.getToken() == null) {
|
||||
throw new IllegalArgumentException("User token is required");
|
||||
}
|
||||
|
||||
Optional<AuthToken> tokenOptional =
|
||||
authTokenRepository.findByToken(statRequest.getToken());
|
||||
|
||||
if (tokenOptional.isEmpty()) {
|
||||
throw new IllegalArgumentException("User token is required");
|
||||
}
|
||||
|
||||
Long userId = tokenOptional.orElseThrow().getUser().getId();
|
||||
|
||||
GlobalSearchStatisticsResponse statistics = statisticsService.getStatistics(
|
||||
userId, statRequest.getLimit(), statRequest.getDays());
|
||||
|
||||
return BaseResponse.builder()
|
||||
.msgId(request.getMsgId())
|
||||
.messageBody(statistics)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
package ru.soune.nocopy.handler;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import ru.soune.nocopy.configuration.search.SearchProperties;
|
||||
import ru.soune.nocopy.dto.BaseRequest;
|
||||
import ru.soune.nocopy.dto.BaseResponse;
|
||||
import ru.soune.nocopy.dto.MessageCode;
|
||||
@@ -15,7 +15,6 @@ import ru.soune.nocopy.exception.NotValidFieldException;
|
||||
import ru.soune.nocopy.repository.FileEntityRepository;
|
||||
import ru.soune.nocopy.service.file.CheckCounterService;
|
||||
import ru.soune.nocopy.service.search.SearchImageService;
|
||||
import ru.soune.nocopy.service.search.GoogleVisionSearchService;
|
||||
import ru.soune.nocopy.service.tariff.TariffConstants;
|
||||
import ru.soune.nocopy.service.tariff.TariffInfoService;
|
||||
|
||||
@@ -32,14 +31,14 @@ public class ImageFoundRequestHandler implements RequestHandler {
|
||||
|
||||
private final SearchImageService searchImageService;
|
||||
|
||||
private final GoogleVisionSearchService googleVisionSearchService;
|
||||
|
||||
private final CheckCounterService checkCounterService;
|
||||
|
||||
private final FileEntityRepository fileEntityRepository;
|
||||
|
||||
private final TariffInfoService tariffInfoService;
|
||||
|
||||
private final SearchProperties searchProperties;
|
||||
|
||||
@Override
|
||||
public BaseResponse handle(BaseRequest request) throws Exception {
|
||||
ImageSearchRequest imageSearchRequest = objectMapper.convertValue(request.getMessageBody(),
|
||||
@@ -51,48 +50,76 @@ public class ImageFoundRequestHandler implements RequestHandler {
|
||||
.orElseThrow(() -> {
|
||||
throw new NotValidFieldException("File not found", new BaseResponse(20007,
|
||||
MessageCode.FILE_NOT_FOUND.getCode(), MessageCode.FILE_NOT_FOUND.getDescription(),
|
||||
Map.of("fileId",fileId)));
|
||||
});
|
||||
Map.of("fileId", fileId)));});
|
||||
|
||||
// YandexSearchResponse response = yandexSearchService.searchByFileEntity(fileEntity);
|
||||
List<YandexSearchResponse.ImageResult> allYandexImages = new ArrayList<>();
|
||||
List<YandexSearchResponse.ImageResult> allGoogleImages = new ArrayList<>();
|
||||
boolean hasTimeout = false;
|
||||
|
||||
//TODO uncommited when add billing
|
||||
// GoogleVisionSearchResponse googleVisionSearchResponse = googleVisionSearchService.searchByFileEntity(fileId);
|
||||
boolean useGoogle = searchProperties.getEngines().getOrDefault("google",
|
||||
new SearchProperties.EngineConfig()).isEnabled();
|
||||
boolean useYandex = searchProperties.getEngines().getOrDefault("yandex",
|
||||
new SearchProperties.EngineConfig()).isEnabled();
|
||||
|
||||
log.info("Search settings: useGoogle={}, useYandex={}", useGoogle, useYandex);
|
||||
|
||||
if (useGoogle) {
|
||||
try {
|
||||
String searchResponseGoogle = searchImageService.searchReverseByPublicUrl(fileEntity, "google_lens",
|
||||
"exact_matches");
|
||||
log.info("searchResponseGoogle OK");
|
||||
allGoogleImages = searchImageService.getAllImagesWithoutPagination(
|
||||
searchResponseGoogle, "exact_matches");
|
||||
} catch (TimeoutException e) {
|
||||
log.warn("Google search timeout for file {}", fileId);
|
||||
hasTimeout = true;
|
||||
} catch (IOException e) {
|
||||
log.error("Google search failed for file {}", fileId, e);
|
||||
}
|
||||
} else {
|
||||
log.info("Google search is disabled by settings");
|
||||
}
|
||||
|
||||
if (useYandex) {
|
||||
try {
|
||||
String searchResponseYandex = searchImageService.searchReverseByPublicUrl(fileEntity, "yandex_reverse_image",
|
||||
"visual_matches");
|
||||
log.info("searchResponseYandex OK");
|
||||
allYandexImages = searchImageService.getAllImagesWithoutPagination(
|
||||
searchResponseYandex, "visual_matches");
|
||||
} catch (TimeoutException e) {
|
||||
log.warn("Yandex search timeout for file {}", fileId);
|
||||
hasTimeout = true;
|
||||
} catch (IOException e) {
|
||||
log.error("Yandex search failed for file {}", fileId, e);
|
||||
}
|
||||
} else {
|
||||
log.info("Yandex search is disabled by settings");
|
||||
}
|
||||
|
||||
if (allYandexImages.isEmpty() && allGoogleImages.isEmpty()) {
|
||||
log.warn("No results from any search engine");
|
||||
String errorMessage = useGoogle || useYandex ? "No results found" : "All search engines are disabled";
|
||||
|
||||
String searchResponseYandex;
|
||||
String searchResponseGoogle;
|
||||
try {
|
||||
searchResponseYandex = searchImageService.searchReverseByPublicUrl(fileEntity, "yandex_reverse_image",
|
||||
"visual_matches");
|
||||
searchResponseGoogle = searchImageService.searchReverseByPublicUrl(fileEntity, "google_lens",
|
||||
"exact_matches");
|
||||
} catch (TimeoutException e) {
|
||||
log.warn("Search timeout for file {}, returning empty results", fileId);
|
||||
return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(),
|
||||
"Search completed (partial)", Map.of(
|
||||
"results", List.of(),
|
||||
"total", 0,
|
||||
"searchStatus", "timeout"
|
||||
));
|
||||
} catch (IOException e) {
|
||||
log.error("Search failed for file {}", fileId, e);
|
||||
return new BaseResponse(request.getMsgId(), 20007,
|
||||
"Search service temporarily unavailable",
|
||||
Map.of("fileId", fileId));
|
||||
errorMessage, new YandexSearchResponse());
|
||||
}
|
||||
|
||||
List<YandexSearchResponse.ImageResult> allUniqueImages;
|
||||
if (useGoogle && useYandex) {
|
||||
allUniqueImages = searchImageService.removeDuplicateUrls(allYandexImages, allGoogleImages);
|
||||
log.info("Merged results from both engines: {} unique images", allUniqueImages.size());
|
||||
} else if (useGoogle) {
|
||||
allUniqueImages = allGoogleImages;
|
||||
log.info("Results only from Google: {} images", allUniqueImages.size());
|
||||
} else {
|
||||
allUniqueImages = allYandexImages;
|
||||
log.info("Results only from Yandex: {} images", allUniqueImages.size());
|
||||
}
|
||||
|
||||
tariffInfoService.writeOffTokens(fileEntity.getUserId(), TariffConstants.TOKEN_VALUE_FOR_SEARCH);
|
||||
|
||||
checkCounterService.incrementCheckCount(fileEntity.getUserId(), fileEntity.getMimeType());
|
||||
|
||||
List<YandexSearchResponse.ImageResult> allYandexImages = searchImageService.getAllImagesWithoutPagination(
|
||||
searchResponseYandex, "visual_matches");
|
||||
List<YandexSearchResponse.ImageResult> allGoogleImages = searchImageService.getAllImagesWithoutPagination(
|
||||
searchResponseGoogle, "exact_matches");
|
||||
|
||||
List<YandexSearchResponse.ImageResult> allUniqueImages = searchImageService.removeDuplicateUrls(allYandexImages,
|
||||
allGoogleImages);
|
||||
|
||||
int page = imageSearchRequest.getPage() != null ? imageSearchRequest.getPage() : 1;
|
||||
int pageSize = 5;
|
||||
|
||||
@@ -106,7 +133,9 @@ public class ImageFoundRequestHandler implements RequestHandler {
|
||||
finalResponse.setTotalResults(allUniqueImages.size());
|
||||
finalResponse.setTotalPages((int) Math.ceil((double) allUniqueImages.size() / (pageSize * 2)));
|
||||
|
||||
String message = hasTimeout ? "Search completed (partial)" : MessageCode.SUCCESS.getDescription();
|
||||
|
||||
return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(),
|
||||
MessageCode.SUCCESS.getDescription(), finalResponse);
|
||||
message, finalResponse);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
package ru.soune.nocopy.handler;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import ru.soune.nocopy.dto.BaseRequest;
|
||||
import ru.soune.nocopy.dto.BaseResponse;
|
||||
import ru.soune.nocopy.dto.MessageCode;
|
||||
import ru.soune.nocopy.dto.monitoring.MonitoringStatusResponse;
|
||||
import ru.soune.nocopy.dto.monitoring.SetMonitoringRequest;
|
||||
import ru.soune.nocopy.entity.monitoring.MonitoringType;
|
||||
import ru.soune.nocopy.entity.user.AuthToken;
|
||||
import ru.soune.nocopy.entity.user.User;
|
||||
import ru.soune.nocopy.exception.UserNotHavePermission;
|
||||
import ru.soune.nocopy.service.monitoring.FileMonitoringService;
|
||||
import ru.soune.nocopy.service.register.AuthService;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class MonitoringHandler implements RequestHandler {
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
private final FileMonitoringService monitoringService;
|
||||
|
||||
private final AuthService authService;
|
||||
|
||||
@Override
|
||||
public BaseResponse handle(BaseRequest request) throws Exception {
|
||||
SetMonitoringRequest setRequest = objectMapper.convertValue(
|
||||
request.getMessageBody(), SetMonitoringRequest.class);
|
||||
|
||||
String authToken = setRequest.getAuthToken();
|
||||
AuthToken userAuthToken = authService.getAuthToken(authToken);
|
||||
|
||||
if (authToken == null || userAuthToken == null) {
|
||||
return new BaseResponse(30007, MessageCode.AUTH_TOKEN_NOT_FOUND.getCode(),
|
||||
MessageCode.AUTH_TOKEN_NOT_FOUND.getDescription(),
|
||||
Map.of("token", authToken));
|
||||
}
|
||||
|
||||
User user = userAuthToken.getUser();
|
||||
Long userId = user.getId();
|
||||
String typeStr = setRequest.getMonitoringType();
|
||||
MonitoringType monitoringType;
|
||||
|
||||
try {
|
||||
monitoringType = MonitoringType.valueOf(typeStr);
|
||||
} catch (IllegalArgumentException e) {
|
||||
return new BaseResponse(request.getMsgId(),
|
||||
MessageCode.MONITORING_TYPE_NOT_FOUND.getCode(),
|
||||
MessageCode.MONITORING_TYPE_NOT_FOUND.getDescription(),
|
||||
Map.of("monitoring", Arrays.asList(MonitoringType.values())));
|
||||
}
|
||||
|
||||
try {
|
||||
monitoringService.setMonitoring(userId, setRequest.getFileId(), monitoringType);
|
||||
} catch (UserNotHavePermission e) {
|
||||
return new BaseResponse(request.getMsgId(),
|
||||
MessageCode.USER_NOT_HAD_PERMISSION.getCode(),
|
||||
MessageCode.USER_NOT_HAD_PERMISSION.getDescription(), Map.of("token", authToken));
|
||||
} catch (FileNotFoundException e) {
|
||||
return new BaseResponse(request.getMsgId(),
|
||||
MessageCode.FILE_NOT_FOUND.getCode(),
|
||||
MessageCode.FILE_NOT_FOUND.getDescription(), Map.of("fileId", setRequest.getFileId()));
|
||||
}
|
||||
|
||||
MonitoringStatusResponse status = monitoringService.getMonitoringStatus(setRequest.getFileId(), userId);
|
||||
|
||||
return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(),
|
||||
"Monitoring settings updated", status);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package ru.soune.nocopy.handler;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
import ru.soune.nocopy.dto.BaseRequest;
|
||||
import ru.soune.nocopy.dto.BaseResponse;
|
||||
import ru.soune.nocopy.dto.MessageCode;
|
||||
import ru.soune.nocopy.dto.payment.PaymentRequest;
|
||||
import ru.soune.nocopy.dto.payment.PaymentResponse;
|
||||
import ru.soune.nocopy.entity.payment.Payment;
|
||||
import ru.soune.nocopy.exception.PaymentNotFoundException;
|
||||
import ru.soune.nocopy.service.payment.PaymentService;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class PaymentHandler implements RequestHandler{
|
||||
|
||||
private final PaymentService paymentService;
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
@Override
|
||||
public BaseResponse handle(BaseRequest request) throws Exception {
|
||||
PaymentRequest paymentRequest = objectMapper.convertValue(request.getMessageBody(), PaymentRequest.class);
|
||||
String action = paymentRequest.getAction();
|
||||
|
||||
switch (action) {
|
||||
case "user_payments":
|
||||
List<Payment> payments = paymentService.userPayments(paymentRequest.getEmail());
|
||||
|
||||
return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(),
|
||||
MessageCode.SUCCESS.getDescription(), new PaymentResponse(payments));
|
||||
case "payment_info":
|
||||
try {
|
||||
Payment payment = paymentService.paymentInfo(paymentRequest.getPaymentUuid());
|
||||
return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(),
|
||||
MessageCode.SUCCESS.getDescription(), new PaymentResponse(List.of(payment)));
|
||||
} catch (PaymentNotFoundException e) {
|
||||
return new BaseResponse(request.getMsgId(), MessageCode.PAYMENT_NOT_FOUND.getCode(),
|
||||
MessageCode.PAYMENT_NOT_FOUND.getDescription(), Map.of("paymentUuid",
|
||||
paymentRequest.getPaymentUuid()));
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,8 @@ import ru.soune.nocopy.dto.register.RegAnswer;
|
||||
import ru.soune.nocopy.dto.register.RegRequest;
|
||||
import ru.soune.nocopy.entity.referral.Referral;
|
||||
import ru.soune.nocopy.entity.user.AuthToken;
|
||||
import ru.soune.nocopy.entity.user.EmailVerificationToken;
|
||||
import ru.soune.nocopy.exception.CompanyAlreadyExist;
|
||||
import ru.soune.nocopy.exception.NotValidFieldException;
|
||||
import ru.soune.nocopy.exception.ValidationException;
|
||||
import ru.soune.nocopy.handler.validator.RegRequestValidator;
|
||||
@@ -19,6 +21,7 @@ import ru.soune.nocopy.repository.ReferralJpaRepository;
|
||||
import ru.soune.nocopy.repository.UserRepository;
|
||||
import ru.soune.nocopy.service.register.AuthService;
|
||||
import ru.soune.nocopy.service.mail.EmailService;
|
||||
import ru.soune.nocopy.service.user.AdditionalInfoService;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
@@ -41,71 +44,97 @@ public class RegRequestHandler implements RequestHandler {
|
||||
|
||||
private final ReferralJpaRepository referralJpaRepository;
|
||||
|
||||
private final AdditionalInfoService additionalInfoService;
|
||||
|
||||
@Override
|
||||
public BaseResponse handle(BaseRequest request) throws ValidationException {
|
||||
RegRequest regRequest = objectMapper.convertValue(request.getMessageBody(), RegRequest.class);
|
||||
try {
|
||||
if (userRepository.existsByEmail(regRequest.getEmail()) || userRepository.existsByPhone(regRequest.getPhone())) {
|
||||
RegAnswer regAnswer = new RegAnswer();
|
||||
regAnswer.setFieldErrors(Arrays.asList(Map.of("email", regRequest.getEmail())));
|
||||
regAnswer.setFieldErrors(Arrays.asList(Map.of("phone", regRequest.getPhone())));
|
||||
|
||||
if (userRepository.existsByEmail(regRequest.getEmail()) || userRepository.existsByPhone(regRequest.getPhone())) {
|
||||
RegAnswer regAnswer = new RegAnswer();
|
||||
regAnswer.setFieldErrors(Arrays.asList(Map.of("email", regRequest.getEmail())));
|
||||
regAnswer.setFieldErrors(Arrays.asList(Map.of("phone", regRequest.getPhone())));
|
||||
|
||||
throw new NotValidFieldException("User already exists with email:" + regRequest.getEmail() + " or phone: " +
|
||||
regRequest.getPhone(), new BaseResponse(request.getMsgId(),
|
||||
MessageCode.REG_EMAIL_OR_PHONE_EXISTS.getCode(),
|
||||
MessageCode.REG_EMAIL_OR_PHONE_EXISTS.getDescription(), regAnswer));
|
||||
}
|
||||
|
||||
String referralLink = regRequest.getReferralLink();
|
||||
|
||||
if (referralLink != null) {
|
||||
Referral referral = referralJpaRepository.findByReferralLink(referralLink);
|
||||
if (referral == null) {
|
||||
throw new NotValidFieldException("Referral link is not found:" + referralLink +
|
||||
referralLink, new BaseResponse(request.getMsgId(),
|
||||
MessageCode.REFERRAL_LINK_IS_NOT_EXIST.getCode(),
|
||||
MessageCode.REFERRAL_LINK_IS_NOT_EXIST.getDescription(), Map.of(
|
||||
"referralLink", referralLink)));
|
||||
throw new NotValidFieldException("User already exists with email:" + regRequest.getEmail() + " or phone: " +
|
||||
regRequest.getPhone(), new BaseResponse(request.getMsgId(),
|
||||
MessageCode.REG_EMAIL_OR_PHONE_EXISTS.getCode(),
|
||||
MessageCode.REG_EMAIL_OR_PHONE_EXISTS.getDescription(), regAnswer));
|
||||
}
|
||||
|
||||
String referralLink = regRequest.getReferralLink();
|
||||
String mailVerified = regRequest.getMailVerified();
|
||||
|
||||
if (referralLink != null) {
|
||||
Referral referral = referralJpaRepository.findByReferralLink(referralLink);
|
||||
if (referral == null) {
|
||||
throw new NotValidFieldException("Referral link is not found:" + referralLink +
|
||||
referralLink, new BaseResponse(request.getMsgId(),
|
||||
MessageCode.REFERRAL_LINK_IS_NOT_EXIST.getCode(),
|
||||
MessageCode.REFERRAL_LINK_IS_NOT_EXIST.getDescription(), Map.of(
|
||||
"referralLink", referralLink)));
|
||||
}
|
||||
|
||||
if (mailVerified == null) {
|
||||
throw new NotValidFieldException("Mailverified is null:" + referralLink +
|
||||
referralLink, new BaseResponse(request.getMsgId(),
|
||||
MessageCode.MAIL_VERIFIED_NULL.getCode(),
|
||||
MessageCode.MAIL_VERIFIED_NULL.getDescription(), Map.of(
|
||||
"mailVerified", mailVerified)));
|
||||
}
|
||||
}
|
||||
|
||||
BindingResult bindingResult = new BeanPropertyBindingResult(regRequest, "regRequest");
|
||||
|
||||
regRequestValidator.validate(regRequest, bindingResult);
|
||||
|
||||
if (bindingResult.hasErrors()) {
|
||||
throw new ValidationException(bindingResult, request.getMsgId());
|
||||
}
|
||||
|
||||
boolean verified = mailVerified.equals("true");
|
||||
|
||||
AuthToken authToken = authService.register(regRequest, verified);
|
||||
EmailVerificationToken emailToken = emailService.createEmailVerificationToken(authToken);
|
||||
RegAnswer regAnswer = new RegAnswer();
|
||||
|
||||
if (verified) {
|
||||
try {
|
||||
emailService.sendVerificationEmail(authToken.getUser(), emailToken.getToken());
|
||||
} catch (Exception e) {
|
||||
return new BaseResponse(request.getMsgId(), MessageCode.SEND_EMAIL_EXCEPTION.getCode(),
|
||||
MessageCode.SEND_EMAIL_EXCEPTION.getDescription(), Map.of(
|
||||
"message", "not send",
|
||||
"email", regRequest.getEmail()
|
||||
));
|
||||
}
|
||||
|
||||
regAnswer.setVerified(false);
|
||||
regAnswer.setActive(false);
|
||||
} else {
|
||||
regAnswer.setUserId(authToken.getUser().getId());
|
||||
|
||||
regAnswer.setVerified(true);
|
||||
regAnswer.setActive(true);
|
||||
}
|
||||
|
||||
String token = authToken.getToken();
|
||||
authService.useUserAuthToken(token);
|
||||
|
||||
regAnswer.setToken(token);
|
||||
regAnswer.setUserId(authToken.getUser().getId());
|
||||
|
||||
if (regRequest.getAccountType().equals("b2c")) {
|
||||
referralService.onRegister(authToken.getUser().getId(), regRequest.getReferralLink());
|
||||
}
|
||||
|
||||
additionalInfoService.additionalInfo(regRequest.getIp(), regRequest.getUserAgent(), authToken.getUser());
|
||||
|
||||
return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(),
|
||||
MessageCode.SUCCESS.getDescription(), regAnswer);
|
||||
} catch (CompanyAlreadyExist e) {
|
||||
return new BaseResponse(request.getMsgId(), MessageCode.COMPANY_ALREADY_EXISTS.getCode(),
|
||||
MessageCode.COMPANY_ALREADY_EXISTS.getDescription(), Map.of(
|
||||
"inn", regRequest.getInn()));
|
||||
}
|
||||
|
||||
BindingResult bindingResult = new BeanPropertyBindingResult(regRequest, "regRequest");
|
||||
|
||||
regRequestValidator.validate(regRequest, bindingResult);
|
||||
|
||||
if (bindingResult.hasErrors()) {
|
||||
throw new ValidationException(bindingResult, request.getMsgId());
|
||||
}
|
||||
|
||||
AuthToken authToken = authService.register(regRequest);
|
||||
// EmailVerificationToken emailToken = emailService.createEmailVerificationToken(authToken);
|
||||
|
||||
// try {
|
||||
// emailService.sendVerificationEmail(authToken.getUser(), emailToken.getToken());
|
||||
// } catch (Exception e) {
|
||||
// return new BaseResponse(request.getMsgId(), MessageCode.SEND_EMAIL_EXCEPTION.getCode(),
|
||||
// MessageCode.SEND_EMAIL_EXCEPTION.getDescription(), Map.of(
|
||||
// "message", "not send",
|
||||
// "email", regRequest.getEmail()
|
||||
// ));
|
||||
// }
|
||||
|
||||
|
||||
String token = authToken.getToken();
|
||||
authService.useUserAuthToken(token);
|
||||
|
||||
RegAnswer regAnswer = new RegAnswer();
|
||||
|
||||
regAnswer.setUserId(authToken.getUser().getId());
|
||||
regAnswer.setToken(token);
|
||||
regAnswer.setVerified(true);
|
||||
regAnswer.setActive(true);
|
||||
|
||||
if (regRequest.getAccountType().equals("b2c")) {
|
||||
referralService.onRegister(authToken.getUser().getId(), regRequest.getReferralLink());
|
||||
}
|
||||
|
||||
return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(),
|
||||
MessageCode.SUCCESS.getDescription(), regAnswer);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
package ru.soune.nocopy.handler;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Component;
|
||||
import ru.soune.nocopy.dto.BaseRequest;
|
||||
import ru.soune.nocopy.dto.BaseResponse;
|
||||
import ru.soune.nocopy.dto.MessageCode;
|
||||
import ru.soune.nocopy.dto.file.ActionResponse;
|
||||
import ru.soune.nocopy.dto.register.ResetPasswordRequest;
|
||||
import ru.soune.nocopy.dto.register.ResetPasswordResponse;
|
||||
import ru.soune.nocopy.entity.user.AuthToken;
|
||||
import ru.soune.nocopy.entity.user.EmailVerificationToken;
|
||||
import ru.soune.nocopy.entity.user.User;
|
||||
import ru.soune.nocopy.exception.NotValidFieldException;
|
||||
import ru.soune.nocopy.exception.UserNotFoundException;
|
||||
import ru.soune.nocopy.repository.AuthTokenRepository;
|
||||
import ru.soune.nocopy.repository.EmailVerificationTokenRepository;
|
||||
import ru.soune.nocopy.repository.UserRepository;
|
||||
import ru.soune.nocopy.service.mail.EmailService;
|
||||
import ru.soune.nocopy.service.register.AuthService;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class ResetPasswordHandler implements RequestHandler{
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
private final EmailService emailService;
|
||||
|
||||
private final AuthService authService;
|
||||
|
||||
private final UserRepository userRepository;
|
||||
|
||||
private final EmailVerificationTokenRepository emailVerificationTokenRepository;
|
||||
|
||||
private final AuthTokenRepository authTokenRepository;
|
||||
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
|
||||
@Override
|
||||
public BaseResponse handle(BaseRequest request) throws Exception {
|
||||
ResetPasswordRequest resetPasswordRequest = objectMapper.convertValue(request.getMessageBody(),
|
||||
ResetPasswordRequest.class);
|
||||
String action = resetPasswordRequest.getAction();
|
||||
User user = userRepository.findByEmail(resetPasswordRequest.getEmail());
|
||||
AuthToken authToken;
|
||||
|
||||
if (user == null) {
|
||||
throw new UserNotFoundException("User not found with email: " + resetPasswordRequest.getEmail());
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
case "resetPassword":
|
||||
authToken = authService.generateAuthToken(user);
|
||||
|
||||
EmailVerificationToken emailToken = emailService.createEmailVerificationToken(authToken);
|
||||
|
||||
emailService.sendResetPasswordEmail(authToken.getUser(), emailToken.getToken());
|
||||
|
||||
return successResponse(request, authToken, user, MessageCode.SUCCESS.getDescription());
|
||||
case "confirmVerification":
|
||||
String verifyToken = resetPasswordRequest.getVerifyToken();
|
||||
|
||||
EmailVerificationToken verificationToken =
|
||||
emailVerificationTokenRepository.findByUserIdAndToken(user.getId(), verifyToken);
|
||||
|
||||
if (verificationToken == null) {
|
||||
return new BaseResponse(request.getMsgId(), MessageCode.INVALID_TOKEN.getCode(),
|
||||
MessageCode.INVALID_TOKEN.getDescription(), Map.of("verifyToken", verifyToken));
|
||||
}
|
||||
|
||||
List<AuthToken> authTokens = authTokenRepository.findByUserId(user.getId());
|
||||
|
||||
authToken = authTokens.isEmpty() ? authService.generateAuthToken(user): authTokens.getFirst();
|
||||
|
||||
user.setPassword(passwordEncoder.encode(resetPasswordRequest.getPassword()));
|
||||
user.setActive(true);
|
||||
|
||||
emailVerificationTokenRepository.delete(verificationToken);
|
||||
|
||||
User saveUser = userRepository.save(user);
|
||||
|
||||
return successResponse(request, authToken, saveUser, MessageCode.SUCCESS.getDescription());
|
||||
default:
|
||||
ActionResponse response = ActionResponse.builder()
|
||||
.action(action)
|
||||
.availableActions(Arrays.asList("confirmVerification", "resetPassword"))
|
||||
.build();
|
||||
|
||||
return new BaseResponse(request.getMsgId(), MessageCode.INVALID_ACTION.getCode(),
|
||||
"Invalid action: " + action, response);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private BaseResponse successResponse(BaseRequest request, AuthToken authToken, User user, String message) {
|
||||
ResetPasswordResponse resetPasswordResponse = new ResetPasswordResponse();
|
||||
resetPasswordResponse.setAuthToken(authToken.getToken());
|
||||
resetPasswordResponse.setUserId(user.getId());
|
||||
|
||||
return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(), message, resetPasswordResponse);
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import ru.soune.nocopy.dto.MessageCode;
|
||||
import ru.soune.nocopy.dto.tarriff.TariffDTO;
|
||||
import ru.soune.nocopy.dto.tarriff.TariffRequest;
|
||||
import ru.soune.nocopy.dto.tarriff.TariffResponse;
|
||||
import ru.soune.nocopy.entity.tarif.TariffTimeTerm;
|
||||
import ru.soune.nocopy.entity.user.AuthToken;
|
||||
import ru.soune.nocopy.entity.user.User;
|
||||
import ru.soune.nocopy.repository.AuthTokenRepository;
|
||||
@@ -44,6 +45,8 @@ public class TariffHandler implements RequestHandler {
|
||||
return handleUpdateTariff(request, tariffRequest);
|
||||
case "get" :
|
||||
return handleGetTariffs(request, tariffRequest);
|
||||
case "tariffs_by_type" :
|
||||
return handleGetTariffsByType(request, tariffRequest);
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
@@ -62,7 +65,7 @@ public class TariffHandler implements RequestHandler {
|
||||
private BaseResponse handleAddTariff(BaseRequest request, TariffRequest tariffRequest) {
|
||||
tariffService.addTariff(tariffRequest.getName(), tariffRequest.getPrice(), tariffRequest.getType(),
|
||||
tariffRequest.getTokens(), tariffRequest.getDiskSize(), tariffRequest.getMaxUsers(),
|
||||
tariffRequest.getMaxFilesCount());
|
||||
tariffRequest.getMaxFilesCount(), tariffRequest.getTariffTerm());
|
||||
|
||||
TariffResponse tariffResponse = TariffResponse.builder()
|
||||
.tariffName(tariffRequest.getName())
|
||||
@@ -120,10 +123,19 @@ public class TariffHandler implements RequestHandler {
|
||||
private BaseResponse handleGetTariffs(BaseRequest request, TariffRequest tariffRequest) {
|
||||
AuthToken authToken = authTokenRepository.findByToken(tariffRequest.getUserToken()).orElseThrow();
|
||||
User user = authToken.getUser();
|
||||
List<TariffDTO> allTariffs = tariffService.getTariffByAccountType(user);
|
||||
List<TariffDTO> allTariffs = tariffService.getTariffByAccountTypeAndTariffTerm(user,
|
||||
TariffTimeTerm.valueOf(tariffRequest.getTariffTerm().toUpperCase()));
|
||||
|
||||
return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(),
|
||||
MessageCode.SUCCESS.getDescription(),
|
||||
Map.of("tariffs", allTariffs));
|
||||
}
|
||||
|
||||
private BaseResponse handleGetTariffsByType(BaseRequest request, TariffRequest tariffRequest) {
|
||||
List<TariffDTO> allTariffs = tariffService.getTariffByType(tariffRequest.getType());
|
||||
|
||||
return new BaseResponse(request.getMsgId(), MessageCode.SUCCESS.getCode(),
|
||||
MessageCode.SUCCESS.getDescription(),
|
||||
Map.of("token_tariffs", allTariffs));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import ru.soune.nocopy.dto.tarriff.TariffInfoRequest;
|
||||
import ru.soune.nocopy.dto.tarriff.TariffInfoResponse;
|
||||
import ru.soune.nocopy.entity.tarif.Tariff;
|
||||
import ru.soune.nocopy.entity.tarif.TariffStatus;
|
||||
import ru.soune.nocopy.entity.tarif.TariffTimeTerm;
|
||||
import ru.soune.nocopy.entity.tarif.TariffType;
|
||||
import ru.soune.nocopy.repository.TariffRepository;
|
||||
import ru.soune.nocopy.service.tariff.TariffInfoService;
|
||||
@@ -75,13 +76,14 @@ public class TariffInfoHandler implements RequestHandler {
|
||||
try {
|
||||
Long tariffId = tariffInfoRequest.getTariffId();
|
||||
Tariff tariff= tariffRepository.findById(tariffId).orElseThrow();
|
||||
TariffTimeTerm tariffTerm = tariff.getTariffTerm();
|
||||
LocalDateTime endDateTime = LocalDateTime.now().plusDays(tariffTerm.getDays());
|
||||
|
||||
TariffInfoDTO tariffInfoDTO = new TariffInfoDTO(null,
|
||||
tariffInfoRequest.getStatus() != null ? tariffInfoRequest.getStatus() : TariffStatus.ACTIVE.name(),
|
||||
tariffInfoRequest.getStartTariff() != null ? tariffInfoRequest.getStartTariff() : LocalDateTime.now(),
|
||||
tariffInfoRequest.getEndTariff() != null ? tariffInfoRequest.getEndTariff() : LocalDateTime.now().plusDays(30),
|
||||
tariffInfoRequest.getTariffId(), tariff.getName(), tariff.getTokens(), tariff.getDiskSize(), 0L,
|
||||
0, tariff.getMaxFilesCount());
|
||||
endDateTime, tariffInfoRequest.getTariffId(), tariff.getName(), tariff.getTokens(),
|
||||
tariff.getDiskSize(), 0L, 0, tariff.getMaxFilesCount());
|
||||
|
||||
TariffInfoDTO createdTariffInfo = tariffInfoService.createTariffInfo(tariffInfoDTO);
|
||||
|
||||
|
||||
@@ -0,0 +1,214 @@
|
||||
package ru.soune.nocopy.handler;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import ru.soune.nocopy.dto.BaseRequest;
|
||||
import ru.soune.nocopy.dto.BaseResponse;
|
||||
|
||||
import ru.soune.nocopy.dto.MessageCode;
|
||||
import ru.soune.nocopy.dto.user.UserAdditionalInfoBody;
|
||||
|
||||
import ru.soune.nocopy.entity.user.UserAdditionalInfo;
|
||||
import ru.soune.nocopy.entity.user.UserAdditionalInfoAnswer;
|
||||
import ru.soune.nocopy.entity.user.UserAdditionalInfoListAnswer;
|
||||
import ru.soune.nocopy.exception.UserAdditionalInfoNotFound;
|
||||
import ru.soune.nocopy.service.user.AdditionalInfoService;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class UserInfoHandler implements RequestHandler {
|
||||
|
||||
private final AdditionalInfoService additionalInfoService;
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
@Override
|
||||
public BaseResponse handle(BaseRequest request) throws Exception {
|
||||
try {
|
||||
UserAdditionalInfoBody body = objectMapper.convertValue(request.getMessageBody(),
|
||||
UserAdditionalInfoBody.class);
|
||||
|
||||
log.info("Processing UserInfoHandler with action: {}", body.getAction());
|
||||
|
||||
return switch (body.getAction()) {
|
||||
case "getAll" -> getAllAdditionalInfos(request);
|
||||
case "getById" -> getAdditionalInfoById(request, body.getUserId());
|
||||
case "update" -> updateAdditionalInfo(request, body);
|
||||
case "delete" -> deleteAdditionalInfo(request, body.getUserId());
|
||||
default -> new BaseResponse(
|
||||
request.getMsgId(),
|
||||
MessageCode.INVALID_ACTION.getCode(),
|
||||
"Invalid action: " + body.getAction(),
|
||||
null
|
||||
);
|
||||
};
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.error("Validation error in UserInfoHandler", e);
|
||||
return new BaseResponse(
|
||||
request.getMsgId(),
|
||||
MessageCode.VALIDATION_ERROR.getCode(),
|
||||
e.getMessage(),
|
||||
null);
|
||||
} catch (UserAdditionalInfoNotFound e) {
|
||||
log.error("User additional info not found", e);
|
||||
return new BaseResponse(
|
||||
request.getMsgId(),
|
||||
MessageCode.NOT_FOUND.getCode(),
|
||||
e.getMessage(),
|
||||
null);
|
||||
} catch (Exception e) {
|
||||
log.error("Unexpected error in UserInfoHandler", e);
|
||||
return new BaseResponse(
|
||||
request.getMsgId(),
|
||||
MessageCode.INTERNAL_ERROR.getCode(),
|
||||
"Internal server error: " + e.getMessage(),
|
||||
null);
|
||||
}
|
||||
}
|
||||
|
||||
private BaseResponse getAllAdditionalInfos(BaseRequest request) {
|
||||
log.info("Getting all additional infos");
|
||||
|
||||
List<UserAdditionalInfo> infos = additionalInfoService.getAllAdditionalInfos();
|
||||
|
||||
List<UserAdditionalInfoAnswer> answerItems = infos.stream()
|
||||
.map(this::convertToAnswer)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
UserAdditionalInfoListAnswer listAnswer = UserAdditionalInfoListAnswer.builder()
|
||||
.items(answerItems)
|
||||
.count(answerItems.size())
|
||||
.build();
|
||||
|
||||
return new BaseResponse(
|
||||
request.getMsgId(),
|
||||
MessageCode.SUCCESS.getCode(),
|
||||
MessageCode.SUCCESS.getDescription(),
|
||||
listAnswer
|
||||
);
|
||||
}
|
||||
|
||||
private BaseResponse getAdditionalInfoById(BaseRequest request, Long userId) {
|
||||
log.info("Getting additional info for user: {}", userId);
|
||||
|
||||
if (userId == null) {
|
||||
throw new IllegalArgumentException("User ID is required for getById action");
|
||||
}
|
||||
|
||||
UserAdditionalInfo info = additionalInfoService.getAdditionalInfoByUser(userId);
|
||||
|
||||
if (info == null) {
|
||||
throw new UserAdditionalInfoNotFound(
|
||||
String.format("User additional info not found for userId: %d", userId)
|
||||
);
|
||||
}
|
||||
|
||||
UserAdditionalInfoAnswer answer = convertToAnswer(info);
|
||||
|
||||
return new BaseResponse(
|
||||
request.getMsgId(),
|
||||
MessageCode.SUCCESS.getCode(),
|
||||
MessageCode.SUCCESS.getDescription(),
|
||||
answer
|
||||
);
|
||||
}
|
||||
|
||||
private BaseResponse updateAdditionalInfo(BaseRequest request, UserAdditionalInfoBody body) {
|
||||
log.info("Updating additional info for user: {}", body.getUserId());
|
||||
|
||||
if (body.getUserId() == null) {
|
||||
throw new IllegalArgumentException("User ID is required for update action");
|
||||
}
|
||||
|
||||
validateIpAddress(body.getIpAddress());
|
||||
validateUserAgent(body.getUserAgent());
|
||||
|
||||
Optional<UserAdditionalInfo> updatedInfo = additionalInfoService.updateAdditionalInfo(
|
||||
body.getUserId(),
|
||||
body.getIpAddress(),
|
||||
body.getUserAgent()
|
||||
);
|
||||
|
||||
if (updatedInfo.isEmpty()) {
|
||||
throw new UserAdditionalInfoNotFound(
|
||||
String.format("User additional info not found for userId: %d", body.getUserId())
|
||||
);
|
||||
}
|
||||
|
||||
UserAdditionalInfoAnswer answer = convertToAnswer(updatedInfo.get());
|
||||
|
||||
return new BaseResponse(
|
||||
request.getMsgId(),
|
||||
MessageCode.SUCCESS.getCode(),
|
||||
MessageCode.SUCCESS.getDescription(),
|
||||
answer
|
||||
);
|
||||
}
|
||||
|
||||
private BaseResponse deleteAdditionalInfo(BaseRequest request, Long userId) {
|
||||
log.info("Deleting additional info for user: {}", userId);
|
||||
|
||||
if (userId == null) {
|
||||
throw new IllegalArgumentException("User ID is required for delete action");
|
||||
}
|
||||
|
||||
UserAdditionalInfo existingInfo = additionalInfoService.getAdditionalInfoByUser(userId);
|
||||
|
||||
if (existingInfo == null) {
|
||||
throw new UserAdditionalInfoNotFound(
|
||||
String.format("User additional info not found for userId: %d", userId)
|
||||
);
|
||||
}
|
||||
|
||||
additionalInfoService.deleteAdditionalInfo(userId);
|
||||
|
||||
return new BaseResponse(
|
||||
request.getMsgId(),
|
||||
MessageCode.SUCCESS.getCode(),
|
||||
MessageCode.SUCCESS.getDescription(),
|
||||
Map.of("deleted", true, "user_id", userId)
|
||||
);
|
||||
}
|
||||
|
||||
private UserAdditionalInfoAnswer convertToAnswer(UserAdditionalInfo info) {
|
||||
return UserAdditionalInfoAnswer.builder()
|
||||
.id(info.getId())
|
||||
.userId(info.getUser() != null ? info.getUser().getId() : null)
|
||||
.ipAddress(info.getIpAddress())
|
||||
.userAgent(info.getUserAgent())
|
||||
.registrationDate(info.getRegistrationDate())
|
||||
.build();
|
||||
}
|
||||
|
||||
private void validateIpAddress(String ip) {
|
||||
if (ip == null || ip.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("IP address is required for update action");
|
||||
}
|
||||
|
||||
String ipv4Pattern =
|
||||
"^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$";
|
||||
|
||||
if (!ip.trim().matches(ipv4Pattern)) {
|
||||
log.warn("Invalid IP address format: {}", ip);
|
||||
throw new IllegalArgumentException("Invalid IP address format");
|
||||
}
|
||||
}
|
||||
|
||||
private void validateUserAgent(String userAgent) {
|
||||
if (userAgent == null || userAgent.trim().isEmpty()) {
|
||||
throw new IllegalArgumentException("User agent is required for update action");
|
||||
}
|
||||
|
||||
if (userAgent.length() > 500) {
|
||||
throw new IllegalArgumentException("User agent must not exceed 500 characters");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import ru.soune.nocopy.service.register.AuthService;
|
||||
import ru.soune.nocopy.service.user.UserService;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
@@ -53,9 +54,9 @@ public class VerifyRegisterUserHandler implements RequestHandler {
|
||||
User user = userRepository.findById(userId)
|
||||
.orElseThrow(() -> new UserNotFoundException("User not found with id: " + userId));
|
||||
|
||||
Optional<AuthToken> userAuthTokens = authTokenRepository.findByUserId(userId);
|
||||
List<AuthToken> userAuthTokens = authTokenRepository.findByUserId(userId);
|
||||
|
||||
AuthToken authToken = userAuthTokens.isEmpty() ? authService.generateAuthToken(user): userAuthTokens.get();
|
||||
AuthToken authToken = userAuthTokens.isEmpty() ? authService.generateAuthToken(user): userAuthTokens.getFirst();
|
||||
|
||||
if (verifyUserRequest.getResend() != null && verifyUserRequest.getResend() == 1) {
|
||||
return handleResend(request, user, authToken);
|
||||
@@ -68,13 +69,13 @@ public class VerifyRegisterUserHandler implements RequestHandler {
|
||||
|
||||
EmailVerificationToken token = emailVerificationTokenRepository.findByUserId(user.getId());
|
||||
|
||||
if (token != null && !token.isExpired()) {
|
||||
emailService.sendVerificationEmail(user, token.getToken());
|
||||
|
||||
log.info("Verification token resent for user {}", user.getEmail());
|
||||
return successResponse(request, authToken, "Verification code has been resent", false,
|
||||
false, user.getEmail());
|
||||
}
|
||||
// if (token != null && !token.isExpired()) {
|
||||
// emailService.sendVerificationEmail(user, token.getToken());
|
||||
//
|
||||
// log.info("Verification token resent for user {}", user.getEmail());
|
||||
// return successResponse(request, authToken, "Verification code has been resent", false,
|
||||
// false, user.getEmail());
|
||||
// }
|
||||
|
||||
if (token != null) {
|
||||
emailVerificationTokenRepository.delete(token);
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
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.stereotype.Component;
|
||||
import ru.soune.nocopy.dto.BaseRequest;
|
||||
import ru.soune.nocopy.dto.BaseResponse;
|
||||
import ru.soune.nocopy.dto.violation.ViolationRequest;
|
||||
import ru.soune.nocopy.dto.violation.ViolationResponse;
|
||||
import ru.soune.nocopy.entity.file.FileEntity;
|
||||
import ru.soune.nocopy.entity.violation.Violation;
|
||||
import ru.soune.nocopy.repository.FileEntityRepository;
|
||||
import ru.soune.nocopy.service.file.FileEntityService;
|
||||
import ru.soune.nocopy.service.register.AuthService;
|
||||
import ru.soune.nocopy.service.violation.ViolationService;
|
||||
import ru.soune.nocopy.service.violation.ViolationStatus;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@Component
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class ViolationHandler implements RequestHandler {
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
private final ViolationService violationService;
|
||||
|
||||
private final FileEntityRepository fileRepository;
|
||||
|
||||
private final AuthService authService;
|
||||
|
||||
private final FileEntityService fileEntityService;
|
||||
|
||||
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
@Override
|
||||
public BaseResponse handle(BaseRequest request) throws Exception {
|
||||
ViolationRequest violationRequest = objectMapper.convertValue(request.getMessageBody(), ViolationRequest.class);
|
||||
|
||||
validateRequest(violationRequest);
|
||||
|
||||
String token = violationRequest.getToken();
|
||||
Long userId = authService.useUserAuthToken(token);
|
||||
|
||||
List<FileEntity> targetFiles;
|
||||
|
||||
if (violationRequest.getFileId() != null && !violationRequest.getFileId().isEmpty()) {
|
||||
FileEntity file = fileRepository.findById(violationRequest.getFileId())
|
||||
.orElseThrow(() -> new FileNotFoundException("File not found with id: " + violationRequest.getFileId()));
|
||||
targetFiles = List.of(file);
|
||||
} else {
|
||||
targetFiles = fileEntityService.getAllUserFiles(userId);
|
||||
}
|
||||
|
||||
LocalDateTime startDate = null;
|
||||
LocalDateTime endDate = null;
|
||||
|
||||
if (violationRequest.getStartDate() != null && violationRequest.getEndDate() != null) {
|
||||
startDate = parseDate(violationRequest.getStartDate());
|
||||
endDate = parseDate(violationRequest.getEndDate());
|
||||
}
|
||||
|
||||
if ("updateStatus".equals(violationRequest.getAction())) {
|
||||
String status = violationRequest.getStatus();
|
||||
Long violationId = violationRequest.getViolationId();
|
||||
|
||||
violationService.changeStatus(ViolationStatus.valueOf(status), violationId);
|
||||
|
||||
return BaseResponse.builder()
|
||||
.msgId(request.getMsgId())
|
||||
.messageBody(Map.of("status", status))
|
||||
.build();
|
||||
}
|
||||
|
||||
if ("group".equalsIgnoreCase(violationRequest.getAction())) {
|
||||
Map<String, Long> groupedData = violationService.getGroupedViolations(
|
||||
targetFiles,
|
||||
violationRequest.getGroupBy(),
|
||||
violationRequest.getStatus(),
|
||||
startDate,
|
||||
endDate,
|
||||
violationRequest.getSortDirection());
|
||||
|
||||
return BaseResponse.builder()
|
||||
.msgId(request.getMsgId())
|
||||
.messageBody(groupedData)
|
||||
.build();
|
||||
} else {
|
||||
Page<Violation> violationPage;
|
||||
|
||||
if (startDate != null && endDate != null) {
|
||||
violationPage = violationService.getViolationsByFilesAndDateRange(
|
||||
targetFiles, startDate, endDate,
|
||||
violationRequest.getPage(), violationRequest.getSize(), violationRequest.getSortDirection()
|
||||
);
|
||||
} else if (violationRequest.getStatus() != null && !violationRequest.getStatus().isEmpty()) {
|
||||
violationPage = violationService.getViolationsByFilesAndStatus(
|
||||
targetFiles, violationRequest.getStatus(),
|
||||
violationRequest.getPage(), violationRequest.getSize(), violationRequest.getSortDirection()
|
||||
);
|
||||
} else {
|
||||
violationPage = violationService.getViolationsByFiles(
|
||||
targetFiles,
|
||||
violationRequest.getPage(), violationRequest.getSize(), violationRequest.getSortDirection()
|
||||
);
|
||||
}
|
||||
|
||||
List<ViolationResponse.ViolationDto> violationDtos = violationPage.getContent()
|
||||
.stream()
|
||||
.map(ViolationResponse.ViolationDto::fromEntity)
|
||||
.toList();
|
||||
|
||||
ViolationResponse response = ViolationResponse.builder()
|
||||
.violations(violationDtos)
|
||||
.totalElements(violationPage.getTotalElements())
|
||||
.totalPages(violationPage.getTotalPages())
|
||||
.currentPage(violationPage.getNumber())
|
||||
.pageSize(violationPage.getSize())
|
||||
.hasNext(violationPage.hasNext())
|
||||
.hasPrevious(violationPage.hasPrevious())
|
||||
.build();
|
||||
|
||||
return BaseResponse.builder()
|
||||
.msgId(request.getMsgId())
|
||||
.messageBody(response)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
private void validateRequest(ViolationRequest request) {
|
||||
if (request.getPage() < 0) {
|
||||
request.setPage(0);
|
||||
}
|
||||
|
||||
if (request.getSize() <= 0 || request.getSize() > 100) {
|
||||
request.setSize(10);
|
||||
}
|
||||
|
||||
if (!request.getSortDirection().equalsIgnoreCase("asc") &&
|
||||
!request.getSortDirection().equalsIgnoreCase("desc")) {
|
||||
request.setSortDirection("desc");
|
||||
}
|
||||
}
|
||||
|
||||
private LocalDateTime parseDate(String dateStr) {
|
||||
try {
|
||||
return LocalDateTime.parse(dateStr, DATE_FORMATTER);
|
||||
} catch (DateTimeParseException e) {
|
||||
log.error(e.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
package ru.soune.nocopy.handler;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import ru.soune.nocopy.dto.BaseRequest;
|
||||
import ru.soune.nocopy.dto.BaseResponse;
|
||||
import ru.soune.nocopy.dto.MessageCode;
|
||||
import ru.soune.nocopy.dto.violation.*;
|
||||
import ru.soune.nocopy.entity.user.AuthToken;
|
||||
import ru.soune.nocopy.repository.AuthTokenRepository;
|
||||
import ru.soune.nocopy.service.violation.ViolationNotionService;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class ViolationNotionHandler implements RequestHandler {
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
private final ViolationNotionService notionService;
|
||||
|
||||
private final AuthTokenRepository authTokenRepository;
|
||||
|
||||
@Override
|
||||
public BaseResponse handle(BaseRequest request) {
|
||||
try {
|
||||
ViolationNotionRequest notionRequest = objectMapper.convertValue(
|
||||
request.getMessageBody(), ViolationNotionRequest.class);
|
||||
|
||||
if (notionRequest.getToken() == null) {
|
||||
return new BaseResponse(
|
||||
request.getMsgId(),
|
||||
MessageCode.INVALID_TOKEN.getCode(),
|
||||
"Token is required",
|
||||
null);
|
||||
}
|
||||
|
||||
Optional<AuthToken> tokenOptional = authTokenRepository.findByToken(notionRequest.getToken());
|
||||
if (tokenOptional.isEmpty()) {
|
||||
return new BaseResponse(
|
||||
request.getMsgId(),
|
||||
MessageCode.INVALID_TOKEN.getCode(),
|
||||
"Invalid token",
|
||||
null);
|
||||
}
|
||||
|
||||
Long userId = tokenOptional.get().getUser().getId();
|
||||
String action = notionRequest.getAction();
|
||||
|
||||
if (action == null || action.trim().isEmpty()) {
|
||||
return new BaseResponse(
|
||||
request.getMsgId(),
|
||||
MessageCode.INVALID_ACTION.getCode(),
|
||||
"Action is required",
|
||||
null);
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
case "get_notions":
|
||||
return handleGetNotions(request, notionRequest, userId);
|
||||
case "get_notion":
|
||||
return handleGetNotion(request, notionRequest, userId);
|
||||
case "add_notion":
|
||||
return handleAddNotion(request, notionRequest, userId);
|
||||
case "update_notion":
|
||||
return handleUpdateNotion(request, notionRequest, userId);
|
||||
case "delete_notion":
|
||||
return handleDeleteNotion(request, notionRequest, userId);
|
||||
default:
|
||||
return new BaseResponse(
|
||||
request.getMsgId(),
|
||||
MessageCode.INVALID_ACTION.getCode(),
|
||||
"Invalid action: " + action,
|
||||
null);
|
||||
}
|
||||
|
||||
} catch (IllegalArgumentException e) {
|
||||
log.error("Validation error: {}", e.getMessage());
|
||||
return new BaseResponse(
|
||||
request.getMsgId(),
|
||||
MessageCode.VALIDATION_ERROR.getCode(),
|
||||
e.getMessage(),
|
||||
null);
|
||||
} catch (SecurityException e) {
|
||||
log.error("Security error: {}", e.getMessage());
|
||||
return new BaseResponse(
|
||||
request.getMsgId(),
|
||||
MessageCode.ACCESS_DENIED.getCode(),
|
||||
e.getMessage(),
|
||||
null);
|
||||
} catch (Exception e) {
|
||||
log.error("Unexpected error", e);
|
||||
return new BaseResponse(
|
||||
request.getMsgId(),
|
||||
MessageCode.INTERNAL_ERROR.getCode(),
|
||||
"Internal server error",
|
||||
null);
|
||||
}
|
||||
}
|
||||
|
||||
private BaseResponse handleGetNotions(BaseRequest request, ViolationNotionRequest notionRequest, Long userId) {
|
||||
if (notionRequest.getViolationId() == null) {
|
||||
return new BaseResponse(
|
||||
request.getMsgId(),
|
||||
MessageCode.INVALID_JSON_BODY.getCode(),
|
||||
"ViolationId is required for get_notions action",
|
||||
null);
|
||||
}
|
||||
|
||||
try {
|
||||
ViolationNotionsListResponse notions = notionService.getNotionsByViolationId(
|
||||
notionRequest.getViolationId(), userId);
|
||||
return BaseResponse.builder()
|
||||
.msgId(request.getMsgId())
|
||||
.messageBody(notions)
|
||||
.build();
|
||||
} catch (IllegalArgumentException e) {
|
||||
return new BaseResponse(
|
||||
request.getMsgId(),
|
||||
MessageCode.NOTION_NOT_FOUND.getCode(),
|
||||
e.getMessage(),
|
||||
null);
|
||||
}
|
||||
}
|
||||
|
||||
private BaseResponse handleGetNotion(BaseRequest request, ViolationNotionRequest notionRequest, Long userId) {
|
||||
if (notionRequest.getNotionId() == null) {
|
||||
return new BaseResponse(
|
||||
request.getMsgId(),
|
||||
MessageCode.INVALID_JSON_BODY.getCode(),
|
||||
"NotionId is required for get_notion action",
|
||||
null);
|
||||
}
|
||||
|
||||
try {
|
||||
ViolationNotionResponse notion = notionService.getNotionById(
|
||||
notionRequest.getNotionId(), userId);
|
||||
return BaseResponse.builder()
|
||||
.msgId(request.getMsgId())
|
||||
.messageBody(notion)
|
||||
.build();
|
||||
} catch (IllegalArgumentException e) {
|
||||
return new BaseResponse(
|
||||
request.getMsgId(),
|
||||
MessageCode.NOTION_NOT_FOUND.getCode(),
|
||||
e.getMessage(),
|
||||
null);
|
||||
}
|
||||
}
|
||||
|
||||
private BaseResponse handleAddNotion(BaseRequest request, ViolationNotionRequest notionRequest, Long userId) {
|
||||
if (notionRequest.getViolationId() == null) {
|
||||
return new BaseResponse(
|
||||
request.getMsgId(),
|
||||
MessageCode.INVALID_JSON_BODY.getCode(),
|
||||
"ViolationId is required for add_notion action",
|
||||
null);
|
||||
}
|
||||
|
||||
if (notionRequest.getMessage() == null || notionRequest.getMessage().trim().isEmpty()) {
|
||||
return new BaseResponse(
|
||||
request.getMsgId(),
|
||||
MessageCode.INVALID_JSON_BODY.getCode(),
|
||||
"Message is required for add_notion action",
|
||||
null);
|
||||
}
|
||||
|
||||
try {
|
||||
ViolationNotionResponse created = notionService.createNotion(
|
||||
notionRequest.getViolationId(), userId, notionRequest.getMessage());
|
||||
return BaseResponse.builder()
|
||||
.msgId(request.getMsgId())
|
||||
.messageBody(created)
|
||||
.build();
|
||||
} catch (IllegalArgumentException e) {
|
||||
return new BaseResponse(
|
||||
request.getMsgId(),
|
||||
MessageCode.NOTION_NOT_FOUND.getCode(),
|
||||
e.getMessage(),
|
||||
null);
|
||||
}
|
||||
}
|
||||
|
||||
private BaseResponse handleUpdateNotion(BaseRequest request, ViolationNotionRequest notionRequest, Long userId) {
|
||||
if (notionRequest.getNotionId() == null) {
|
||||
return new BaseResponse(
|
||||
request.getMsgId(),
|
||||
MessageCode.INVALID_JSON_BODY.getCode(),
|
||||
"NotionId is required for update_notion action",
|
||||
null);
|
||||
}
|
||||
|
||||
if (notionRequest.getMessage() == null || notionRequest.getMessage().trim().isEmpty()) {
|
||||
return new BaseResponse(
|
||||
request.getMsgId(),
|
||||
MessageCode.INVALID_JSON_BODY.getCode(),
|
||||
"Message is required for update_notion action",
|
||||
null);
|
||||
}
|
||||
|
||||
try {
|
||||
ViolationNotionResponse updated = notionService.updateNotion(
|
||||
notionRequest.getNotionId(), userId, notionRequest.getMessage());
|
||||
return BaseResponse.builder()
|
||||
.msgId(request.getMsgId())
|
||||
.messageBody(updated)
|
||||
.build();
|
||||
} catch (IllegalArgumentException e) {
|
||||
return new BaseResponse(
|
||||
request.getMsgId(),
|
||||
MessageCode.NOTION_NOT_FOUND.getCode(),
|
||||
e.getMessage(),
|
||||
null);
|
||||
} catch (SecurityException e) {
|
||||
return new BaseResponse(
|
||||
request.getMsgId(),
|
||||
MessageCode.ACCESS_DENIED.getCode(),
|
||||
e.getMessage(),
|
||||
null);
|
||||
}
|
||||
}
|
||||
|
||||
private BaseResponse handleDeleteNotion(BaseRequest request, ViolationNotionRequest notionRequest, Long userId) {
|
||||
if (notionRequest.getNotionId() == null) {
|
||||
return new BaseResponse(
|
||||
request.getMsgId(),
|
||||
MessageCode.INVALID_JSON_BODY.getCode(),
|
||||
"NotionId is required for delete_notion action",
|
||||
null);
|
||||
}
|
||||
|
||||
try {
|
||||
notionService.deleteNotion(notionRequest.getNotionId(), userId);
|
||||
DeleteNotionResponse deleteResponse = DeleteNotionResponse.builder()
|
||||
.notionId(notionRequest.getNotionId())
|
||||
.message("Notion deleted successfully")
|
||||
.deleted(true)
|
||||
.build();
|
||||
return BaseResponse.builder()
|
||||
.msgId(request.getMsgId())
|
||||
.messageBody(deleteResponse)
|
||||
.build();
|
||||
} catch (IllegalArgumentException e) {
|
||||
return new BaseResponse(
|
||||
request.getMsgId(),
|
||||
MessageCode.NOTION_NOT_FOUND.getCode(),
|
||||
e.getMessage(),
|
||||
null);
|
||||
} catch (SecurityException e) {
|
||||
return new BaseResponse(
|
||||
request.getMsgId(),
|
||||
MessageCode.ACCESS_DENIED.getCode(),
|
||||
e.getMessage(),
|
||||
null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package ru.soune.nocopy.handler;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
import ru.soune.nocopy.dto.BaseRequest;
|
||||
import ru.soune.nocopy.dto.BaseResponse;
|
||||
import ru.soune.nocopy.dto.violation.ViolationStatisticsRequest;
|
||||
import ru.soune.nocopy.dto.violation.ViolationStatisticsResponse;
|
||||
import ru.soune.nocopy.entity.user.AuthToken;
|
||||
import ru.soune.nocopy.repository.AuthTokenRepository;
|
||||
import ru.soune.nocopy.service.violation.ViolationService;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.Optional;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class ViolationStatisticsHandler implements RequestHandler {
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
private final ViolationService violationService;
|
||||
|
||||
private final AuthTokenRepository authTokenRepository;
|
||||
|
||||
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
@Override
|
||||
public BaseResponse handle(BaseRequest request) throws Exception {
|
||||
ViolationStatisticsRequest statRequest = objectMapper.convertValue(
|
||||
request.getMessageBody(), ViolationStatisticsRequest.class);
|
||||
|
||||
validateRequest(statRequest);
|
||||
|
||||
LocalDateTime startDate = null;
|
||||
LocalDateTime endDate = null;
|
||||
|
||||
if (statRequest.getStartDate() != null && statRequest.getEndDate() != null) {
|
||||
startDate = parseDate(statRequest.getStartDate());
|
||||
endDate = parseDate(statRequest.getEndDate());
|
||||
|
||||
if (endDate != null && !statRequest.getEndDate().contains(" ")) {
|
||||
endDate = endDate.withHour(23).withMinute(59).withSecond(59);
|
||||
}
|
||||
}
|
||||
|
||||
Optional<AuthToken> tokenOptional =
|
||||
authTokenRepository.findByToken(statRequest.getToken());
|
||||
|
||||
if (tokenOptional.isEmpty()) {
|
||||
throw new IllegalArgumentException("User token is required");
|
||||
}
|
||||
|
||||
Long userId = tokenOptional.orElseThrow().getUser().getId();
|
||||
|
||||
ViolationStatisticsResponse statistics = violationService.getViolationStatistics(
|
||||
userId,
|
||||
statRequest.getFileId(),
|
||||
startDate,
|
||||
endDate);
|
||||
|
||||
return BaseResponse.builder()
|
||||
.msgId(request.getMsgId())
|
||||
.messageBody(statistics)
|
||||
.build();
|
||||
}
|
||||
|
||||
private void validateRequest(ViolationStatisticsRequest request) {
|
||||
if (request.getToken() == null) {
|
||||
throw new IllegalArgumentException("Token is required");
|
||||
}
|
||||
}
|
||||
|
||||
private LocalDateTime parseDate(String dateStr) {
|
||||
try {
|
||||
return LocalDateTime.parse(dateStr, DATE_FORMATTER);
|
||||
} catch (DateTimeParseException e) {
|
||||
try {
|
||||
return LocalDateTime.parse(dateStr + " 00:00:00", DATE_FORMATTER);
|
||||
} catch (DateTimeParseException ex) {
|
||||
log.error("Error parsing date: {}", dateStr, ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package ru.soune.nocopy.handler.validator;
|
||||
|
||||
import org.apache.commons.validator.routines.EmailValidator;
|
||||
import org.apache.commons.validator.routines.InetAddressValidator;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.Validator;
|
||||
@@ -28,6 +29,7 @@ public class RegRequestValidator implements Validator {
|
||||
validateEmail(request.getEmail(), errors);
|
||||
validateCompanyName(request.getCompanyName(), errors);
|
||||
validateFullName(request.getFullName(), errors);
|
||||
validateAdditionalInfo(request.getIp(), request.getUserAgent(), errors);
|
||||
}
|
||||
|
||||
private void validateFullName(String fullName, Errors errors) {
|
||||
@@ -73,6 +75,21 @@ public class RegRequestValidator implements Validator {
|
||||
}
|
||||
}
|
||||
|
||||
public void validateAdditionalInfo(String ip, String userAgent, Errors errors) {
|
||||
if (ip == null || ip.trim().isEmpty()) {
|
||||
errors.rejectValue("ip", "ip.required", "IP address is required");
|
||||
} else if (!InetAddressValidator.getInstance().isValid(ip.trim())) {
|
||||
errors.rejectValue("ip", "ip.invalid", "Invalid IP address format");
|
||||
}
|
||||
|
||||
if (userAgent == null || userAgent.trim().isEmpty()) {
|
||||
errors.rejectValue("userAgent", "userAgent.required", "User agent is required");
|
||||
} else if (userAgent.length() > 500) {
|
||||
errors.rejectValue("userAgent", "userAgent.tooLong", "User agent must not exceed " +
|
||||
"500 characters");
|
||||
}
|
||||
}
|
||||
|
||||
public void validateEmail(String email, Errors errors) {
|
||||
if (email == null || email.trim().isEmpty()) {
|
||||
errors.rejectValue("email", "email.is.empty", "Email must not be empty");
|
||||
|
||||
Reference in New Issue
Block a user