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

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

feature/VSN-1122 - Add documents statistics implementation

Closes VSN-1122

See merge request !26
parents e8c8a340 f3d61a34
Branches
Étiquettes v0.0.16
1 requête de fusion!26feature/VSN-1122 - Add documents statistics implementation
Pipeline #18330 réussi avec l'étape
in 19 secondes
......@@ -17,6 +17,7 @@
- Create document/Upload new Document/s3 docs upload: implementations
- Add root documents to storage quota counting
- Document listing implementations
- Add documents statistics implementation
## [0.0.9]
-
## [0.0.8]
......
......@@ -22,4 +22,6 @@ public class MessageConstants {
public static final String SUCCESSFUL_UPLOAD = "Document uploaded successfully.";
public static final String DUPLICATE_NAME = "A document with the same name already exists in the target folder.";
public static final String DOCUMENT_NOT_FOUND = "Document Not Found";
public static final String UNAUTHORIZED_FOLDER_ACCESS = "The folder does not belong to the specified user.";
}
......@@ -43,5 +43,7 @@ public class Paths {
public static final String USER_DOCUMENTS = "/all";
public static final String DOCUMENT_DETAILS = "/details";
public static final String ROOT_DOCUMENTS = "/root";
public static final String DOCUMENT_STATS = "/stats";
}
......@@ -3,6 +3,7 @@ package com.marketingconfort.adanev.vsn.document.controller;
import com.marketingconfort.adanev.vsn.document.constants.MessageConstants;
import com.marketingconfort.adanev.vsn.document.constants.paths.Paths;
import com.marketingconfort.adanev.vsn.document.dtos.DocumentDTO;
import com.marketingconfort.adanev.vsn.document.dtos.DocumentStatisticsDTO;
import com.marketingconfort.adanev.vsn.document.dtos.requests.AddDocumentRequest;
import com.marketingconfort.adanev.vsn.document.services.DocumentService;
import com.marketingconfort.starter.core.exceptions.FunctionalException;
......@@ -58,4 +59,10 @@ public class DocumentController {
public ResponseEntity<List<DocumentDTO>> getRootDocuments(@RequestParam Long ownerId) {
return ResponseEntity.ok(documentService.getRootDocumentsByOwnerId(ownerId));
}
@GetMapping(Paths.DOCUMENT_STATS)
public ResponseEntity<List<DocumentStatisticsDTO>> getDocumentStats(@RequestParam Long ownerId) {
List<DocumentStatisticsDTO> stats = documentService.getDocumentStatistics(ownerId);
return ResponseEntity.ok(stats);
}
}
package com.marketingconfort.adanev.vsn.document.dtos;
import com.marketingconfort.adanev.vsn.document.enums.DocumentType;
import lombok.Builder;
import lombok.Data;
@Data
@Builder
public class DocumentStatisticsDTO {
private DocumentType documentType;
private long documentCount;
private long totalSizeBytes;
private String totalSizeFormatted;
private String averageSizeFormatted;
}
package com.marketingconfort.adanev.vsn.document.services;
import com.marketingconfort.adanev.vsn.document.dtos.DocumentDTO;
import com.marketingconfort.adanev.vsn.document.dtos.DocumentStatisticsDTO;
import com.marketingconfort.adanev.vsn.document.dtos.requests.AddDocumentRequest;
import com.marketingconfort.adanev.vsn.document.dtos.response.DocumentUploadResponseDTO;
import com.marketingconfort.starter.core.exceptions.FunctionalException;
......@@ -20,4 +21,5 @@ public interface DocumentService {
DocumentDTO getDocumentByIdAndOwner(Long documentId, Long ownerId) throws FunctionalException;
List<DocumentDTO> getRootDocumentsByOwnerId(Long ownerId);
List<DocumentStatisticsDTO> getDocumentStatistics(Long ownerId);
}
......@@ -3,7 +3,9 @@ package com.marketingconfort.adanev.vsn.document.services.Implementations;
import com.marketingconfort.adanev.vsn.document.config.EnvConfigLoader;
import com.marketingconfort.adanev.vsn.document.constants.MessageConstants;
import com.marketingconfort.adanev.vsn.document.dtos.DocumentDTO;
import com.marketingconfort.adanev.vsn.document.dtos.DocumentStatisticsDTO;
import com.marketingconfort.adanev.vsn.document.dtos.requests.AddDocumentRequest;
import com.marketingconfort.adanev.vsn.document.enums.DocumentType;
import com.marketingconfort.adanev.vsn.document.mappers.DocumentMapper;
import com.marketingconfort.adanev.vsn.document.models.Document;
import com.marketingconfort.adanev.vsn.document.enums.ContentType;
......@@ -13,6 +15,7 @@ import com.marketingconfort.adanev.vsn.document.repositories.FolderRepository;
import com.marketingconfort.adanev.vsn.document.services.DocumentService;
import com.marketingconfort.adanev.vsn.document.services.StorageQuotaService;
import com.marketingconfort.adanev.vsn.document.utils.DocumentUtils;
import com.marketingconfort.adanev.vsn.document.utils.FolderSizeCalculator;
import com.marketingconfort.starter.core.exceptions.FunctionalException;
import com.marketingconfort.starter.core.exceptions.S3FunctionalException;
import com.marketingconfort.starter.core.services.S3FileService;
......@@ -23,6 +26,7 @@ import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
......@@ -43,6 +47,9 @@ public class DocumentServiceImpl implements DocumentService {
if (request.getFolderId() != null) {
folder = folderRepository.findById(request.getFolderId())
.orElseThrow(() -> new FunctionalException(MessageConstants.FOLDER_NOT_FOUND));
if (!isFolderOwnedByUser(folder.getId(), request.getOwnerId())) {
throw new FunctionalException(MessageConstants.UNAUTHORIZED_FOLDER_ACCESS);
}
}
if (!storageQuotaService.hasAvailableStorage(request.getOwnerId(), file.getSize())) {
......@@ -103,7 +110,32 @@ public class DocumentServiceImpl implements DocumentService {
return documents.stream().map(DocumentMapper::toDto).collect(Collectors.toList());
}
public boolean isDocumentNameUnique(String name, Long folderId, Long ownerId) {
@Override
public List<DocumentStatisticsDTO> getDocumentStatistics(Long ownerId) {
List<Document> userDocuments = documentRepository.findByOwnerId(ownerId);
Map<DocumentType, List<Document>> groupedByType = userDocuments.stream()
.filter(doc -> doc.getDocumentType() != null)
.collect(Collectors.groupingBy(Document::getDocumentType));
return groupedByType.entrySet().stream().map(entry -> {
DocumentType type = entry.getKey();
List<Document> docs = entry.getValue();
long totalSize = docs.stream().filter(d -> d.getSize() != null).mapToLong(Document::getSize).sum();
long count = docs.size();
long avgSize = count > 0 ? totalSize / count : 0;
return DocumentStatisticsDTO.builder()
.documentType(type)
.documentCount(count)
.totalSizeBytes(totalSize)
.totalSizeFormatted(FolderSizeCalculator.formatBytes(totalSize))
.averageSizeFormatted(FolderSizeCalculator.formatBytes(avgSize))
.build();
}).collect(Collectors.toList());
}
private boolean isDocumentNameUnique(String name, Long folderId, Long ownerId) {
if (folderId == null) {
// Root space: check documents for this user with no folder
return !documentRepository.existsByNameAndFolderIsNullAndOwnerId(name, ownerId);
......@@ -111,6 +143,12 @@ public class DocumentServiceImpl implements DocumentService {
return !documentRepository.existsByNameAndFolderIdAndOwnerId(name, folderId, ownerId);
}
}
private boolean isFolderOwnedByUser(Long folderId, Long ownerId) {
return folderRepository.findById(folderId)
.map(folder -> folder.getOwnerId() != null && folder.getOwnerId().equals(ownerId))
.orElse(false);
}
}
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