FINERACT-2169: Refactor document management api and update swagger doc;

This commit is contained in:
viktorpavlenko
2025-03-19 12:26:37 +01:00
committed by Adam Saghy
parent a0ffaa1c0b
commit ac8f62db51
11 changed files with 48 additions and 156 deletions
@@ -20,7 +20,6 @@ package org.apache.fineract.infrastructure.documentmanagement.api;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
@@ -36,20 +35,14 @@ import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.core.UriInfo;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
import org.apache.fineract.infrastructure.core.serialization.ToApiJsonSerializer;
import org.apache.fineract.infrastructure.documentmanagement.command.DocumentCommand;
import org.apache.fineract.infrastructure.documentmanagement.data.DocumentData;
import org.apache.fineract.infrastructure.documentmanagement.data.FileData;
@@ -70,16 +63,11 @@ import org.springframework.stereotype.Component;
@RequiredArgsConstructor
public class DocumentManagementApiResource {
private static final Set<String> RESPONSE_DATA_PARAMETERS = new HashSet<>(
Arrays.asList("id", "parentEntityType", "parentEntityId", "name", "fileName", "size", "type", "description"));
private static final String SYSTEM_ENTITY_TYPE = "DOCUMENT";
private final PlatformSecurityContext context;
private final DocumentReadPlatformService documentReadPlatformService;
private final DocumentWritePlatformService documentWritePlatformService;
private final ApiRequestParameterHelper apiRequestParameterHelper;
private final ToApiJsonSerializer<DocumentData> toApiJsonSerializer;
private final FileUploadValidator fileUploadValidator;
@GET
@@ -87,18 +75,11 @@ public class DocumentManagementApiResource {
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "List documents", description = "Example Requests:\n" + "\n" + "clients/1/documents\n" + "\n"
+ "client_identifiers/1/documents\n" + "\n" + "loans/1/documents?fields=name,description")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(array = @ArraySchema(schema = @Schema(implementation = DocumentManagementApiResourceSwagger.GetEntityTypeEntityIdDocumentsResponse.class)))) })
public String retrieveAllDocuments(@Context final UriInfo uriInfo,
@PathParam("entityType") @Parameter(description = "entityType") final String entityType,
public List<DocumentData> retrieveAllDocuments(@PathParam("entityType") @Parameter(description = "entityType") final String entityType,
@PathParam("entityId") @Parameter(description = "entityId") final Long entityId) {
this.context.authenticatedUser().validateHasReadPermission(SYSTEM_ENTITY_TYPE);
final Collection<DocumentData> documentDatas = this.documentReadPlatformService.retrieveAllDocuments(entityType, entityId);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, documentDatas, RESPONSE_DATA_PARAMETERS);
context.authenticatedUser().validateHasReadPermission(SYSTEM_ENTITY_TYPE);
return documentReadPlatformService.retrieveAllDocuments(entityType, entityId);
}
@POST
@@ -112,7 +93,7 @@ public class DocumentManagementApiResource {
+ "file and description")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "Not Shown (multi-part form data)", content = @Content(schema = @Schema(implementation = DocumentManagementApiResourceSwagger.PostEntityTypeEntityIdDocumentsResponse.class))) })
public String createDocument(@PathParam("entityType") @Parameter(description = "entityType") final String entityType,
public CommandProcessingResult createDocument(@PathParam("entityType") @Parameter(description = "entityType") final String entityType,
@PathParam("entityId") @Parameter(description = "entityId") final Long entityId,
@HeaderParam("Content-Length") @Parameter(description = "Content-Length") final Long fileSize,
@FormDataParam("file") final InputStream inputStream, @FormDataParam("file") final FormDataContentDisposition fileDetails,
@@ -125,8 +106,8 @@ public class DocumentManagementApiResource {
fileUploadValidator.validate(fileSize, inputStream, fileDetails, bodyPart);
final DocumentCommand documentCommand = new DocumentCommand(null, null, entityType, entityId, name, fileDetails.getFileName(),
fileSize, bodyPart.getMediaType().toString(), description, null);
final Long documentId = this.documentWritePlatformService.createDocument(documentCommand, inputStream);
return this.toApiJsonSerializer.serialize(CommandProcessingResult.resourceResult(documentId));
final Long documentId = documentWritePlatformService.createDocument(documentCommand, inputStream);
return CommandProcessingResult.resourceResult(documentId);
}
@PUT
@@ -140,7 +121,7 @@ public class DocumentManagementApiResource {
+ "The file to be uploaded")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "Not Shown (multi-part form data)", content = @Content(schema = @Schema(implementation = DocumentManagementApiResourceSwagger.PutEntityTypeEntityIdDocumentsResponse.class))) })
public String updateDocument(@PathParam("entityType") @Parameter(description = "entityType") final String entityType,
public CommandProcessingResult updateDocument(@PathParam("entityType") @Parameter(description = "entityType") final String entityType,
@PathParam("entityId") @Parameter(description = "entityId") final Long entityId,
@PathParam("documentId") @Parameter(description = "documentId") final Long documentId,
@HeaderParam("Content-Length") @Parameter(description = "Content-Length") final Long fileSize,
@@ -155,7 +136,7 @@ public class DocumentManagementApiResource {
/***
* Populate Document command based on whether a file has also been passed in as a part of the update
***/
DocumentCommand documentCommand = null;
DocumentCommand documentCommand;
if (inputStream != null && fileDetails.getFileName() != null) {
fileUploadValidator.validate(fileSize, inputStream, fileDetails, bodyPart);
modifiedParams.add("fileName");
@@ -171,9 +152,7 @@ public class DocumentManagementApiResource {
/***
* TODO: does not return list of changes, should be done for consistency with rest of API
**/
final CommandProcessingResult identifier = this.documentWritePlatformService.updateDocument(documentCommand, inputStream);
return this.toApiJsonSerializer.serialize(identifier);
return documentWritePlatformService.updateDocument(documentCommand, inputStream);
}
@GET
@@ -182,18 +161,12 @@ public class DocumentManagementApiResource {
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Retrieve a Document", description = "Example Requests:\n" + "\n" + "clients/1/documents/1\n" + "\n" + "\n"
+ "loans/1/documents/1\n" + "\n" + "\n" + "client_identifiers/1/documents/1?fields=name,description")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = DocumentManagementApiResourceSwagger.GetEntityTypeEntityIdDocumentsResponse.class))) })
public String getDocument(@PathParam("entityType") @Parameter(description = "entityType") final String entityType,
public DocumentData getDocument(@PathParam("entityType") @Parameter(description = "entityType") final String entityType,
@PathParam("entityId") @Parameter(description = "entityId") final Long entityId,
@PathParam("documentId") @Parameter(description = "documentId") final Long documentId, @Context final UriInfo uriInfo) {
@PathParam("documentId") @Parameter(description = "documentId") final Long documentId) {
this.context.authenticatedUser().validateHasReadPermission(SYSTEM_ENTITY_TYPE);
final DocumentData documentData = this.documentReadPlatformService.retrieveDocument(entityType, entityId, documentId);
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
return this.toApiJsonSerializer.serialize(settings, documentData, RESPONSE_DATA_PARAMETERS);
context.authenticatedUser().validateHasReadPermission(SYSTEM_ENTITY_TYPE);
return documentReadPlatformService.retrieveDocument(entityType, entityId, documentId);
}
@GET
@@ -207,8 +180,8 @@ public class DocumentManagementApiResource {
@PathParam("entityId") @Parameter(description = "entityId") final Long entityId,
@PathParam("documentId") @Parameter(description = "documentId") final Long documentId) {
this.context.authenticatedUser().validateHasReadPermission(SYSTEM_ENTITY_TYPE);
final FileData fileData = this.documentReadPlatformService.retrieveFileData(entityType, entityId, documentId);
context.authenticatedUser().validateHasReadPermission(SYSTEM_ENTITY_TYPE);
final FileData fileData = documentReadPlatformService.retrieveFileData(entityType, entityId, documentId);
return ContentResources.fileDataToResponse(fileData, "attachment");
}
@@ -219,15 +192,13 @@ public class DocumentManagementApiResource {
@Operation(summary = "Remove a Document", description = "")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = DocumentManagementApiResourceSwagger.DeleteEntityTypeEntityIdDocumentsResponse.class))) })
public String deleteDocument(@PathParam("entityType") @Parameter(description = "entityType") final String entityType,
public CommandProcessingResult deleteDocument(@PathParam("entityType") @Parameter(description = "entityType") final String entityType,
@PathParam("entityId") @Parameter(description = "entityId") final Long entityId,
@PathParam("documentId") @Parameter(description = "documentId") final Long documentId) {
final DocumentCommand documentCommand = new DocumentCommand(null, documentId, entityType, entityId, null, null, null, null, null,
null);
final CommandProcessingResult documentIdentifier = this.documentWritePlatformService.deleteDocument(documentCommand);
return this.toApiJsonSerializer.serialize(documentIdentifier);
return documentWritePlatformService.deleteDocument(documentCommand);
}
}
@@ -32,35 +32,6 @@ final class DocumentManagementApiResourceSwagger {
}
@Schema(description = "GetEntityTypeEntityIdDocumentsResponse")
public static final class GetEntityTypeEntityIdDocumentsResponse {
private GetEntityTypeEntityIdDocumentsResponse() {
}
@Schema(example = "1")
public Long id;
@Schema(example = "clients")
public String parentEntityType;
@Schema(example = "1")
public Long parentEntityId;
@Schema(example = "Client Details Form")
public String name;
@Schema(example = "CGAP.pdf")
public String fileName;
@Schema(example = "5246719")
public Long size;
@Schema(example = "application/pdf")
public String type;
@Schema(example = "A signed form signed by new member")
public String description;
@Schema(example = "")
public String location;
@Schema(example = "")
public Integer storageType;
}
@Schema(description = "PostEntityTypeEntityIdDocumentsResponse")
public static final class PostEntityTypeEntityIdDocumentsResponse {
@@ -103,17 +74,8 @@ final class DocumentManagementApiResourceSwagger {
}
public static final class PutEntityTypeEntityIdDocumentsResponseChangesSwagger {
private PutEntityTypeEntityIdDocumentsResponseChangesSwagger() {
}
}
@Schema(example = "3")
public Long resourceId;
public DeleteEntityTypeEntityIdDocumentsResponse.PutEntityTypeEntityIdDocumentsResponseChangesSwagger changes;
@Schema(example = "3")
public String resourceIdentifier;
}
@@ -104,10 +104,10 @@ public class FileSystemContentRepository implements ContentRepository {
@Override
public FileData fetchFile(final DocumentData documentData) {
String sanitizedPath = pathSanitizer.sanitize(documentData.fileLocation());
String sanitizedPath = pathSanitizer.sanitize(documentData.getLocation());
final File file = new File(sanitizedPath);
return new FileData(Files.asByteSource(file), documentData.fileName(), documentData.contentType());
return new FileData(Files.asByteSource(file), documentData.getFileName(), documentData.getType());
}
@Override
@@ -108,9 +108,9 @@ public class S3ContentRepository implements ContentRepository {
@Override
public InputStream openStream() throws IOException {
return s3Client.getObject(GetObjectRequest.builder().bucket(fineractProperties.getContent().getS3().getBucketName())
.key(documentData.fileLocation()).build(), ResponseTransformer.toBytes()).asInputStream();
.key(documentData.getLocation()).build(), ResponseTransformer.toBytes()).asInputStream();
}
}, documentData.fileName(), documentData.contentType());
}, documentData.getFileName(), documentData.getType());
}
@Override
@@ -18,13 +18,13 @@
*/
package org.apache.fineract.infrastructure.documentmanagement.service;
import java.util.Collection;
import java.util.List;
import org.apache.fineract.infrastructure.documentmanagement.data.DocumentData;
import org.apache.fineract.infrastructure.documentmanagement.data.FileData;
public interface DocumentReadPlatformService {
Collection<DocumentData> retrieveAllDocuments(String entityType, Long entityId);
List<DocumentData> retrieveAllDocuments(String entityType, Long entityId);
FileData retrieveFileData(String entityType, Long entityId, Long documentId);
@@ -20,7 +20,7 @@ package org.apache.fineract.infrastructure.documentmanagement.service;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.core.domain.JdbcSupport;
import org.apache.fineract.infrastructure.documentmanagement.contentrepository.ContentRepository;
@@ -43,7 +43,7 @@ public class DocumentReadPlatformServiceImpl implements DocumentReadPlatformServ
private final ContentRepositoryFactory contentRepositoryFactory;
@Override
public Collection<DocumentData> retrieveAllDocuments(final String entityType, final Long entityId) {
public List<DocumentData> retrieveAllDocuments(final String entityType, final Long entityId) {
this.context.authenticatedUser();
@@ -118,7 +118,7 @@ public class DocumentReadPlatformServiceImpl implements DocumentReadPlatformServ
if (!this.hideStorageType) {
storageType = rs.getInt("storageType");
}
return new DocumentData(id, parentEntityType, parentEntityId, name, fileName, fileSize, fileType, description, location,
return new DocumentData(id, parentEntityType, parentEntityId, name, fileName, fileSize, fileType, location, description,
storageType);
}
}