Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
131 changes: 104 additions & 27 deletions backend/src/main/java/cloudpage/controller/FileController.java
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
package cloudpage.controller;

import cloudpage.dto.FileDto;
import cloudpage.model.File;
import cloudpage.repository.FileRepository;
import cloudpage.service.FileService;
import cloudpage.service.FolderService;
import cloudpage.service.UserService;
import lombok.RequiredArgsConstructor;

import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
Expand All @@ -15,6 +23,8 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;

@RestController
@RequiredArgsConstructor
Expand All @@ -24,6 +34,7 @@ public class FileController {
private final FileService fileService;
private final UserService userService;
private final FolderService folderService;
private final FileRepository fileRepository;

@PostMapping("/upload")
public void uploadFile(@RequestParam String folderPath, @RequestParam MultipartFile file) throws IOException {
Expand All @@ -32,7 +43,29 @@ public void uploadFile(@RequestParam String folderPath, @RequestParam MultipartF
}

@GetMapping("/content")
public ResponseEntity<String> getFileContent(@RequestParam String path) throws IOException {
public ResponseEntity<?> getFileContent(
@RequestParam(required = false) String path,
@RequestParam(defaultValue = "0") int pageNumber,
@RequestParam(defaultValue = "10") int pageSize) throws IOException {

// If path is null or empty, treat as listing directory/files
if (path == null || path.isEmpty()) {
Pageable pageable = PageRequest.of(pageNumber, pageSize, Sort.by("fileId").descending());
Page<File> filePage = fileRepository.findAllFiles(pageable);

Map<String, Object> response = new HashMap<>();
response.put("message", "File(s) retrieved successfully");
response.put("status", "success");
response.put("data", filePage.getContent());
response.put("totalFiles", filePage.getTotalElements());
response.put("totalPages", filePage.getTotalPages());
response.put("currentPage", filePage.getNumber());
response.put("code", 200);

return ResponseEntity.ok(response);
}

// Otherwise, treat as a request for a single file's content
var user = userService.getCurrentUser();
Path fullPath = Paths.get(user.getRootFolderPath(), path).normalize();
folderService.validatePath(user.getRootFolderPath(), fullPath);
Expand All @@ -42,8 +75,14 @@ public ResponseEntity<String> getFileContent(@RequestParam String path) throws I
}

String content = fileService.readFileContent(user.getRootFolderPath(), path);
return ResponseEntity.ok(content);
}
return ResponseEntity.ok(Map.of(
"message", "File content retrieved successfully",
"status", "success",
"data", content,
"code", 200
));
}


@DeleteMapping
public void deleteFile(@RequestParam String filePath) throws IOException {
Expand All @@ -57,35 +96,73 @@ public void renameOrMoveFile(@RequestParam String filePath, @RequestParam String
fileService.renameOrMoveFile(user.getRootFolderPath(), filePath, newPath);
}

@GetMapping("/download")
public ResponseEntity<Resource> downloadFile(@RequestParam String path) throws IOException {
var user = userService.getCurrentUser();
Path fullPath = Paths.get(user.getRootFolderPath(), path).normalize();
folderService.validatePath(user.getRootFolderPath(), fullPath); // ensure security
Resource resource = new UrlResource(fullPath.toUri());
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fullPath.getFileName() + "\"")
.body(resource);
}
@GetMapping("/download")
public ResponseEntity<?> listFilesForDownload(
@RequestParam(required = false) String path,
@RequestParam(defaultValue = "0") int pageNumber,
@RequestParam(defaultValue = "10") int pageSize,
@RequestParam(required = false) String sort) {

@GetMapping("/view")
public ResponseEntity<Resource> viewFile(@RequestParam String path) throws IOException {
var user = userService.getCurrentUser();
Path fullPath = Paths.get(user.getRootFolderPath(), path).normalize();
folderService.validatePath(user.getRootFolderPath(), fullPath);
Pageable pageable;
if (sort != null && !sort.isEmpty()) {
pageable = PageRequest.of(pageNumber, pageSize, Sort.by(sort));
} else {
pageable = PageRequest.of(pageNumber, pageSize, Sort.by("fileId").descending());
}

if (!fullPath.toFile().exists() || !fullPath.toFile().isFile()) {
throw new IllegalArgumentException("File does not exist: " + fullPath);
Page<File> filePage;

if (path == null || path.isEmpty()) {
filePage = fileRepository.findAllFiles(pageable);
} else {
filePage = fileRepository.searchAllFiles(pageable, path.toUpperCase());
}

Resource resource = new UrlResource(fullPath.toUri());
String mimeType = Files.probeContentType(fullPath);
if (mimeType == null) {
mimeType = "application/octet-stream";
Map<String, Object> response = new HashMap<>();
response.put("message", "File(s) available for download");
response.put("status", "success");
response.put("data", filePage.getContent());
response.put("totalFiles", filePage.getTotalElements());
response.put("totalPages", filePage.getTotalPages());
response.put("currentPage", filePage.getNumber());
response.put("code", 200);

return ResponseEntity.ok(response);
}


@GetMapping("/view")
public ResponseEntity<?> listFilesForView(
@RequestParam(required = false) String path,
@RequestParam(defaultValue = "0") int pageNumber,
@RequestParam(defaultValue = "10") int pageSize,
@RequestParam(required = false) String sort) {

Pageable pageable;
if (sort != null && !sort.isEmpty()) {
pageable = PageRequest.of(pageNumber, pageSize, Sort.by(sort));
} else {
pageable = PageRequest.of(pageNumber, pageSize, Sort.by("fileId").descending());
}

Page<File> filePage;

if (path == null || path.isEmpty()) {
filePage = fileRepository.findAllFiles(pageable);
} else {
filePage = fileRepository.searchAllFiles(pageable, path.toUpperCase());
}

return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_TYPE, mimeType)
.body(resource);
Map<String, Object> response = new HashMap<>();
response.put("message", "File(s) available for viewing");
response.put("status", "success");
response.put("data", filePage.getContent());
response.put("totalFiles", filePage.getTotalElements());
response.put("totalPages", filePage.getTotalPages());
response.put("currentPage", filePage.getNumber());
response.put("code", 200);

return ResponseEntity.ok(response);
}

}
28 changes: 28 additions & 0 deletions backend/src/main/java/cloudpage/model/File.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package cloudpage.model;

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@Entity
@AllArgsConstructor
@Table(name = "files")
public class File {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

private String name;
private String path;
private Long size;
private String mimeType;
}



21 changes: 21 additions & 0 deletions backend/src/main/java/cloudpage/repository/FileRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package cloudpage.repository;

import org.hibernate.cache.spi.support.AbstractReadWriteAccess.Item;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

import cloudpage.model.File;

@Repository
public interface FileRepository extends JpaRepository<File, Long>{

@Query("select f from File f")
Page<File> findAllFiles(Pageable pageable);

@Query("select fi from File fi where fi.name like %:path%")
Page<File> searchAllFiles(Pageable pageable, String path);

}
2 changes: 1 addition & 1 deletion backend/src/main/resources/application.properties
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ spring.application.name=backend
server.port=8090
# PostgreSQL DB Connection
spring.datasource.username=postgres
spring.datasource.password=root
spring.datasource.password=12345
spring.datasource.url=jdbc:postgresql://localhost:5432/cloud-db
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
Expand Down