Skip to content
Extraits de code Groupes Projets
Valider 60d94cc5 rédigé par Mohamed Lemine BAILLAHI's avatar Mohamed Lemine BAILLAHI
Parcourir les fichiers

Merge branch 'feature/VSN-974' into 'develop'

feature/VSN-974 - implement folder storage quota feature

Closes VSN-974

See merge request !18
parents 0ba63cd1 ff492e0b
Branches
Étiquettes v0.0.9
1 requête de fusion!18feature/VSN-974 - implement folder storage quota feature
Pipeline #18020 réussi avec l'étape
in 18 secondes
......@@ -15,6 +15,7 @@
- Cancel folder sharing
- Zip/Compress folder implementation
- Implement Folder or Document Download feature
- implement folder storage quota feature
## [1.0.0]
- Create vsn-document-service
- Add Aws S3 config to the microservice
......
......@@ -20,4 +20,5 @@ public class Paths {
public static final String FOLDER_SHARE = "/share";
public static final String FOLDER_CANCEL_SHARE = "/{folderId}/unshare/{userId}";
public static final String FOLDER_ZIP = "/zip/{folderId}";
public static final String FOLDER_SIZE = "/size/{folderId}";
}
......@@ -7,6 +7,7 @@ import com.marketingconfort.adanev.vsn.document.dtos.FolderDTO;
import com.marketingconfort.adanev.vsn.document.dtos.requests.NewFolderRequest;
import com.marketingconfort.adanev.vsn.document.dtos.requests.ShareFolderRequest;
import com.marketingconfort.adanev.vsn.document.dtos.response.FolderDetailsResponse;
import com.marketingconfort.adanev.vsn.document.dtos.response.FolderSizeResponseDTO;
import com.marketingconfort.adanev.vsn.document.services.FolderService;
import com.marketingconfort.starter.core.exceptions.FunctionalException;
import com.marketingconfort.starter.core.exceptions.S3FunctionalException;
......@@ -133,4 +134,10 @@ public class FolderController {
}
}
@GetMapping(Paths.FOLDER_SIZE)
public ResponseEntity<FolderSizeResponseDTO> getFolderSize(@PathVariable Long folderId) throws FunctionalException {
FolderSizeResponseDTO response = folderService.calculateFolderSize(folderId);
return ResponseEntity.ok(response);
}
}
package com.marketingconfort.adanev.vsn.document.dtos.response;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class FolderSizeResponseDTO {
private Long folderId;
private String folderName;
private Long totalSizeBytes;
private String formattedSize;
}
package com.marketingconfort.adanev.vsn.document.repositories;
import com.marketingconfort.adanev.vsn.document.dtos.FolderDTO;
import com.marketingconfort.adanev.vsn.document.models.Folder;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.repository.JpaRepository;
......@@ -25,6 +26,12 @@ public interface FolderRepository extends JpaRepository<Folder, Long>, JpaSpecif
Optional<Folder> findByNameAndOwnerId(String name, Long ownerId);
@Query("SELECT f FROM Folder f " +
"LEFT JOIN FETCH f.documents " +
"LEFT JOIN FETCH f.subFolders " +
"WHERE f.id = :folderId")
Optional<FolderDTO> findByIdWithDocumentsAndSubfolders(@Param("folderId") Long folderId);
......
......@@ -5,6 +5,7 @@ import com.marketingconfort.adanev.vsn.document.dtos.FolderDTO;
import com.marketingconfort.adanev.vsn.document.dtos.requests.NewFolderRequest;
import com.marketingconfort.adanev.vsn.document.dtos.requests.ShareFolderRequest;
import com.marketingconfort.adanev.vsn.document.dtos.response.FolderDetailsResponse;
import com.marketingconfort.adanev.vsn.document.dtos.response.FolderSizeResponseDTO;
import com.marketingconfort.starter.core.exceptions.FunctionalException;
import org.springframework.data.domain.Page;
import org.springframework.http.ResponseEntity;
......@@ -27,4 +28,5 @@ public interface FolderService {
void unshareFolderWithUser(Long folderId, Long userId) throws FunctionalException;
byte[] zipFolderAndReturn(Long folderId) throws FunctionalException;
ResponseEntity<byte[]> downloadZippedFolder(Long folderId) throws FunctionalException;
FolderSizeResponseDTO calculateFolderSize(Long folderId) throws FunctionalException;
}
......@@ -6,6 +6,7 @@ import com.marketingconfort.adanev.vsn.document.dtos.FolderDTO;
import com.marketingconfort.adanev.vsn.document.dtos.requests.NewFolderRequest;
import com.marketingconfort.adanev.vsn.document.dtos.requests.ShareFolderRequest;
import com.marketingconfort.adanev.vsn.document.dtos.response.FolderDetailsResponse;
import com.marketingconfort.adanev.vsn.document.dtos.response.FolderSizeResponseDTO;
import com.marketingconfort.adanev.vsn.document.mappers.DocumentMapper;
import com.marketingconfort.adanev.vsn.document.mappers.FolderMapper;
import com.marketingconfort.adanev.vsn.document.models.Document;
......@@ -13,6 +14,7 @@ import com.marketingconfort.adanev.vsn.document.models.Folder;
import com.marketingconfort.adanev.vsn.document.repositories.DocumentRepository;
import com.marketingconfort.adanev.vsn.document.repositories.FolderRepository;
import com.marketingconfort.adanev.vsn.document.services.FolderService;
import com.marketingconfort.adanev.vsn.document.utils.FolderSizeCalculator;
import com.marketingconfort.adanev.vsn.document.utils.FolderUtils;
import com.marketingconfort.starter.core.exceptions.FunctionalException;
import jakarta.persistence.criteria.Join;
......@@ -353,6 +355,21 @@ public class FolderServiceImpl implements FolderService {
.body(zipBytes);
}
@Override
public FolderSizeResponseDTO calculateFolderSize(Long folderId) throws FunctionalException {
Folder folder = folderRepository.findById(folderId)
.orElseThrow(() -> new FunctionalException(MessageConstants.FOLDER_NOT_FOUND));
long totalSizeBytes = FolderSizeCalculator.calculateFolderSize(FolderMapper.toDto(folder));
String formattedSize = FolderSizeCalculator.formatBytes(totalSizeBytes);
return FolderSizeResponseDTO.builder()
.folderId(folderId)
.folderName(folder.getName())
.totalSizeBytes(totalSizeBytes)
.formattedSize(formattedSize)
.build();
}
//helpers
private boolean isDescendant(Folder folder, Folder targetParent) {
......
package com.marketingconfort.adanev.vsn.document.utils;
import com.marketingconfort.adanev.vsn.document.dtos.DocumentDTO;
import com.marketingconfort.adanev.vsn.document.dtos.FolderDTO;
public class FolderSizeCalculator {
public static long calculateFolderSize(FolderDTO folder) {
if (folder == null) {
return 0L;
}
long totalSize = 0L;
// Sum up sizes of all documents in this folder
if (folder.getDocuments() != null) {
for (DocumentDTO document : folder.getDocuments()) {
if (document != null && document.getSize() != null) {
totalSize += document.getSize();
}
}
}
// Recursively calculate sizes of all subfolders
if (folder.getSubFolders() != null) {
for (FolderDTO subFolder : folder.getSubFolders()) {
totalSize += calculateFolderSize(subFolder);
}
}
return totalSize;
}
//size of a folder and returns it in a human-readable format("1.5 MB", "2.3 GB")
public static String calculateFolderSizeFormatted(FolderDTO folder) {
long sizeInBytes = calculateFolderSize(folder);
return formatBytes(sizeInBytes);
}
public static String formatBytes(long bytes) {
if (bytes < 0) {
return "0 B";
}
String[] units = {"B", "KB", "MB", "GB", "TB", "PB"};
int unitIndex = 0;
double size = bytes;
while (size >= 1024 && unitIndex < units.length - 1) {
size /= 1024;
unitIndex++;
}
if (unitIndex == 0) {
return String.format("%.0f %s", size, units[unitIndex]);
} else {
return String.format("%.1f %s", size, units[unitIndex]);
}
}
public static int countFilesInFolder(FolderDTO folder) {
if (folder == null) {
return 0;
}
int fileCount = 0;
// Count documents in this folder
if (folder.getDocuments() != null) {
fileCount += folder.getDocuments().size();
}
// Recursively count files in subfolders
if (folder.getSubFolders() != null) {
for (FolderDTO subFolder : folder.getSubFolders()) {
fileCount += countFilesInFolder(subFolder);
}
}
return fileCount;
}
public static int countSubfoldersInFolder(FolderDTO folder) {
if (folder == null || folder.getSubFolders() == null) {
return 0;
}
int subfolderCount = folder.getSubFolders().size();
// Recursively count subfolders in each subfolder
for (FolderDTO subFolder : folder.getSubFolders()) {
subfolderCount += countSubfoldersInFolder(subFolder);
}
return subfolderCount;
}
}
0% ou .
You are about to add 0 people to the discussion. Proceed with caution.
Terminez d'abord l'édition de ce message.
Veuillez vous inscrire ou vous pour commenter