@@ -0,0 +1,28 @@
|
|||||||
|
package ru.soune.nocopy.configuration;
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import ru.soune.nocopy.handler.*;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class HandlerConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Map<Integer, RequestHandler> handlers(
|
||||||
|
RegRequestHandler reg,
|
||||||
|
LoginRequestHandler login,
|
||||||
|
FileUploadHandler upload,
|
||||||
|
FileEntityHandler file
|
||||||
|
) {
|
||||||
|
Map<Integer, RequestHandler> map = new HashMap<>();
|
||||||
|
map.put(20001, login);
|
||||||
|
map.put(20002, reg);
|
||||||
|
map.put(20004, upload);
|
||||||
|
map.put(20005, file);
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,7 @@
|
|||||||
package ru.soune.nocopy.controller;
|
package ru.soune.nocopy.controller;
|
||||||
|
|
||||||
import jakarta.annotation.PostConstruct;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.context.ApplicationContext;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.validation.BindingResult;
|
import org.springframework.validation.BindingResult;
|
||||||
import org.springframework.validation.FieldError;
|
import org.springframework.validation.FieldError;
|
||||||
@@ -19,10 +17,7 @@ import ru.soune.nocopy.dto.file.UploadProgress;
|
|||||||
import ru.soune.nocopy.entity.file.UploadStatus;
|
import ru.soune.nocopy.entity.file.UploadStatus;
|
||||||
import ru.soune.nocopy.exception.NotValidFieldException;
|
import ru.soune.nocopy.exception.NotValidFieldException;
|
||||||
import ru.soune.nocopy.exception.ValidationException;
|
import ru.soune.nocopy.exception.ValidationException;
|
||||||
import ru.soune.nocopy.handler.FileUploadHandler;
|
import ru.soune.nocopy.handler.*;
|
||||||
import ru.soune.nocopy.handler.LoginRequestHandler;
|
|
||||||
import ru.soune.nocopy.handler.RegRequestHandler;
|
|
||||||
import ru.soune.nocopy.handler.RequestHandler;
|
|
||||||
import ru.soune.nocopy.service.file.FileUploadService;
|
import ru.soune.nocopy.service.file.FileUploadService;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -35,21 +30,10 @@ import java.util.stream.Collectors;
|
|||||||
@RequestMapping("/api")
|
@RequestMapping("/api")
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class ApiController {
|
public class ApiController {
|
||||||
private final ApplicationContext applicationContext;
|
|
||||||
private final FileUploadService fileUploadService;
|
private final FileUploadService fileUploadService;
|
||||||
|
|
||||||
private Map<Integer, RequestHandler> handlers = new HashMap<>();
|
private final Map<Integer, RequestHandler> handlers;
|
||||||
|
|
||||||
@PostConstruct
|
|
||||||
public void init() {
|
|
||||||
RegRequestHandler regHandler = applicationContext.getBean(RegRequestHandler.class);
|
|
||||||
LoginRequestHandler loginHandler = applicationContext.getBean(LoginRequestHandler.class);
|
|
||||||
FileUploadHandler fileUploadHandler = applicationContext.getBean(FileUploadHandler.class);
|
|
||||||
|
|
||||||
handlers.put(20004, fileUploadHandler);
|
|
||||||
handlers.put(20002, regHandler);
|
|
||||||
handlers.put(20001, loginHandler);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/v{version}/data")
|
@PostMapping("/v{version}/data")
|
||||||
public ResponseEntity<?> handlePostRequest(@RequestBody BaseRequest request,
|
public ResponseEntity<?> handlePostRequest(@RequestBody BaseRequest request,
|
||||||
|
|||||||
@@ -1,210 +0,0 @@
|
|||||||
package ru.soune.nocopy.controller.file;
|
|
||||||
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
import ru.soune.nocopy.dto.file.FileApiResponse;
|
|
||||||
import ru.soune.nocopy.dto.file.FileEntityResponse;
|
|
||||||
import ru.soune.nocopy.dto.file.FileListResponse;
|
|
||||||
import ru.soune.nocopy.entity.AuthToken;
|
|
||||||
import ru.soune.nocopy.exception.NotFoundAuthToken;
|
|
||||||
import ru.soune.nocopy.repository.AuthTokenRepository;
|
|
||||||
import ru.soune.nocopy.service.file.FileEntityService;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/file-entities")
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class FileEntityController {
|
|
||||||
|
|
||||||
private final FileEntityService fileEntityService;
|
|
||||||
private final AuthTokenRepository authTokenRepository;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Получить информацию о файле по ID
|
|
||||||
*/
|
|
||||||
@GetMapping("/{fileId}")
|
|
||||||
public ResponseEntity<FileApiResponse<FileEntityResponse>> getFileInfo(
|
|
||||||
@PathVariable String fileId,
|
|
||||||
@RequestHeader("Authorization") String tokenHeader) {
|
|
||||||
|
|
||||||
try {
|
|
||||||
Long userId = getUserIdFromToken(tokenHeader);
|
|
||||||
FileEntityResponse fileInfo = fileEntityService.getById(fileId);
|
|
||||||
|
|
||||||
if (!fileInfo.getUserId().equals(userId)) {
|
|
||||||
return ResponseEntity.status(403)
|
|
||||||
.body(FileApiResponse.error("Access denied"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return ResponseEntity.ok(FileApiResponse.success(fileInfo));
|
|
||||||
|
|
||||||
} catch (NotFoundAuthToken e) {
|
|
||||||
return ResponseEntity.status(401)
|
|
||||||
.body(FileApiResponse.error("Authentication required"));
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Error getting file info", e);
|
|
||||||
return ResponseEntity.badRequest()
|
|
||||||
.body(FileApiResponse.error("Failed to get file info: " + e.getMessage()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Получить информацию о файле по ID сессии загрузки
|
|
||||||
*/
|
|
||||||
@GetMapping("/by-session/{uploadSessionId}")
|
|
||||||
public ResponseEntity<FileApiResponse<FileEntityResponse>> getFileByUploadSession(
|
|
||||||
@PathVariable String uploadSessionId,
|
|
||||||
@RequestHeader("Authorization") String tokenHeader) {
|
|
||||||
|
|
||||||
try {
|
|
||||||
Long userId = getUserIdFromToken(tokenHeader);
|
|
||||||
FileEntityResponse fileInfo = fileEntityService.getByUploadSessionId(uploadSessionId);
|
|
||||||
|
|
||||||
if (!fileInfo.getUserId().equals(userId)) {
|
|
||||||
return ResponseEntity.status(403)
|
|
||||||
.body(FileApiResponse.error("Access denied"));
|
|
||||||
}
|
|
||||||
|
|
||||||
return ResponseEntity.ok(FileApiResponse.success(fileInfo));
|
|
||||||
|
|
||||||
} catch (NotFoundAuthToken e) {
|
|
||||||
return ResponseEntity.status(401)
|
|
||||||
.body(FileApiResponse.error("Authentication required"));
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Error getting file by session", e);
|
|
||||||
return ResponseEntity.badRequest()
|
|
||||||
.body(FileApiResponse.error("Failed to get file: " + e.getMessage()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Получить все файлы пользователя
|
|
||||||
*/
|
|
||||||
@GetMapping("/my-files")
|
|
||||||
public ResponseEntity<FileApiResponse<FileListResponse>> getUserFiles(
|
|
||||||
@RequestHeader("Authorization") String tokenHeader,
|
|
||||||
@RequestParam(defaultValue = "1") int page,
|
|
||||||
@RequestParam(defaultValue = "20") int pageSize) {
|
|
||||||
|
|
||||||
try {
|
|
||||||
Long userId = getUserIdFromToken(tokenHeader);
|
|
||||||
FileListResponse files = fileEntityService.getUserFiles(userId, page, pageSize);
|
|
||||||
|
|
||||||
return ResponseEntity.ok(FileApiResponse.success(files));
|
|
||||||
|
|
||||||
} catch (NotFoundAuthToken e) {
|
|
||||||
return ResponseEntity.status(401)
|
|
||||||
.body(FileApiResponse.error("Authentication required"));
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Error getting user files", e);
|
|
||||||
return ResponseEntity.badRequest()
|
|
||||||
.body(FileApiResponse.error("Failed to get files: " + e.getMessage()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Поиск файлов пользователя
|
|
||||||
*/
|
|
||||||
@GetMapping("/search")
|
|
||||||
public ResponseEntity<FileApiResponse<FileListResponse>> searchFiles(
|
|
||||||
@RequestParam String query,
|
|
||||||
@RequestHeader("Authorization") String tokenHeader,
|
|
||||||
@RequestParam(defaultValue = "1") int page,
|
|
||||||
@RequestParam(defaultValue = "20") int pageSize) {
|
|
||||||
|
|
||||||
try {
|
|
||||||
Long userId = getUserIdFromToken(tokenHeader);
|
|
||||||
FileListResponse allFiles = fileEntityService.getUserFiles(userId, 1, 1000);
|
|
||||||
|
|
||||||
var filteredFiles = allFiles.getFiles().stream()
|
|
||||||
.filter(f -> f.getOriginalFileName().toLowerCase().contains(query.toLowerCase()))
|
|
||||||
.toList();
|
|
||||||
|
|
||||||
int start = (page - 1) * pageSize;
|
|
||||||
int end = Math.min(start + pageSize, filteredFiles.size());
|
|
||||||
|
|
||||||
FileListResponse response = FileListResponse.builder()
|
|
||||||
.files(filteredFiles.subList(start, Math.min(end, filteredFiles.size())))
|
|
||||||
.totalCount(filteredFiles.size())
|
|
||||||
.totalSize(allFiles.getTotalSize())
|
|
||||||
.formattedTotalSize(allFiles.getFormattedTotalSize())
|
|
||||||
.page(page)
|
|
||||||
.pageSize(pageSize)
|
|
||||||
.build();
|
|
||||||
|
|
||||||
return ResponseEntity.ok(FileApiResponse.success(response));
|
|
||||||
|
|
||||||
} catch (NotFoundAuthToken e) {
|
|
||||||
return ResponseEntity.status(401)
|
|
||||||
.body(FileApiResponse.error("Authentication required"));
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Error searching files", e);
|
|
||||||
return ResponseEntity.badRequest()
|
|
||||||
.body(FileApiResponse.error("Failed to search files: " + e.getMessage()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Получить общий размер файлов пользователя
|
|
||||||
*/
|
|
||||||
@GetMapping("/storage/usage")
|
|
||||||
public ResponseEntity<FileApiResponse<Long>> getStorageUsage(
|
|
||||||
@RequestHeader("Authorization") String tokenHeader) {
|
|
||||||
|
|
||||||
try {
|
|
||||||
Long userId = getUserIdFromToken(tokenHeader);
|
|
||||||
long usage = fileEntityService.getUserStorageUsed(userId);
|
|
||||||
|
|
||||||
return ResponseEntity.ok(FileApiResponse.success(usage));
|
|
||||||
|
|
||||||
} catch (NotFoundAuthToken e) {
|
|
||||||
return ResponseEntity.status(401)
|
|
||||||
.body(FileApiResponse.error("Authentication required"));
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Error getting storage usage", e);
|
|
||||||
return ResponseEntity.badRequest()
|
|
||||||
.body(FileApiResponse.error("Failed to get storage usage: " + e.getMessage()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Пометить файл как удаленный
|
|
||||||
*/
|
|
||||||
@DeleteMapping("/{fileId}")
|
|
||||||
public ResponseEntity<FileApiResponse<Void>> deleteFile(
|
|
||||||
@PathVariable String fileId,
|
|
||||||
@RequestHeader("Authorization") String tokenHeader) {
|
|
||||||
|
|
||||||
try {
|
|
||||||
Long userId = getUserIdFromToken(tokenHeader);
|
|
||||||
FileEntityResponse fileInfo = fileEntityService.getById(fileId);
|
|
||||||
|
|
||||||
if (!fileInfo.getUserId().equals(userId)) {
|
|
||||||
return ResponseEntity.status(403)
|
|
||||||
.body(FileApiResponse.error("Access denied"));
|
|
||||||
}
|
|
||||||
|
|
||||||
fileEntityService.markAsDeleted(fileId);
|
|
||||||
|
|
||||||
return ResponseEntity.ok(FileApiResponse.success(
|
|
||||||
"File marked as deleted", null));
|
|
||||||
|
|
||||||
} catch (NotFoundAuthToken e) {
|
|
||||||
return ResponseEntity.status(401)
|
|
||||||
.body(FileApiResponse.error("Authentication required"));
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Error deleting file", e);
|
|
||||||
return ResponseEntity.badRequest()
|
|
||||||
.body(FileApiResponse.error("Failed to delete file: " + e.getMessage()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private Long getUserIdFromToken(String tokenHeader) {
|
|
||||||
String token = tokenHeader.replace("Bearer ", "");
|
|
||||||
AuthToken authToken = authTokenRepository.findByToken(token)
|
|
||||||
.orElseThrow(() -> new NotFoundAuthToken("Token not found"));
|
|
||||||
return authToken.getUser().getId();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
package ru.soune.nocopy.controller.file;
|
|
||||||
|
|
||||||
import jakarta.validation.Valid;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
|
||||||
import org.springframework.web.bind.annotation.*;
|
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
|
||||||
import ru.soune.nocopy.dto.file.FileApiResponse;
|
|
||||||
import ru.soune.nocopy.dto.file.InitUploadRequest;
|
|
||||||
import ru.soune.nocopy.dto.file.UploadProgressResponse;
|
|
||||||
import ru.soune.nocopy.entity.AuthToken;
|
|
||||||
import ru.soune.nocopy.entity.file.FileType;
|
|
||||||
import ru.soune.nocopy.entity.file.FileUploadSession;
|
|
||||||
import ru.soune.nocopy.entity.file.UploadStatus;
|
|
||||||
import ru.soune.nocopy.exception.FileUploadException;
|
|
||||||
import ru.soune.nocopy.exception.NotFoundAuthToken;
|
|
||||||
import ru.soune.nocopy.exception.UploadSessionNotFoundException;
|
|
||||||
import ru.soune.nocopy.repository.AuthTokenRepository;
|
|
||||||
import ru.soune.nocopy.repository.FileUploadSessionRepository;
|
|
||||||
import ru.soune.nocopy.service.file.FileUploadService;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@RestController
|
|
||||||
@RequestMapping("/api/files")
|
|
||||||
@RequiredArgsConstructor
|
|
||||||
public class FileUploadController {
|
|
||||||
|
|
||||||
private final FileUploadService fileUploadService;
|
|
||||||
|
|
||||||
@PostMapping("/chunk")
|
|
||||||
public ResponseEntity<FileApiResponse<UploadProgressResponse>> uploadChunk(
|
|
||||||
@RequestParam("uploadId") String uploadId,
|
|
||||||
@RequestParam("chunkNumber") Integer chunkNumber,
|
|
||||||
@RequestParam("chunk") MultipartFile chunk) {
|
|
||||||
|
|
||||||
log.info("Uploading chunk {} for session {}, file size: {} bytes",
|
|
||||||
chunkNumber, uploadId, chunk.getSize());
|
|
||||||
|
|
||||||
if (chunk.isEmpty()) {
|
|
||||||
return ResponseEntity.badRequest()
|
|
||||||
.body(FileApiResponse.error("Chunk file is empty"));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (uploadId == null || uploadId.isBlank()) {
|
|
||||||
return ResponseEntity.badRequest()
|
|
||||||
.body(FileApiResponse.error("Upload ID is required"));
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
UploadProgressResponse progress = fileUploadService.uploadChunk(
|
|
||||||
uploadId, chunkNumber, chunk);
|
|
||||||
|
|
||||||
return ResponseEntity.ok(FileApiResponse.success(progress));
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Error uploading chunk", e);
|
|
||||||
return ResponseEntity.badRequest()
|
|
||||||
.body(FileApiResponse.error(e.getMessage()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -11,7 +11,8 @@ public enum MessageCode {
|
|||||||
INVALID_JSON_BODY(2, "Invalid fields in JSON object"),
|
INVALID_JSON_BODY(2, "Invalid fields in JSON object"),
|
||||||
INCOMPLETE_UPLOAD(2, "Not load all chunks"),
|
INCOMPLETE_UPLOAD(2, "Not load all chunks"),
|
||||||
MSG_ID_NOT_FOUND(4, "Message id not found"),
|
MSG_ID_NOT_FOUND(4, "Message id not found"),
|
||||||
|
FILE_ENTITY_ERROR(2, "File entity error"),
|
||||||
|
ACCESS_DENIED(2, "Access denied"),
|
||||||
AUTH_EMAIL_NOT_FOUND(4, "Email not found"),
|
AUTH_EMAIL_NOT_FOUND(4, "Email not found"),
|
||||||
FILE_NOT_FOUND(4, "File not found"),
|
FILE_NOT_FOUND(4, "File not found"),
|
||||||
AUTH_PASSWORD_NOT_MATCHES(2, "Password does not match");
|
AUTH_PASSWORD_NOT_MATCHES(2, "Password does not match");
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
package ru.soune.nocopy.dto.file;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class DeleteFileResponse {
|
||||||
|
@JsonProperty("file_id")
|
||||||
|
private String fileId;
|
||||||
|
|
||||||
|
@JsonProperty("message")
|
||||||
|
private String message;
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package ru.soune.nocopy.dto.file;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class FileEntityRequest {
|
||||||
|
@JsonProperty("action")
|
||||||
|
private String action;
|
||||||
|
|
||||||
|
@JsonProperty("file_id")
|
||||||
|
private String fileId;
|
||||||
|
|
||||||
|
@JsonProperty("upload_session_id")
|
||||||
|
private String uploadSessionId;
|
||||||
|
|
||||||
|
@JsonProperty("query")
|
||||||
|
private String query;
|
||||||
|
|
||||||
|
@JsonProperty("page")
|
||||||
|
private Integer page;
|
||||||
|
|
||||||
|
@JsonProperty("page_size")
|
||||||
|
private Integer pageSize;
|
||||||
|
|
||||||
|
@JsonProperty("token")
|
||||||
|
private String token;
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package ru.soune.nocopy.dto.file;
|
package ru.soune.nocopy.dto.file;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Builder;
|
import lombok.Builder;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
@@ -9,14 +10,24 @@ import java.util.List;
|
|||||||
|
|
||||||
@Data
|
@Data
|
||||||
@Builder
|
@Builder
|
||||||
@NoArgsConstructor
|
|
||||||
@AllArgsConstructor
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
public class FileListResponse {
|
public class FileListResponse {
|
||||||
|
@JsonProperty("files")
|
||||||
private List<FileEntityResponse> files;
|
private List<FileEntityResponse> files;
|
||||||
private int totalCount;
|
|
||||||
private long totalSize;
|
@JsonProperty("total_count")
|
||||||
|
private Integer totalCount;
|
||||||
|
|
||||||
|
@JsonProperty("total_size")
|
||||||
|
private Long totalSize;
|
||||||
|
|
||||||
|
@JsonProperty("formatted_total_size")
|
||||||
private String formattedTotalSize;
|
private String formattedTotalSize;
|
||||||
private int page;
|
|
||||||
private int pageSize;
|
@JsonProperty("page")
|
||||||
|
private Integer page;
|
||||||
|
|
||||||
|
@JsonProperty("page_size")
|
||||||
|
private Integer pageSize;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package ru.soune.nocopy.dto.file;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class FileResponse {
|
||||||
|
|
||||||
|
private List<FileEntityResponse> files;
|
||||||
|
private int totalCount;
|
||||||
|
private long totalSize;
|
||||||
|
private String formattedTotalSize;
|
||||||
|
private int page;
|
||||||
|
private int pageSize;
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
package ru.soune.nocopy.dto.file;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@Builder
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class StorageUsageResponse {
|
||||||
|
@JsonProperty("user_id")
|
||||||
|
private Long userId;
|
||||||
|
|
||||||
|
@JsonProperty("storage_used")
|
||||||
|
private Long storageUsed;
|
||||||
|
|
||||||
|
@JsonProperty("formatted_storage_used")
|
||||||
|
private String formattedStorageUsed;
|
||||||
|
}
|
||||||
@@ -0,0 +1,292 @@
|
|||||||
|
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.*;
|
||||||
|
import ru.soune.nocopy.dto.file.*;
|
||||||
|
import ru.soune.nocopy.entity.AuthToken;
|
||||||
|
import ru.soune.nocopy.exception.NotFoundAuthToken;
|
||||||
|
import ru.soune.nocopy.repository.AuthTokenRepository;
|
||||||
|
import ru.soune.nocopy.service.file.FileEntityService;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class FileEntityHandler implements RequestHandler {
|
||||||
|
|
||||||
|
private final FileEntityService fileEntityService;
|
||||||
|
private final AuthTokenRepository authTokenRepository;
|
||||||
|
private final ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BaseResponse handle(BaseRequest request) {
|
||||||
|
try {
|
||||||
|
FileEntityRequest fileRequest = objectMapper.convertValue(
|
||||||
|
request.getMessageBody(), FileEntityRequest.class);
|
||||||
|
|
||||||
|
String action = fileRequest.getAction();
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case "get_file_info":
|
||||||
|
return handleGetFileInfo(request, fileRequest);
|
||||||
|
case "get_file_by_session":
|
||||||
|
return handleGetFileBySession(request, fileRequest);
|
||||||
|
case "get_user_files":
|
||||||
|
return handleGetUserFiles(request, fileRequest);
|
||||||
|
case "search_files":
|
||||||
|
return handleSearchFiles(request, fileRequest);
|
||||||
|
case "get_storage_usage":
|
||||||
|
return handleGetStorageUsage(request, fileRequest);
|
||||||
|
case "delete_file":
|
||||||
|
return handleDeleteFile(request, fileRequest);
|
||||||
|
default:
|
||||||
|
ActionResponse response = ActionResponse.builder()
|
||||||
|
.action(action)
|
||||||
|
.availableActions(Arrays.asList(
|
||||||
|
"get_file_info", "get_file_by_session", "get_user_files",
|
||||||
|
"search_files", "get_storage_usage", "delete_file"))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return new BaseResponse(request.getMsgId(),
|
||||||
|
MessageCode.INVALID_ACTION.getCode(),
|
||||||
|
"Invalid action: " + action,
|
||||||
|
response);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error in FileEntityHandler", e);
|
||||||
|
return new BaseResponse(request.getMsgId(),
|
||||||
|
MessageCode.FILE_UPLOAD_ERROR.getCode(),
|
||||||
|
"Handler error: " + e.getMessage(),
|
||||||
|
null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BaseResponse handleGetFileInfo(BaseRequest request, FileEntityRequest fileRequest) {
|
||||||
|
try {
|
||||||
|
Long userId = getUserIdFromToken(fileRequest.getToken());
|
||||||
|
FileEntityResponse fileInfo = fileEntityService.getById(fileRequest.getFileId());
|
||||||
|
|
||||||
|
if (!fileInfo.getUserId().equals(userId)) {
|
||||||
|
return new BaseResponse(request.getMsgId(),
|
||||||
|
MessageCode.ACCESS_DENIED.getCode(),
|
||||||
|
"Access denied",
|
||||||
|
null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new BaseResponse(request.getMsgId(),
|
||||||
|
MessageCode.SUCCESS.getCode(),
|
||||||
|
MessageCode.SUCCESS.getDescription(),
|
||||||
|
fileInfo);
|
||||||
|
|
||||||
|
} catch (NotFoundAuthToken e) {
|
||||||
|
return new BaseResponse(request.getMsgId(),
|
||||||
|
MessageCode.INVALID_TOKEN.getCode(),
|
||||||
|
"Authentication required",
|
||||||
|
null);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error getting file info", e);
|
||||||
|
return new BaseResponse(request.getMsgId(),
|
||||||
|
MessageCode.FILE_UPLOAD_ERROR.getCode(),
|
||||||
|
"Failed to get file info: " + e.getMessage(),
|
||||||
|
null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BaseResponse handleGetFileBySession(BaseRequest request, FileEntityRequest fileRequest) {
|
||||||
|
try {
|
||||||
|
Long userId = getUserIdFromToken(fileRequest.getToken());
|
||||||
|
FileEntityResponse fileInfo = fileEntityService.getByUploadSessionId(fileRequest.getUploadSessionId());
|
||||||
|
|
||||||
|
if (!fileInfo.getUserId().equals(userId)) {
|
||||||
|
return new BaseResponse(request.getMsgId(),
|
||||||
|
MessageCode.ACCESS_DENIED.getCode(),
|
||||||
|
"Access denied",
|
||||||
|
null);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new BaseResponse(request.getMsgId(),
|
||||||
|
MessageCode.SUCCESS.getCode(),
|
||||||
|
MessageCode.SUCCESS.getDescription(),
|
||||||
|
fileInfo);
|
||||||
|
|
||||||
|
} catch (NotFoundAuthToken e) {
|
||||||
|
return new BaseResponse(request.getMsgId(),
|
||||||
|
MessageCode.INVALID_TOKEN.getCode(),
|
||||||
|
"Authentication required",
|
||||||
|
null);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error getting file by session", e);
|
||||||
|
return new BaseResponse(request.getMsgId(),
|
||||||
|
MessageCode.FILE_UPLOAD_ERROR.getCode(),
|
||||||
|
"Failed to get file: " + e.getMessage(),
|
||||||
|
null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BaseResponse handleGetUserFiles(BaseRequest request, FileEntityRequest fileRequest) {
|
||||||
|
try {
|
||||||
|
Long userId = getUserIdFromToken(fileRequest.getToken());
|
||||||
|
int page = fileRequest.getPage() != null ? fileRequest.getPage() : 1;
|
||||||
|
int pageSize = fileRequest.getPageSize() != null ? fileRequest.getPageSize() : 20;
|
||||||
|
|
||||||
|
FileResponse files = fileEntityService.getUserFiles(userId, page, pageSize);
|
||||||
|
|
||||||
|
return new BaseResponse(request.getMsgId(),
|
||||||
|
MessageCode.SUCCESS.getCode(),
|
||||||
|
MessageCode.SUCCESS.getDescription(),
|
||||||
|
files);
|
||||||
|
|
||||||
|
} catch (NotFoundAuthToken e) {
|
||||||
|
return new BaseResponse(request.getMsgId(),
|
||||||
|
MessageCode.INVALID_TOKEN.getCode(),
|
||||||
|
"Authentication required",
|
||||||
|
null);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error getting user files", e);
|
||||||
|
return new BaseResponse(request.getMsgId(),
|
||||||
|
MessageCode.FILE_UPLOAD_ERROR.getCode(),
|
||||||
|
"Failed to get files: " + e.getMessage(),
|
||||||
|
null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BaseResponse handleSearchFiles(BaseRequest request, FileEntityRequest fileRequest) {
|
||||||
|
try {
|
||||||
|
Long userId = getUserIdFromToken(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
FileResponse allFiles = fileEntityService.getUserFiles(userId, 1, 1000);
|
||||||
|
|
||||||
|
var filteredFiles = allFiles.getFiles().stream()
|
||||||
|
.filter(f -> f.getOriginalFileName().toLowerCase().contains(fileRequest.getQuery().toLowerCase()))
|
||||||
|
.toList();
|
||||||
|
|
||||||
|
int start = (page - 1) * pageSize;
|
||||||
|
int end = Math.min(start + pageSize, filteredFiles.size());
|
||||||
|
|
||||||
|
FileListResponse response = FileListResponse.builder()
|
||||||
|
.files(filteredFiles.subList(start, Math.min(end, filteredFiles.size())))
|
||||||
|
.totalCount(filteredFiles.size())
|
||||||
|
.totalSize(allFiles.getTotalSize())
|
||||||
|
.formattedTotalSize(allFiles.getFormattedTotalSize())
|
||||||
|
.page(page)
|
||||||
|
.pageSize(pageSize)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return new BaseResponse(request.getMsgId(),
|
||||||
|
MessageCode.SUCCESS.getCode(),
|
||||||
|
MessageCode.SUCCESS.getDescription(),
|
||||||
|
response);
|
||||||
|
|
||||||
|
} catch (NotFoundAuthToken e) {
|
||||||
|
return new BaseResponse(request.getMsgId(),
|
||||||
|
MessageCode.INVALID_TOKEN.getCode(),
|
||||||
|
"Authentication required",
|
||||||
|
null);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error searching files", e);
|
||||||
|
return new BaseResponse(request.getMsgId(),
|
||||||
|
MessageCode.FILE_UPLOAD_ERROR.getCode(),
|
||||||
|
"Failed to search files: " + e.getMessage(),
|
||||||
|
null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BaseResponse handleGetStorageUsage(BaseRequest request, FileEntityRequest fileRequest) {
|
||||||
|
try {
|
||||||
|
Long userId = getUserIdFromToken(fileRequest.getToken());
|
||||||
|
long usage = fileEntityService.getUserStorageUsed(userId);
|
||||||
|
|
||||||
|
StorageUsageResponse response = StorageUsageResponse.builder()
|
||||||
|
.userId(userId)
|
||||||
|
.storageUsed(usage)
|
||||||
|
.formattedStorageUsed(formatFileSize(usage))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return new BaseResponse(request.getMsgId(),
|
||||||
|
MessageCode.SUCCESS.getCode(),
|
||||||
|
MessageCode.SUCCESS.getDescription(),
|
||||||
|
response);
|
||||||
|
|
||||||
|
} catch (NotFoundAuthToken e) {
|
||||||
|
return new BaseResponse(request.getMsgId(),
|
||||||
|
MessageCode.INVALID_TOKEN.getCode(),
|
||||||
|
"Authentication required",
|
||||||
|
null);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error getting storage usage", e);
|
||||||
|
return new BaseResponse(request.getMsgId(),
|
||||||
|
MessageCode.FILE_UPLOAD_ERROR.getCode(),
|
||||||
|
"Failed to get storage usage: " + e.getMessage(),
|
||||||
|
null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private BaseResponse handleDeleteFile(BaseRequest request, FileEntityRequest fileRequest) {
|
||||||
|
try {
|
||||||
|
Long userId = getUserIdFromToken(fileRequest.getToken());
|
||||||
|
FileEntityResponse fileInfo = fileEntityService.getById(fileRequest.getFileId());
|
||||||
|
|
||||||
|
if (!fileInfo.getUserId().equals(userId)) {
|
||||||
|
return new BaseResponse(request.getMsgId(),
|
||||||
|
MessageCode.ACCESS_DENIED.getCode(),
|
||||||
|
"Access denied",
|
||||||
|
null);
|
||||||
|
}
|
||||||
|
|
||||||
|
fileEntityService.markAsDeleted(fileRequest.getFileId());
|
||||||
|
|
||||||
|
DeleteFileResponse response = DeleteFileResponse.builder()
|
||||||
|
.fileId(fileRequest.getFileId())
|
||||||
|
.message("File marked as deleted")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
return new BaseResponse(request.getMsgId(),
|
||||||
|
MessageCode.SUCCESS.getCode(),
|
||||||
|
"File marked as deleted",
|
||||||
|
response);
|
||||||
|
|
||||||
|
} catch (NotFoundAuthToken e) {
|
||||||
|
return new BaseResponse(request.getMsgId(),
|
||||||
|
MessageCode.INVALID_TOKEN.getCode(),
|
||||||
|
"Authentication required",
|
||||||
|
null);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Error deleting file", e);
|
||||||
|
return new BaseResponse(request.getMsgId(),
|
||||||
|
MessageCode.FILE_UPLOAD_ERROR.getCode(),
|
||||||
|
"Failed to delete file: " + e.getMessage(),
|
||||||
|
null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Long getUserIdFromToken(String token) {
|
||||||
|
if (token == null || token.isBlank()) {
|
||||||
|
throw new NotFoundAuthToken("Token is required");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (token.startsWith("Bearer ")) {
|
||||||
|
token = token.replace("Bearer ", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
AuthToken authToken = authTokenRepository.findByToken(token)
|
||||||
|
.orElseThrow(() -> new NotFoundAuthToken("Token not found"));
|
||||||
|
return authToken.getUser().getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String formatFileSize(long size) {
|
||||||
|
if (size < 1024) return size + " B";
|
||||||
|
int exp = (int) (Math.log(size) / Math.log(1024));
|
||||||
|
String pre = "KMGTPE".charAt(exp-1) + "";
|
||||||
|
return String.format("%.1f %sB", size / Math.pow(1024, exp), pre);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,7 +5,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import ru.soune.nocopy.dto.file.FileEntityResponse;
|
import ru.soune.nocopy.dto.file.FileEntityResponse;
|
||||||
import ru.soune.nocopy.dto.file.FileListResponse;
|
import ru.soune.nocopy.dto.file.FileResponse;
|
||||||
import ru.soune.nocopy.entity.file.FileEntity;
|
import ru.soune.nocopy.entity.file.FileEntity;
|
||||||
import ru.soune.nocopy.entity.file.FileStatus;
|
import ru.soune.nocopy.entity.file.FileStatus;
|
||||||
import ru.soune.nocopy.entity.file.FileUploadSession;
|
import ru.soune.nocopy.entity.file.FileUploadSession;
|
||||||
@@ -27,9 +27,6 @@ public class FileEntityService {
|
|||||||
|
|
||||||
private final FileEntityRepository fileEntityRepository;
|
private final FileEntityRepository fileEntityRepository;
|
||||||
|
|
||||||
/**
|
|
||||||
* Создает FileEntity на основе завершенной сессии загрузки
|
|
||||||
*/
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public FileEntity createFromUploadSession(FileUploadSession session, String checksum) {
|
public FileEntity createFromUploadSession(FileUploadSession session, String checksum) {
|
||||||
log.info("Creating FileEntity for upload session: {}", session.getUploadId());
|
log.info("Creating FileEntity for upload session: {}", session.getUploadId());
|
||||||
@@ -72,9 +69,7 @@ public class FileEntityService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Извлекает расширение файла из имени
|
|
||||||
*/
|
|
||||||
private String extractFileExtension(String fileName) {
|
private String extractFileExtension(String fileName) {
|
||||||
int dotIndex = fileName.lastIndexOf('.');
|
int dotIndex = fileName.lastIndexOf('.');
|
||||||
if (dotIndex > 0 && dotIndex < fileName.length() - 1) {
|
if (dotIndex > 0 && dotIndex < fileName.length() - 1) {
|
||||||
@@ -83,9 +78,6 @@ public class FileEntityService {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Получает FileEntity по ID
|
|
||||||
*/
|
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public FileEntityResponse getById(String fileId) {
|
public FileEntityResponse getById(String fileId) {
|
||||||
FileEntity fileEntity = fileEntityRepository.findById(fileId)
|
FileEntity fileEntity = fileEntityRepository.findById(fileId)
|
||||||
@@ -94,9 +86,6 @@ public class FileEntityService {
|
|||||||
return convertToResponse(fileEntity);
|
return convertToResponse(fileEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Получает FileEntity по ID сессии загрузки
|
|
||||||
*/
|
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public FileEntityResponse getByUploadSessionId(String uploadSessionId) {
|
public FileEntityResponse getByUploadSessionId(String uploadSessionId) {
|
||||||
FileEntity fileEntity = fileEntityRepository.findByUploadSessionId(uploadSessionId)
|
FileEntity fileEntity = fileEntityRepository.findByUploadSessionId(uploadSessionId)
|
||||||
@@ -106,9 +95,6 @@ public class FileEntityService {
|
|||||||
return convertToResponse(fileEntity);
|
return convertToResponse(fileEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Получает FileEntity по пути файла
|
|
||||||
*/
|
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public FileEntityResponse getByFilePath(String filePath) {
|
public FileEntityResponse getByFilePath(String filePath) {
|
||||||
FileEntity fileEntity = fileEntityRepository.findByFilePath(filePath)
|
FileEntity fileEntity = fileEntityRepository.findByFilePath(filePath)
|
||||||
@@ -117,11 +103,9 @@ public class FileEntityService {
|
|||||||
return convertToResponse(fileEntity);
|
return convertToResponse(fileEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Получает все файлы пользователя
|
|
||||||
*/
|
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public FileListResponse getAllUserFiles(Long userId) {
|
public FileResponse getAllUserFiles(Long userId) {
|
||||||
List<FileEntity> fileEntities = fileEntityRepository.findByUserIdAndStatus(
|
List<FileEntity> fileEntities = fileEntityRepository.findByUserIdAndStatus(
|
||||||
userId, FileStatus.ACTIVE);
|
userId, FileStatus.ACTIVE);
|
||||||
|
|
||||||
@@ -133,7 +117,7 @@ public class FileEntityService {
|
|||||||
.mapToLong(FileEntity::getFileSize)
|
.mapToLong(FileEntity::getFileSize)
|
||||||
.sum();
|
.sum();
|
||||||
|
|
||||||
return FileListResponse.builder()
|
return FileResponse.builder()
|
||||||
.files(files)
|
.files(files)
|
||||||
.totalCount(files.size())
|
.totalCount(files.size())
|
||||||
.totalSize(totalSize)
|
.totalSize(totalSize)
|
||||||
@@ -143,11 +127,9 @@ public class FileEntityService {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Получает файлы пользователя с пагинацией
|
|
||||||
*/
|
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public FileListResponse getUserFiles(Long userId, int page, int pageSize) {
|
public FileResponse getUserFiles(Long userId, int page, int pageSize) {
|
||||||
List<FileEntity> allFiles = fileEntityRepository.findByUserIdAndStatus(
|
List<FileEntity> allFiles = fileEntityRepository.findByUserIdAndStatus(
|
||||||
userId, FileStatus.ACTIVE);
|
userId, FileStatus.ACTIVE);
|
||||||
|
|
||||||
@@ -155,7 +137,7 @@ public class FileEntityService {
|
|||||||
int end = Math.min(start + pageSize, allFiles.size());
|
int end = Math.min(start + pageSize, allFiles.size());
|
||||||
|
|
||||||
if (start >= allFiles.size()) {
|
if (start >= allFiles.size()) {
|
||||||
return FileListResponse.builder()
|
return FileResponse.builder()
|
||||||
.files(List.of())
|
.files(List.of())
|
||||||
.totalCount(allFiles.size())
|
.totalCount(allFiles.size())
|
||||||
.totalSize(0)
|
.totalSize(0)
|
||||||
@@ -175,7 +157,7 @@ public class FileEntityService {
|
|||||||
.mapToLong(FileEntity::getFileSize)
|
.mapToLong(FileEntity::getFileSize)
|
||||||
.sum();
|
.sum();
|
||||||
|
|
||||||
return FileListResponse.builder()
|
return FileResponse.builder()
|
||||||
.files(files)
|
.files(files)
|
||||||
.totalCount(allFiles.size())
|
.totalCount(allFiles.size())
|
||||||
.totalSize(totalSize)
|
.totalSize(totalSize)
|
||||||
@@ -185,9 +167,6 @@ public class FileEntityService {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Помечает файл как удаленный (мягкое удаление)
|
|
||||||
*/
|
|
||||||
@Transactional
|
@Transactional
|
||||||
public void markAsDeleted(String fileId) {
|
public void markAsDeleted(String fileId) {
|
||||||
FileEntity fileEntity = fileEntityRepository.findById(fileId)
|
FileEntity fileEntity = fileEntityRepository.findById(fileId)
|
||||||
@@ -200,18 +179,12 @@ public class FileEntityService {
|
|||||||
log.info("FileEntity marked as deleted: {}", fileId);
|
log.info("FileEntity marked as deleted: {}", fileId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Получает общий размер файлов пользователя
|
|
||||||
*/
|
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public long getUserStorageUsed(Long userId) {
|
public long getUserStorageUsed(Long userId) {
|
||||||
Long totalSize = fileEntityRepository.getTotalSizeByUserId(userId);
|
Long totalSize = fileEntityRepository.getTotalSizeByUserId(userId);
|
||||||
return totalSize != null ? totalSize : 0L;
|
return totalSize != null ? totalSize : 0L;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Поиск файлов пользователя по имени
|
|
||||||
*/
|
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public List<FileEntityResponse> searchFiles(Long userId, String query) {
|
public List<FileEntityResponse> searchFiles(Long userId, String query) {
|
||||||
List<FileEntity> files = fileEntityRepository.searchByFileName(userId, query);
|
List<FileEntity> files = fileEntityRepository.searchByFileName(userId, query);
|
||||||
@@ -222,9 +195,6 @@ public class FileEntityService {
|
|||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Проверяет, существует ли файл на диске
|
|
||||||
*/
|
|
||||||
private boolean checkFileExistsOnDisk(String filePath) {
|
private boolean checkFileExistsOnDisk(String filePath) {
|
||||||
try {
|
try {
|
||||||
return Files.exists(Paths.get(filePath));
|
return Files.exists(Paths.get(filePath));
|
||||||
@@ -234,9 +204,6 @@ public class FileEntityService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Конвертирует FileEntity в DTO
|
|
||||||
*/
|
|
||||||
private FileEntityResponse convertToResponse(FileEntity fileEntity) {
|
private FileEntityResponse convertToResponse(FileEntity fileEntity) {
|
||||||
boolean existsOnDisk = checkFileExistsOnDisk(fileEntity.getFilePath());
|
boolean existsOnDisk = checkFileExistsOnDisk(fileEntity.getFilePath());
|
||||||
|
|
||||||
@@ -260,9 +227,6 @@ public class FileEntityService {
|
|||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Форматирует размер файла в читаемый вид
|
|
||||||
*/
|
|
||||||
private String formatFileSize(long size) {
|
private String formatFileSize(long size) {
|
||||||
if (size < 1024) {
|
if (size < 1024) {
|
||||||
return size + " B";
|
return size + " B";
|
||||||
|
|||||||
Reference in New Issue
Block a user