diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/DocumentManagementApiResource.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/DocumentManagementApiResource.java deleted file mode 100755 index 70c1c9bf5..000000000 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/DocumentManagementApiResource.java +++ /dev/null @@ -1,281 +0,0 @@ -package org.mifosng.platform.api; - -import java.io.File; -import java.io.InputStream; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; -import java.util.Set; - -import javax.ws.rs.Consumes; -import javax.ws.rs.DELETE; -import javax.ws.rs.GET; -import javax.ws.rs.HeaderParam; -import javax.ws.rs.POST; -import javax.ws.rs.PUT; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.ResponseBuilder; -import javax.ws.rs.core.UriInfo; - -import org.mifosng.platform.api.commands.DocumentCommand; -import org.mifosng.platform.api.data.DocumentData; -import org.mifosng.platform.documentmanagement.service.DocumentReadPlatformService; -import org.mifosng.platform.documentmanagement.service.DocumentWritePlatformService; -import org.mifosplatform.infrastructure.core.api.ApiConstants; -import org.mifosplatform.infrastructure.core.api.ApiParameterHelper; -import org.mifosplatform.infrastructure.core.api.PortfolioApiJsonSerializerService; -import org.mifosplatform.infrastructure.core.data.EntityIdentifier; -import org.mifosplatform.infrastructure.core.service.FileUtils; -import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Scope; -import org.springframework.stereotype.Component; - -import com.sun.jersey.core.header.FormDataContentDisposition; -import com.sun.jersey.multipart.FormDataBodyPart; -import com.sun.jersey.multipart.FormDataParam; - -@Path("{entityType}/{entityId}/documents") -@Component -@Scope("singleton") -public class DocumentManagementApiResource { - - @Autowired - private DocumentReadPlatformService documentReadPlatformService; - - @Autowired - private DocumentWritePlatformService documentWritePlatformService; - - @Autowired - private PortfolioApiJsonSerializerService apiJsonSerializerService; - - private static final Set typicalResponseParameters = new HashSet( - Arrays.asList("id", "parentEntityType", "parentEntityId", "name", - "fileName", "type", "size", "description")); - - private final String SystemEntityType = "DOCUMENT"; - @Autowired - private PlatformSecurityContext context; - - /** - * @param uriInfo - * @param entityType - * @param entityId - * @return - */ - @GET - @Consumes({ MediaType.APPLICATION_JSON }) - @Produces({ MediaType.APPLICATION_JSON }) - public String retreiveAllDocuments(@Context final UriInfo uriInfo, - @PathParam("entityType") String entityType, - @PathParam("entityId") Long entityId) { - - context.authenticatedUser().validateHasReadPermission(SystemEntityType); - - Set responseParameters = ApiParameterHelper - .extractFieldsForResponseIfProvided(uriInfo - .getQueryParameters()); - if (responseParameters.isEmpty()) { - responseParameters.addAll(typicalResponseParameters); - } - boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo - .getQueryParameters()); - - Collection documentDatas = this.documentReadPlatformService - .retrieveAllDocuments(entityType, entityId); - - return this.apiJsonSerializerService.serializeDocumentDataToJson( - prettyPrint, responseParameters, documentDatas); - } - - /** - * @param entityType - * @param entityId - * @param fileSize - * @param inputStream - * @param fileDetails - * @param bodyPart - * @param name - * @param description - * @return - */ - @POST - @Consumes({ MediaType.MULTIPART_FORM_DATA }) - @Produces({ MediaType.APPLICATION_JSON }) - public Response createDocument(@PathParam("entityType") String entityType, - @PathParam("entityId") Long entityId, - @HeaderParam("Content-Length") Long fileSize, - @FormDataParam("file") InputStream inputStream, - @FormDataParam("file") FormDataContentDisposition fileDetails, - @FormDataParam("file") FormDataBodyPart bodyPart, - @FormDataParam("name") String name, - @FormDataParam("description") String description) { - - FileUtils.validateFileSizeWithinPermissibleRange(fileSize, name, ApiConstants.MAX_FILE_UPLOAD_SIZE_IN_MB); - - /** - * TODO: also need to have a backup and stop reading from stream after - * max size is reached to protect against malicious clients - **/ - - /** - * TODO: need to extract the actual file type and determine if they are - * permissable - **/ - DocumentCommand documentCommand = new DocumentCommand(null, null, - entityType, entityId, name, fileDetails.getFileName(), - fileSize, bodyPart.getMediaType().toString(), description, null); - - Long documentId = this.documentWritePlatformService.createDocument( - documentCommand, inputStream); - - return Response.ok().entity(new EntityIdentifier(documentId)).build(); - } - - /** - * @param entityType - * @param entityId - * @param documentId - * @param fileSize - * @param inputStream - * @param fileDetails - * @param bodyPart - * @param name - * @param description - * @return - */ - @PUT - @Path("{documentId}") - @Consumes({ MediaType.MULTIPART_FORM_DATA }) - @Produces({ MediaType.APPLICATION_JSON }) - public Response updateDocument(@PathParam("entityType") String entityType, - @PathParam("entityId") Long entityId, - @PathParam("documentId") Long documentId, - @HeaderParam("Content-Length") Long fileSize, - @FormDataParam("file") InputStream inputStream, - @FormDataParam("file") FormDataContentDisposition fileDetails, - @FormDataParam("file") FormDataBodyPart bodyPart, - @FormDataParam("name") String name, - @FormDataParam("description") String description) { - - FileUtils.validateFileSizeWithinPermissibleRange(fileSize, name, ApiConstants.MAX_FILE_UPLOAD_SIZE_IN_MB); - - Set modifiedParams = new HashSet(); - modifiedParams.add("name"); - modifiedParams.add("description"); - - /*** - * Populate Document command based on whether a file has also been - * passed in as a part of the update - ***/ - DocumentCommand documentCommand = null; - if (inputStream != null && fileDetails.getFileName() != null) { - modifiedParams.add("fileName"); - modifiedParams.add("size"); - modifiedParams.add("type"); - modifiedParams.add("location"); - documentCommand = new DocumentCommand(modifiedParams, documentId, - entityType, entityId, name, fileDetails.getFileName(), - fileSize, bodyPart.getMediaType().toString(), description, - null); - } else { - documentCommand = new DocumentCommand(modifiedParams, documentId, - entityType, entityId, name, null, null, null, description, - null); - } - EntityIdentifier identifier = this.documentWritePlatformService - .updateDocument(documentCommand, inputStream); - - return Response.ok().entity(identifier).build(); - } - - - /** - * @param entityType - * @param entityId - * @param documentId - * @param uriInfo - * @return - */ - @GET - @Path("{documentId}") - @Consumes({ MediaType.APPLICATION_JSON }) - @Produces({ MediaType.APPLICATION_JSON }) - public String getDocument(@PathParam("entityType") String entityType, - @PathParam("entityId") Long entityId, - @PathParam("documentId") Long documentId, - @Context final UriInfo uriInfo) { - - context.authenticatedUser().validateHasReadPermission(SystemEntityType); - - Set responseParameters = ApiParameterHelper - .extractFieldsForResponseIfProvided(uriInfo - .getQueryParameters()); - if (responseParameters.isEmpty()) { - responseParameters.addAll(typicalResponseParameters); - } - - boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo - .getQueryParameters()); - - DocumentData documentData = this.documentReadPlatformService - .retrieveDocument(entityType, entityId, documentId); - - return this.apiJsonSerializerService.serializeDocumentDataToJson( - prettyPrint, responseParameters, documentData); - } - - /** - * @param entityType - * @param entityId - * @param documentId - * @return - */ - @GET - @Path("{documentId}/attachment") - @Consumes({ MediaType.APPLICATION_JSON }) - @Produces({ MediaType.APPLICATION_JSON }) - public Response downloadFile(@PathParam("entityType") String entityType, - @PathParam("entityId") Long entityId, - @PathParam("documentId") Long documentId) { - - context.authenticatedUser().validateHasReadPermission(SystemEntityType); - - DocumentData documentData = this.documentReadPlatformService - .retrieveDocument(entityType, entityId, documentId); - File file = new File(documentData.getLocation()); - ResponseBuilder response = Response.ok(file); - response.header("Content-Disposition", "attachment; filename=\"" - + documentData.getFileName() + "\""); - response.header("Content-Type", documentData.getType()); - return response.build(); - } - - /** - * @param entityType - * @param entityId - * @param documentId - * @return - */ - @DELETE - @Path("{documentId}") - @Consumes({ MediaType.APPLICATION_JSON }) - @Produces({ MediaType.APPLICATION_JSON }) - public Response deleteDocument(@PathParam("entityType") String entityType, - @PathParam("entityId") Long entityId, - @PathParam("documentId") Long documentId) { - DocumentCommand documentCommand = new DocumentCommand(null, documentId, - entityType, entityId, null, null, null, null, null, null); - - EntityIdentifier documentIdentifier = this.documentWritePlatformService - .deleteDocument(documentCommand); - - return Response.ok(documentIdentifier).build(); - } - -} diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/DocumentCommand.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/DocumentCommand.java deleted file mode 100755 index 6677d3769..000000000 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/commands/DocumentCommand.java +++ /dev/null @@ -1,119 +0,0 @@ -package org.mifosng.platform.api.commands; - -import java.util.Set; - -/** - * Immutable command for creating or updating details of a client identifier. - */ -public class DocumentCommand { - - private final Long id; - private final String parentEntityType; - private final Long parentEntityId; - private final String name; - private final String description; - - private String fileName; - private Long size; - private String type; - private String location; - - private final Set modifiedParameters; - - public DocumentCommand(final Set modifiedParameters, final Long id, - final String parentEntityType, final Long parentEntityId, - final String name, final String fileName, Long size, String type, - final String description, String location) { - this.modifiedParameters = modifiedParameters; - this.id = id; - this.parentEntityType = parentEntityType; - this.parentEntityId = parentEntityId; - this.name = name; - this.fileName = fileName; - this.size = size; - this.type = type; - this.description = description; - this.location = location; - } - - public Long getId() { - return id; - } - - public String getParentEntityType() { - return parentEntityType; - } - - public Long getParentEntityId() { - return parentEntityId; - } - - public String getName() { - return name; - } - - public String getFileName() { - return fileName; - } - - public Long getSize() { - return size; - } - - public String getType() { - return type; - } - - public String getDescription() { - return description; - } - - public String getLocation() { - return location; - } - - public Set getModifiedParameters() { - return modifiedParameters; - } - - public void setFileName(String fileName) { - this.fileName = fileName; - } - - public void setSize(Long size) { - this.size = size; - } - - public void setType(String type) { - this.type = type; - } - - public void setLocation(String location) { - this.location = location; - } - - public boolean isNameChanged() { - return this.modifiedParameters.contains("name"); - } - - public boolean isFileNameChanged() { - return this.modifiedParameters.contains("fileName"); - } - - public boolean isSizeChanged() { - return this.modifiedParameters.contains("size"); - } - - public boolean isFileTypeChanged() { - return this.modifiedParameters.contains("type"); - } - - public boolean isDescriptionChanged() { - return this.modifiedParameters.contains("description"); - } - - public boolean isLocationChanged() { - return this.modifiedParameters.contains("location"); - } - -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/api/data/DocumentData.java b/mifosng-provider/src/main/java/org/mifosng/platform/api/data/DocumentData.java deleted file mode 100755 index 439d24d78..000000000 --- a/mifosng-provider/src/main/java/org/mifosng/platform/api/data/DocumentData.java +++ /dev/null @@ -1,67 +0,0 @@ -package org.mifosng.platform.api.data; - - -public class DocumentData { - - private final Long id; - private final String parentEntityType; - private final Long parentEntityId; - private final String name; - private final String fileName; - private final Long size; - private final String type; - private final String description; - private final String location; - - public DocumentData(final Long id, final String parentEntityType, - final Long parentEntityId, final String name, - final String fileName, final Long size, final String type, - final String description, final String location) { - this.id = id; - this.parentEntityType = parentEntityType; - this.parentEntityId = parentEntityId; - this.name = name; - this.fileName = fileName; - this.size = size; - this.type = type; - this.description = description; - this.location = location; - } - - public Long getId() { - return id; - } - - public String getParentEntityType() { - return parentEntityType; - } - - public Long getParentEntityId() { - return parentEntityId; - } - - public String getName() { - return name; - } - - public String getFileName() { - return fileName; - } - - public Long getSize() { - return size; - } - - public String getType() { - return type; - } - - public String getDescription() { - return description; - } - - public String getLocation() { - return location; - } - -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/domain/Document.java b/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/domain/Document.java deleted file mode 100755 index 802f8fb15..000000000 --- a/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/domain/Document.java +++ /dev/null @@ -1,150 +0,0 @@ -package org.mifosng.platform.documentmanagement.domain; - -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Table; - -import org.apache.commons.lang.StringUtils; -import org.mifosng.platform.api.commands.DocumentCommand; -import org.mifosplatform.infrastructure.core.domain.AbstractAuditableCustom; -import org.mifosplatform.infrastructure.user.domain.AppUser; - -@Entity -@Table(name = "m_document") -public class Document extends AbstractAuditableCustom { - - @Column(name = "parent_entity_type", length = 50) - private String parentEntityType; - - @Column(name = "parent_entity_id", length = 1000) - private Long parentEntityId; - - @Column(name = "name", length = 250) - private String name; - - @Column(name = "file_name", length = 250) - private String fileName; - - @Column(name = "size") - private Long size; - - @Column(name = "type", length = 50) - private String type; - - @Column(name = "description", length = 1000) - private String description; - - @Column(name = "location", length = 500) - private String location; - - public Document() { - } - - public static Document createNew(String parentEntityType, - Long parentEntityId, String name, String fileName, Long size, - String type, String description, String location) { - return new Document(parentEntityType, parentEntityId, name, fileName, - size, type, description, location); - } - - private Document(String parentEntityType, Long parentEntityId, String name, - String fileName, Long size, String type, String description, - String location) { - this.parentEntityType = StringUtils.defaultIfEmpty(parentEntityType, - null); - this.parentEntityId = parentEntityId; - this.name = StringUtils.defaultIfEmpty(name, null); - this.fileName = StringUtils.defaultIfEmpty(fileName, null); - this.size = size; - this.type = StringUtils.defaultIfEmpty(type, null); - this.description = StringUtils.defaultIfEmpty(description, null); - this.location = StringUtils.defaultIfEmpty(location, null); - } - - public void update(final DocumentCommand command) { - if (command.isDescriptionChanged()) { - this.description = command.getDescription(); - } - if (command.isFileNameChanged()) { - this.fileName = command.getFileName(); - } - if (command.isFileTypeChanged()) { - this.type = command.getType(); - } - if (command.isLocationChanged()) { - this.location = command.getLocation(); - } - if (command.isNameChanged()) { - this.name = command.getName(); - } - if (command.isSizeChanged()) { - this.size = command.getSize(); - } - - } - - public String getParentEntityType() { - return parentEntityType; - } - - public void setParentEntityType(String parentEntityType) { - this.parentEntityType = parentEntityType; - } - - public Long getParentEntityId() { - return parentEntityId; - } - - public void setParentEntityId(Long parentEntityId) { - this.parentEntityId = parentEntityId; - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public String getFileName() { - return fileName; - } - - public void setFileName(String fileName) { - this.fileName = fileName; - } - - public Long getSize() { - return size; - } - - public void setSize(Long size) { - this.size = size; - } - - public String getType() { - return type; - } - - public void setType(String type) { - this.type = type; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public String getLocation() { - return location; - } - - public void setLocation(String location) { - this.location = location; - } - -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/domain/DocumentRepository.java b/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/domain/DocumentRepository.java deleted file mode 100755 index aaa83940c..000000000 --- a/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/domain/DocumentRepository.java +++ /dev/null @@ -1,9 +0,0 @@ -package org.mifosng.platform.documentmanagement.domain; - -import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.JpaSpecificationExecutor; - -public interface DocumentRepository extends - JpaRepository, JpaSpecificationExecutor { - // no added behaviour -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/service/DocumentCommandValidator.java b/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/service/DocumentCommandValidator.java deleted file mode 100755 index ca0c3b9fb..000000000 --- a/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/service/DocumentCommandValidator.java +++ /dev/null @@ -1,75 +0,0 @@ -package org.mifosng.platform.documentmanagement.service; - -import java.util.ArrayList; -import java.util.List; - -import org.mifosng.platform.api.commands.DocumentCommand; -import org.mifosplatform.infrastructure.core.data.ApiParameterError; -import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder; -import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; - -public class DocumentCommandValidator { - - private final DocumentCommand command; - - public DocumentCommandValidator(DocumentCommand command) { - this.command = command; - } - - public void validateForUpdate() { - List dataValidationErrors = new ArrayList(); - - DataValidatorBuilder baseDataValidator = new DataValidatorBuilder( - dataValidationErrors).resource("document"); - - baseDataValidator.reset().parameter("name").value(command.getName()) - .ignoreIfNull().notBlank(); - baseDataValidator.reset().parameter("size").value(command.getSize()) - .ignoreIfNull().integerGreaterThanZero(); - baseDataValidator.reset().parameter("fileName") - .value(command.getFileName()).ignoreIfNull().notBlank() - .notExceedingLengthOf(250); - baseDataValidator.reset().parameter("location") - .value(command.getLocation()).ignoreIfNull().notBlank(); - baseDataValidator.reset().parameter("description") - .value(command.getName()).ignoreIfNull() - .notExceedingLengthOf(250); - - baseDataValidator.reset().anyOfNotNull(command.getName(), - command.getFileName(), command.getDescription(), - command.getLocation(), command.getSize()); - - if (!dataValidationErrors.isEmpty()) { - throw new PlatformApiDataValidationException( - "validation.msg.validation.errors.exist", - "Validation errors exist.", dataValidationErrors); - } - } - - public void validateForCreate() { - List dataValidationErrors = new ArrayList(); - - DataValidatorBuilder baseDataValidator = new DataValidatorBuilder( - dataValidationErrors).resource("document"); - baseDataValidator.reset().parameter("parentEntityType") - .value(command.getParentEntityType()).notBlank() - .notExceedingLengthOf(50); - baseDataValidator.reset().parameter("parentEntityId") - .value(command.getParentEntityId()).integerGreaterThanZero(); - baseDataValidator.reset().parameter("name").value(command.getName()) - .notBlank().notExceedingLengthOf(250); - baseDataValidator.reset().parameter("size").value(command.getSize()) - .integerGreaterThanZero(); - baseDataValidator.reset().parameter("fileName") - .value(command.getFileName()).notBlank() - .notExceedingLengthOf(250); - baseDataValidator.reset().parameter("description") - .value(command.getName()).notExceedingLengthOf(250); - - if (!dataValidationErrors.isEmpty()) { - throw new PlatformApiDataValidationException( - "validation.msg.validation.errors.exist", - "Validation errors exist.", dataValidationErrors); - } - } -} diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/service/DocumentReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/service/DocumentReadPlatformService.java deleted file mode 100755 index 7f0624468..000000000 --- a/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/service/DocumentReadPlatformService.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.mifosng.platform.documentmanagement.service; - -import java.util.Collection; - -import org.mifosng.platform.api.data.DocumentData; - -public interface DocumentReadPlatformService { - - Collection retrieveAllDocuments(String entityType, - Long entityId); - - DocumentData retrieveDocument(String entityType, Long entityId, - Long documentId); - -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/service/DocumentReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/service/DocumentReadPlatformServiceImpl.java deleted file mode 100755 index d17f0d9a7..000000000 --- a/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/service/DocumentReadPlatformServiceImpl.java +++ /dev/null @@ -1,107 +0,0 @@ -package org.mifosng.platform.documentmanagement.service; - -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.Collection; - -import org.mifosng.platform.api.data.DocumentData; -import org.mifosng.platform.exceptions.DocumentNotFoundException; -import org.mifosplatform.infrastructure.core.domain.JdbcSupport; -import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource; -import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.dao.EmptyResultDataAccessException; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.core.RowMapper; -import org.springframework.stereotype.Service; - -@Service -public class DocumentReadPlatformServiceImpl implements DocumentReadPlatformService { - - private final JdbcTemplate jdbcTemplate; - - // TODO: use these services to check if passed in entities for document - // management exists (and ensure appropriate errors are thrown) - private final PlatformSecurityContext context; -// private final OfficeReadPlatformService officeReadPlatformService; -// private final ClientReadPlatformService clientReadPlatformService; -// private final LoanReadPlatformService loanReadPlatformService; -// private final StaffReadPlatformService staffReadPlatformService; -// private final AppUserReadPlatformService appUserReadPlatformService; - - @Autowired - public DocumentReadPlatformServiceImpl( - final PlatformSecurityContext context, - final TenantAwareRoutingDataSource dataSource -// final OfficeReadPlatformService officeReadPlatformService, -// final AppUserReadPlatformService appUserReadPlatformService, -// final ClientReadPlatformService clientReadPlatformService, -// final LoanReadPlatformService loanReadPlatformService, -// final StaffReadPlatformService staffReadPlatformService - ) { - this.context = context; -// this.officeReadPlatformService = officeReadPlatformService; -// this.appUserReadPlatformService = appUserReadPlatformService; -// this.clientReadPlatformService = clientReadPlatformService; -// this.loanReadPlatformService = loanReadPlatformService; -// this.staffReadPlatformService = staffReadPlatformService; - this.jdbcTemplate = new JdbcTemplate(dataSource); - } - - @Override - public Collection retrieveAllDocuments(final String entityType, final Long entityId) { - - context.authenticatedUser(); - - // TODO verify if the entities are valid and a user - // has data - // scope for the particular entities - DocumentMapper mapper = new DocumentMapper(); - String sql = "select " + mapper.schema() + " order by d.id"; - return this.jdbcTemplate.query(sql, mapper, new Object[] {entityType, entityId}); - } - - @Override - public DocumentData retrieveDocument(final String entityType, final Long entityId, final Long documentId) { - - try { - context.authenticatedUser(); - - // TODO verify if the entities are valid and a - // user has data - // scope for the particular entities - DocumentMapper mapper = new DocumentMapper(); - String sql = "select " + mapper.schema() + " and d.id=? "; - return this.jdbcTemplate.queryForObject(sql, mapper, new Object[] {entityType, entityId, documentId }); - } catch (EmptyResultDataAccessException e) { - throw new DocumentNotFoundException(entityType, entityId, documentId); - } - } - - private static final class DocumentMapper implements RowMapper { - - public String schema() { - return "d.id as id, d.parent_entity_type as parentEntityType, d.parent_entity_id as parentEntityId, d.name as name, " - + " d.file_name as fileName, d.size as fileSize, d.type as fileType, " - + " d.description as description, d.location as location" - + " from m_document d where d.parent_entity_type=? and d.parent_entity_id=?"; - } - - @Override - public DocumentData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { - - final Long id = JdbcSupport.getLong(rs, "id"); - final Long parentEntityId = JdbcSupport.getLong(rs, "parentEntityId"); - final Long fileSize = JdbcSupport.getLong(rs, "fileSize"); - final String parentEntityType = rs.getString("parentEntityType"); - final String name = rs.getString("name"); - final String fileName = rs.getString("fileName"); - final String fileType = rs.getString("fileType"); - final String description = rs.getString("description"); - final String location = rs.getString("location"); - - return new DocumentData(id, parentEntityType, parentEntityId, name, - fileName, fileSize, fileType, description, location); - } - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/service/DocumentWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/service/DocumentWritePlatformService.java deleted file mode 100755 index 034634406..000000000 --- a/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/service/DocumentWritePlatformService.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.mifosng.platform.documentmanagement.service; - -import java.io.InputStream; - -import org.mifosng.platform.api.commands.DocumentCommand; -import org.mifosplatform.infrastructure.core.data.EntityIdentifier; -import org.springframework.security.access.prepost.PreAuthorize; - -public interface DocumentWritePlatformService { - - @PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'PORTFOLIO_MANAGEMENT_SUPER_USER', 'CREATE_m_guarantor_external')") - Long createDocument(DocumentCommand documentCommand, InputStream inputStream); - - @PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'PORTFOLIO_MANAGEMENT_SUPER_USER', 'UPDATE_m_guarantor_external')") - EntityIdentifier updateDocument(DocumentCommand documentCommand, - InputStream inputStream); - - @PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'PORTFOLIO_MANAGEMENT_SUPER_USER', 'DELETE_m_guarantor_external')") - EntityIdentifier deleteDocument(DocumentCommand documentCommand); - -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/service/DocumentWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/service/DocumentWritePlatformServiceJpaRepositoryImpl.java deleted file mode 100755 index 88a18e3ea..000000000 --- a/mifosng-provider/src/main/java/org/mifosng/platform/documentmanagement/service/DocumentWritePlatformServiceJpaRepositoryImpl.java +++ /dev/null @@ -1,198 +0,0 @@ -package org.mifosng.platform.documentmanagement.service; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; - -import org.mifosng.platform.api.commands.DocumentCommand; -import org.mifosng.platform.documentmanagement.domain.Document; -import org.mifosng.platform.documentmanagement.domain.DocumentRepository; -import org.mifosng.platform.exceptions.DocumentManagementException; -import org.mifosng.platform.exceptions.DocumentNotFoundException; -import org.mifosng.platform.exceptions.InvalidEntityTypeForDocumentManagementException; -import org.mifosplatform.infrastructure.core.data.EntityIdentifier; -import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException; -import org.mifosplatform.infrastructure.core.service.FileUtils; -import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; - -@Service -public class DocumentWritePlatformServiceJpaRepositoryImpl implements - DocumentWritePlatformService { - - private final static Logger logger = LoggerFactory.getLogger(DocumentWritePlatformServiceJpaRepositoryImpl.class); - - private final PlatformSecurityContext context; - private final DocumentRepository documentRepository; - - @Autowired - public DocumentWritePlatformServiceJpaRepositoryImpl( - final PlatformSecurityContext context, - final DocumentRepository documentRepository) { - this.context = context; - this.documentRepository = documentRepository; - } - - @Transactional - @Override - public Long createDocument(final DocumentCommand documentCommand, final InputStream inputStream) { - try { - context.authenticatedUser(); - - DocumentCommandValidator validator = new DocumentCommandValidator(documentCommand); - - validateParentEntityType(documentCommand); - - validator.validateForCreate(); - - String fileUploadLocation = FileUtils.generateFileParentDirectory( - documentCommand.getParentEntityType(), - documentCommand.getParentEntityId()); - - /** Recursively create the directory if it does not exist **/ - if (!new File(fileUploadLocation).isDirectory()) { - new File(fileUploadLocation).mkdirs(); - } - - String fileLocation = FileUtils.saveToFileSystem(inputStream, - fileUploadLocation, documentCommand.getFileName()); - - Document document = Document.createNew( - documentCommand.getParentEntityType(), - documentCommand.getParentEntityId(), - documentCommand.getName(), documentCommand.getFileName(), - documentCommand.getSize(), documentCommand.getType(), - documentCommand.getDescription(), fileLocation); - - this.documentRepository.save(document); - - return document.getId(); - } catch (DataIntegrityViolationException dve) { - logger.error(dve.getMessage(), dve); - throw new PlatformDataIntegrityException( - "error.msg.document.unknown.data.integrity.issue", - "Unknown data integrity issue with resource."); - } catch (IOException ioe) { - logger.error(ioe.getMessage(), ioe); - throw new DocumentManagementException(documentCommand.getName()); - } - } - - @Transactional - @Override - public EntityIdentifier updateDocument(final DocumentCommand documentCommand, final InputStream inputStream) { - try { - context.authenticatedUser(); - - String oldLocation = null; - DocumentCommandValidator validator = new DocumentCommandValidator(documentCommand); - validator.validateForUpdate(); - // TODO check if entity id is valid and within data scope for the - // user - Document documentForUpdate = this.documentRepository - .findOne(documentCommand.getId()); - if (documentForUpdate == null) { - throw new DocumentNotFoundException( - documentCommand.getParentEntityType(), - documentCommand.getParentEntityId(), - documentCommand.getId()); - } - oldLocation = documentForUpdate.getLocation(); - // if a new file is also passed in - if (inputStream != null && documentCommand.isFileNameChanged()) { - String fileUploadLocation = FileUtils - .generateFileParentDirectory( - documentCommand.getParentEntityType(), - documentCommand.getParentEntityId()); - - /** Recursively create the directory if it does not exist **/ - if (!new File(fileUploadLocation).isDirectory()) { - new File(fileUploadLocation).mkdirs(); - } - - // TODO replace file system appender with an Amazon S3 appender - String fileLocation = FileUtils.saveToFileSystem(inputStream, - fileUploadLocation, documentCommand.getFileName()); - documentCommand.setLocation(fileLocation); - } - - documentForUpdate.update(documentCommand); - - if (inputStream != null && documentCommand.isFileNameChanged()) { - // delete previous file - deleteFile(documentCommand.getName(), oldLocation); - } - - this.documentRepository.saveAndFlush(documentForUpdate); - - return new EntityIdentifier(documentForUpdate.getId()); - } catch (DataIntegrityViolationException dve) { - logger.error(dve.getMessage(), dve); - throw new PlatformDataIntegrityException( - "error.msg.document.unknown.data.integrity.issue", - "Unknown data integrity issue with resource."); - } catch (IOException ioe) { - logger.error(ioe.getMessage(), ioe); - throw new DocumentManagementException(documentCommand.getName()); - } - } - - @Transactional - @Override - public EntityIdentifier deleteDocument(final DocumentCommand documentCommand) { - context.authenticatedUser(); - - validateParentEntityType(documentCommand); - // TODO: Check document is present under this entity Id - Document document = this.documentRepository.findOne(documentCommand.getId()); - if (document == null) { - throw new DocumentNotFoundException( - documentCommand.getParentEntityType(), - documentCommand.getParentEntityId(), - documentCommand.getId()); - } - - this.documentRepository.delete(document); - deleteFile(document.getName(), document.getLocation()); - return new EntityIdentifier(document.getId()); - } - - private void deleteFile(String documentName, String location) { - File fileToBeDeleted = new File(location); - boolean fileDeleted = fileToBeDeleted.delete(); - if (!fileDeleted) { - throw new DocumentManagementException(documentName); - } - } - - private void validateParentEntityType(DocumentCommand documentCommand) { - if (!checkValidEntityType(documentCommand.getParentEntityType())) { - throw new InvalidEntityTypeForDocumentManagementException( - documentCommand.getParentEntityType()); - } - } - - private static boolean checkValidEntityType(final String entityType) { - - for (DOCUMENT_MANAGEMENT_ENTITY entities : DOCUMENT_MANAGEMENT_ENTITY.values()) { - if (entities.name().equalsIgnoreCase(entityType)) { - return true; - } - } - return false; - } - - /*** Entities for document Management **/ - public static enum DOCUMENT_MANAGEMENT_ENTITY { - CLIENTS, CLIENT_IDENTIFIERS, STAFF, LOANS, SAVINGS; - @Override - public String toString() { - return name().toString().toLowerCase(); - } - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/DocumentManagementException.java b/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/DocumentManagementException.java deleted file mode 100755 index 122989d40..000000000 --- a/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/DocumentManagementException.java +++ /dev/null @@ -1,24 +0,0 @@ -package org.mifosng.platform.exceptions; - -import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException; - - -public class DocumentManagementException extends - AbstractPlatformDomainRuleException { - - public DocumentManagementException(final String name) { - super("error.msg.document.save", "Error while manipulating file " - + name + " due to a File system / Amazon S3 issue", name); - } - - public DocumentManagementException(final String name, final Long fileSize, - final int maxFileSize) { - super("error.msg.document.file.too.big", - "Unable to save the document with name" + name - + " since its file Size of " + fileSize / (1024 * 1024) - + " MB exceeds the max permissable file size of " - + maxFileSize - + " MB", name, fileSize); - } - -} diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/DocumentNotFoundException.java b/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/DocumentNotFoundException.java deleted file mode 100755 index 18bc9c3cc..000000000 --- a/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/DocumentNotFoundException.java +++ /dev/null @@ -1,14 +0,0 @@ -package org.mifosng.platform.exceptions; - -import org.mifosplatform.infrastructure.core.exception.AbstractPlatformResourceNotFoundException; - -public class DocumentNotFoundException extends - AbstractPlatformResourceNotFoundException { - - public DocumentNotFoundException(final String entityType, - final Long entityId, final Long id) { - super("error.msg.document.id.invalid", "Document with identifier " + id - + " does not exist for the " + entityType + " with Identifier " - + entityId, id); - } -} diff --git a/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/InvalidEntityTypeForDocumentManagementException.java b/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/InvalidEntityTypeForDocumentManagementException.java deleted file mode 100755 index 13dfa699a..000000000 --- a/mifosng-provider/src/main/java/org/mifosng/platform/exceptions/InvalidEntityTypeForDocumentManagementException.java +++ /dev/null @@ -1,18 +0,0 @@ -package org.mifosng.platform.exceptions; - -import org.mifosplatform.infrastructure.core.exception.AbstractPlatformResourceNotFoundException; - -/** - * A {@link RuntimeException} thrown when document management functionality is - * invoked for invalid Entity Types - */ -public class InvalidEntityTypeForDocumentManagementException extends - AbstractPlatformResourceNotFoundException { - - public InvalidEntityTypeForDocumentManagementException( - final String entityType) { - super("error.documentmanagement.entitytype.invalid", - "Document Management is not support for the Entity Type: " - + entityType, entityType); - } -} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/api/GoogleGsonPortfolioApiJsonSerializerService.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/api/GoogleGsonPortfolioApiJsonSerializerService.java index c1d37c9ca..77c8678b2 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/api/GoogleGsonPortfolioApiJsonSerializerService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/api/GoogleGsonPortfolioApiJsonSerializerService.java @@ -7,7 +7,6 @@ import java.util.Set; import org.mifosng.platform.api.data.DepositAccountData; import org.mifosng.platform.api.data.DepositProductData; -import org.mifosng.platform.api.data.DocumentData; import org.mifosng.platform.api.data.GroupAccountSummaryCollectionData; import org.mifosng.platform.api.data.GroupData; import org.mifosng.platform.api.data.GuarantorData; @@ -19,6 +18,7 @@ import org.mifosplatform.infrastructure.configuration.data.ConfigurationData; import org.mifosplatform.infrastructure.core.data.EntityIdentifier; import org.mifosplatform.infrastructure.dataqueries.data.DatatableData; import org.mifosplatform.infrastructure.dataqueries.data.GenericResultsetData; +import org.mifosplatform.infrastructure.documentmanagement.data.DocumentData; import org.mifosplatform.infrastructure.office.data.OfficeData; import org.mifosplatform.infrastructure.office.data.OfficeTransactionData; import org.mifosplatform.infrastructure.staff.data.BulkTransferLoanOfficerData; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/api/PortfolioApiJsonSerializerService.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/api/PortfolioApiJsonSerializerService.java index df6684e31..a9d70b976 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/api/PortfolioApiJsonSerializerService.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/api/PortfolioApiJsonSerializerService.java @@ -5,7 +5,6 @@ import java.util.Set; import org.mifosng.platform.api.data.DepositAccountData; import org.mifosng.platform.api.data.DepositProductData; -import org.mifosng.platform.api.data.DocumentData; import org.mifosng.platform.api.data.GroupAccountSummaryCollectionData; import org.mifosng.platform.api.data.GroupData; import org.mifosng.platform.api.data.GuarantorData; @@ -17,6 +16,7 @@ import org.mifosplatform.infrastructure.configuration.data.ConfigurationData; import org.mifosplatform.infrastructure.core.data.EntityIdentifier; import org.mifosplatform.infrastructure.dataqueries.data.DatatableData; import org.mifosplatform.infrastructure.dataqueries.data.GenericResultsetData; +import org.mifosplatform.infrastructure.documentmanagement.data.DocumentData; import org.mifosplatform.infrastructure.office.data.OfficeData; import org.mifosplatform.infrastructure.office.data.OfficeTransactionData; import org.mifosplatform.infrastructure.staff.data.BulkTransferLoanOfficerData; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/service/FileUtils.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/service/FileUtils.java index 70a10a51f..05879a9bf 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/service/FileUtils.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/core/service/FileUtils.java @@ -9,12 +9,12 @@ import java.util.ArrayList; import java.util.List; import java.util.Random; -import org.mifosng.platform.exceptions.DocumentManagementException; import org.mifosplatform.infrastructure.core.data.ApiParameterError; import org.mifosplatform.infrastructure.core.domain.Base64EncodedImage; import org.mifosplatform.infrastructure.core.exception.ImageDataURLNotValidException; import org.mifosplatform.infrastructure.core.exception.ImageUploadException; import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; +import org.mifosplatform.infrastructure.documentmanagement.exception.DocumentManagementException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/api/DocumentManagementApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/api/DocumentManagementApiResource.java new file mode 100644 index 000000000..f07745e4f --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/api/DocumentManagementApiResource.java @@ -0,0 +1,191 @@ +package org.mifosplatform.infrastructure.documentmanagement.api; + +import java.io.File; +import java.io.InputStream; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.ResponseBuilder; +import javax.ws.rs.core.UriInfo; + +import org.mifosplatform.infrastructure.core.api.ApiConstants; +import org.mifosplatform.infrastructure.core.api.ApiParameterHelper; +import org.mifosplatform.infrastructure.core.api.PortfolioApiJsonSerializerService; +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.mifosplatform.infrastructure.core.service.FileUtils; +import org.mifosplatform.infrastructure.documentmanagement.command.DocumentCommand; +import org.mifosplatform.infrastructure.documentmanagement.data.DocumentData; +import org.mifosplatform.infrastructure.documentmanagement.service.DocumentReadPlatformService; +import org.mifosplatform.infrastructure.documentmanagement.service.DocumentWritePlatformService; +import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Scope; +import org.springframework.stereotype.Component; + +import com.sun.jersey.core.header.FormDataContentDisposition; +import com.sun.jersey.multipart.FormDataBodyPart; +import com.sun.jersey.multipart.FormDataParam; + +@Path("{entityType}/{entityId}/documents") +@Component +@Scope("singleton") +public class DocumentManagementApiResource { + + private final String SystemEntityType = "DOCUMENT"; + + private final PlatformSecurityContext context; + private final DocumentReadPlatformService documentReadPlatformService; + private final DocumentWritePlatformService documentWritePlatformService; + private final PortfolioApiJsonSerializerService apiJsonSerializerService; + + @Autowired + public DocumentManagementApiResource(final PlatformSecurityContext context, + final DocumentReadPlatformService documentReadPlatformService, final DocumentWritePlatformService documentWritePlatformService, + final PortfolioApiJsonSerializerService apiJsonSerializerService) { + this.context = context; + this.documentReadPlatformService = documentReadPlatformService; + this.documentWritePlatformService = documentWritePlatformService; + this.apiJsonSerializerService = apiJsonSerializerService; + } + + @GET + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String retreiveAllDocuments(@Context final UriInfo uriInfo, @PathParam("entityType") String entityType, + @PathParam("entityId") Long entityId) { + + context.authenticatedUser().validateHasReadPermission(SystemEntityType); + + final Set responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); + final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); + + final Collection documentDatas = this.documentReadPlatformService.retrieveAllDocuments(entityType, entityId); + + return this.apiJsonSerializerService.serializeDocumentDataToJson(prettyPrint, responseParameters, documentDatas); + } + + @POST + @Consumes({ MediaType.MULTIPART_FORM_DATA }) + @Produces({ MediaType.APPLICATION_JSON }) + public Response createDocument(@PathParam("entityType") String entityType, @PathParam("entityId") Long entityId, + @HeaderParam("Content-Length") Long fileSize, @FormDataParam("file") InputStream inputStream, + @FormDataParam("file") FormDataContentDisposition fileDetails, @FormDataParam("file") FormDataBodyPart bodyPart, + @FormDataParam("name") String name, @FormDataParam("description") String description) { + + FileUtils.validateFileSizeWithinPermissibleRange(fileSize, name, ApiConstants.MAX_FILE_UPLOAD_SIZE_IN_MB); + + /** + * TODO: also need to have a backup and stop reading from stream after + * max size is reached to protect against malicious clients + **/ + + /** + * TODO: need to extract the actual file type and determine if they are + * permissable + **/ + DocumentCommand documentCommand = new DocumentCommand(null, null, entityType, entityId, name, fileDetails.getFileName(), fileSize, + bodyPart.getMediaType().toString(), description, null); + + Long documentId = this.documentWritePlatformService.createDocument(documentCommand, inputStream); + + return Response.ok().entity(new EntityIdentifier(documentId)).build(); + } + + @PUT + @Path("{documentId}") + @Consumes({ MediaType.MULTIPART_FORM_DATA }) + @Produces({ MediaType.APPLICATION_JSON }) + public Response updateDocument(@PathParam("entityType") String entityType, @PathParam("entityId") Long entityId, + @PathParam("documentId") Long documentId, @HeaderParam("Content-Length") Long fileSize, + @FormDataParam("file") InputStream inputStream, @FormDataParam("file") FormDataContentDisposition fileDetails, + @FormDataParam("file") FormDataBodyPart bodyPart, @FormDataParam("name") String name, + @FormDataParam("description") String description) { + + FileUtils.validateFileSizeWithinPermissibleRange(fileSize, name, ApiConstants.MAX_FILE_UPLOAD_SIZE_IN_MB); + + Set modifiedParams = new HashSet(); + modifiedParams.add("name"); + modifiedParams.add("description"); + + /*** + * Populate Document command based on whether a file has also been + * passed in as a part of the update + ***/ + DocumentCommand documentCommand = null; + if (inputStream != null && fileDetails.getFileName() != null) { + modifiedParams.add("fileName"); + modifiedParams.add("size"); + modifiedParams.add("type"); + modifiedParams.add("location"); + documentCommand = new DocumentCommand(modifiedParams, documentId, entityType, entityId, name, fileDetails.getFileName(), + fileSize, bodyPart.getMediaType().toString(), description, null); + } else { + documentCommand = new DocumentCommand(modifiedParams, documentId, entityType, entityId, name, null, null, null, description, + null); + } + EntityIdentifier identifier = this.documentWritePlatformService.updateDocument(documentCommand, inputStream); + + return Response.ok().entity(identifier).build(); + } + + @GET + @Path("{documentId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public String getDocument(@PathParam("entityType") String entityType, @PathParam("entityId") Long entityId, + @PathParam("documentId") Long documentId, @Context final UriInfo uriInfo) { + + context.authenticatedUser().validateHasReadPermission(SystemEntityType); + + final Set responseParameters = ApiParameterHelper.extractFieldsForResponseIfProvided(uriInfo.getQueryParameters()); + final boolean prettyPrint = ApiParameterHelper.prettyPrint(uriInfo.getQueryParameters()); + + final DocumentData documentData = this.documentReadPlatformService.retrieveDocument(entityType, entityId, documentId); + + return this.apiJsonSerializerService.serializeDocumentDataToJson(prettyPrint, responseParameters, documentData); + } + + @GET + @Path("{documentId}/attachment") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public Response downloadFile(@PathParam("entityType") String entityType, @PathParam("entityId") Long entityId, + @PathParam("documentId") Long documentId) { + + context.authenticatedUser().validateHasReadPermission(SystemEntityType); + + DocumentData documentData = this.documentReadPlatformService.retrieveDocument(entityType, entityId, documentId); + File file = new File(documentData.fileLocation()); + ResponseBuilder response = Response.ok(file); + response.header("Content-Disposition", "attachment; filename=\"" + documentData.fileName() + "\""); + response.header("Content-Type", documentData.contentType()); + return response.build(); + } + + @DELETE + @Path("{documentId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + public Response deleteDocument(@PathParam("entityType") String entityType, @PathParam("entityId") Long entityId, + @PathParam("documentId") Long documentId) { + + DocumentCommand documentCommand = new DocumentCommand(null, documentId, entityType, entityId, null, null, null, null, null, null); + + EntityIdentifier documentIdentifier = this.documentWritePlatformService.deleteDocument(documentCommand); + + return Response.ok(documentIdentifier).build(); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/command/DocumentCommand.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/command/DocumentCommand.java new file mode 100644 index 000000000..e3e54c881 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/command/DocumentCommand.java @@ -0,0 +1,117 @@ +package org.mifosplatform.infrastructure.documentmanagement.command; + +import java.util.Set; + +/** + * Immutable command for creating or updating details of a client identifier. + */ +public class DocumentCommand { + + private final Long id; + private final String parentEntityType; + private final Long parentEntityId; + private final String name; + private final String description; + + private String fileName; + private Long size; + private String type; + private String location; + + private final Set modifiedParameters; + + public DocumentCommand(final Set modifiedParameters, final Long id, final String parentEntityType, final Long parentEntityId, + final String name, final String fileName, Long size, String type, final String description, String location) { + this.modifiedParameters = modifiedParameters; + this.id = id; + this.parentEntityType = parentEntityType; + this.parentEntityId = parentEntityId; + this.name = name; + this.fileName = fileName; + this.size = size; + this.type = type; + this.description = description; + this.location = location; + } + + public Long getId() { + return id; + } + + public String getParentEntityType() { + return parentEntityType; + } + + public Long getParentEntityId() { + return parentEntityId; + } + + public String getName() { + return name; + } + + public String getFileName() { + return fileName; + } + + public Long getSize() { + return size; + } + + public String getType() { + return type; + } + + public String getDescription() { + return description; + } + + public String getLocation() { + return location; + } + + public Set getModifiedParameters() { + return modifiedParameters; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public void setSize(Long size) { + this.size = size; + } + + public void setType(String type) { + this.type = type; + } + + public void setLocation(String location) { + this.location = location; + } + + public boolean isNameChanged() { + return this.modifiedParameters.contains("name"); + } + + public boolean isFileNameChanged() { + return this.modifiedParameters.contains("fileName"); + } + + public boolean isSizeChanged() { + return this.modifiedParameters.contains("size"); + } + + public boolean isFileTypeChanged() { + return this.modifiedParameters.contains("type"); + } + + public boolean isDescriptionChanged() { + return this.modifiedParameters.contains("description"); + } + + public boolean isLocationChanged() { + return this.modifiedParameters.contains("location"); + } + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/command/DocumentCommandValidator.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/command/DocumentCommandValidator.java new file mode 100644 index 000000000..884b93d26 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/command/DocumentCommandValidator.java @@ -0,0 +1,50 @@ +package org.mifosplatform.infrastructure.documentmanagement.command; + +import java.util.ArrayList; +import java.util.List; + +import org.mifosplatform.infrastructure.core.data.ApiParameterError; +import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder; +import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException; + +public class DocumentCommandValidator { + + private final DocumentCommand command; + + public DocumentCommandValidator(DocumentCommand command) { + this.command = command; + } + + public void validateForUpdate() { + List dataValidationErrors = new ArrayList(); + + DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("document"); + + baseDataValidator.reset().parameter("name").value(command.getName()).ignoreIfNull().notBlank(); + baseDataValidator.reset().parameter("size").value(command.getSize()).ignoreIfNull().integerGreaterThanZero(); + baseDataValidator.reset().parameter("fileName").value(command.getFileName()).ignoreIfNull().notBlank().notExceedingLengthOf(250); + baseDataValidator.reset().parameter("location").value(command.getLocation()).ignoreIfNull().notBlank(); + baseDataValidator.reset().parameter("description").value(command.getName()).ignoreIfNull().notExceedingLengthOf(250); + + baseDataValidator.reset().anyOfNotNull(command.getName(), command.getFileName(), command.getDescription(), command.getLocation(), + command.getSize()); + + if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", + "Validation errors exist.", dataValidationErrors); } + } + + public void validateForCreate() { + List dataValidationErrors = new ArrayList(); + + DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("document"); + baseDataValidator.reset().parameter("parentEntityType").value(command.getParentEntityType()).notBlank().notExceedingLengthOf(50); + baseDataValidator.reset().parameter("parentEntityId").value(command.getParentEntityId()).integerGreaterThanZero(); + baseDataValidator.reset().parameter("name").value(command.getName()).notBlank().notExceedingLengthOf(250); + baseDataValidator.reset().parameter("size").value(command.getSize()).integerGreaterThanZero(); + baseDataValidator.reset().parameter("fileName").value(command.getFileName()).notBlank().notExceedingLengthOf(250); + baseDataValidator.reset().parameter("description").value(command.getName()).notExceedingLengthOf(250); + + if (!dataValidationErrors.isEmpty()) { throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", + "Validation errors exist.", dataValidationErrors); } + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/data/DocumentData.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/data/DocumentData.java new file mode 100644 index 000000000..626e7c96e --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/data/DocumentData.java @@ -0,0 +1,48 @@ +package org.mifosplatform.infrastructure.documentmanagement.data; + +/** + * Immutable data object represent document being managed on platform. + */ +public class DocumentData { + + @SuppressWarnings("unused") + private final Long id; + @SuppressWarnings("unused") + private final String parentEntityType; + @SuppressWarnings("unused") + private final Long parentEntityId; + @SuppressWarnings("unused") + private final String name; + private final String fileName; + @SuppressWarnings("unused") + private final Long size; + private final String type; + @SuppressWarnings("unused") + private final String description; + private final String location; + + public DocumentData(final Long id, final String parentEntityType, final Long parentEntityId, final String name, final String fileName, + final Long size, final String type, final String description, final String location) { + this.id = id; + this.parentEntityType = parentEntityType; + this.parentEntityId = parentEntityId; + this.name = name; + this.fileName = fileName; + this.size = size; + this.type = type; + this.description = description; + this.location = location; + } + + public String contentType() { + return this.type; + } + + public String fileName() { + return this.fileName; + } + + public String fileLocation() { + return this.location; + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/domain/Document.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/domain/Document.java new file mode 100644 index 000000000..553559e85 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/domain/Document.java @@ -0,0 +1,145 @@ +package org.mifosplatform.infrastructure.documentmanagement.domain; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Table; + +import org.apache.commons.lang.StringUtils; +import org.mifosplatform.infrastructure.core.domain.AbstractAuditableCustom; +import org.mifosplatform.infrastructure.documentmanagement.command.DocumentCommand; +import org.mifosplatform.infrastructure.user.domain.AppUser; + +@Entity +@Table(name = "m_document") +public class Document extends AbstractAuditableCustom { + + @Column(name = "parent_entity_type", length = 50) + private String parentEntityType; + + @Column(name = "parent_entity_id", length = 1000) + private Long parentEntityId; + + @Column(name = "name", length = 250) + private String name; + + @Column(name = "file_name", length = 250) + private String fileName; + + @Column(name = "size") + private Long size; + + @Column(name = "type", length = 50) + private String type; + + @Column(name = "description", length = 1000) + private String description; + + @Column(name = "location", length = 500) + private String location; + + public Document() {} + + public static Document createNew(String parentEntityType, Long parentEntityId, String name, String fileName, Long size, String type, + String description, String location) { + return new Document(parentEntityType, parentEntityId, name, fileName, size, type, description, location); + } + + private Document(String parentEntityType, Long parentEntityId, String name, String fileName, Long size, String type, + String description, String location) { + this.parentEntityType = StringUtils.defaultIfEmpty(parentEntityType, null); + this.parentEntityId = parentEntityId; + this.name = StringUtils.defaultIfEmpty(name, null); + this.fileName = StringUtils.defaultIfEmpty(fileName, null); + this.size = size; + this.type = StringUtils.defaultIfEmpty(type, null); + this.description = StringUtils.defaultIfEmpty(description, null); + this.location = StringUtils.defaultIfEmpty(location, null); + } + + public void update(final DocumentCommand command) { + if (command.isDescriptionChanged()) { + this.description = command.getDescription(); + } + if (command.isFileNameChanged()) { + this.fileName = command.getFileName(); + } + if (command.isFileTypeChanged()) { + this.type = command.getType(); + } + if (command.isLocationChanged()) { + this.location = command.getLocation(); + } + if (command.isNameChanged()) { + this.name = command.getName(); + } + if (command.isSizeChanged()) { + this.size = command.getSize(); + } + + } + + public String getParentEntityType() { + return parentEntityType; + } + + public void setParentEntityType(String parentEntityType) { + this.parentEntityType = parentEntityType; + } + + public Long getParentEntityId() { + return parentEntityId; + } + + public void setParentEntityId(Long parentEntityId) { + this.parentEntityId = parentEntityId; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public Long getSize() { + return size; + } + + public void setSize(Long size) { + this.size = size; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public String getLocation() { + return location; + } + + public void setLocation(String location) { + this.location = location; + } + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/domain/DocumentRepository.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/domain/DocumentRepository.java new file mode 100644 index 000000000..e7787c3dd --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/domain/DocumentRepository.java @@ -0,0 +1,8 @@ +package org.mifosplatform.infrastructure.documentmanagement.domain; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +public interface DocumentRepository extends JpaRepository, JpaSpecificationExecutor { + // no added behaviour +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/exception/DocumentManagementException.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/exception/DocumentManagementException.java new file mode 100644 index 000000000..677577451 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/exception/DocumentManagementException.java @@ -0,0 +1,16 @@ +package org.mifosplatform.infrastructure.documentmanagement.exception; + +import org.mifosplatform.infrastructure.core.exception.AbstractPlatformDomainRuleException; + +public class DocumentManagementException extends AbstractPlatformDomainRuleException { + + public DocumentManagementException(final String name) { + super("error.msg.document.save", "Error while manipulating file " + name + " due to a File system / Amazon S3 issue", name); + } + + public DocumentManagementException(final String name, final Long fileSize, final int maxFileSize) { + super("error.msg.document.file.too.big", "Unable to save the document with name" + name + " since its file Size of " + fileSize + / (1024 * 1024) + " MB exceeds the max permissable file size of " + maxFileSize + " MB", name, fileSize); + } + +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/exception/DocumentNotFoundException.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/exception/DocumentNotFoundException.java new file mode 100644 index 000000000..821fa3716 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/exception/DocumentNotFoundException.java @@ -0,0 +1,11 @@ +package org.mifosplatform.infrastructure.documentmanagement.exception; + +import org.mifosplatform.infrastructure.core.exception.AbstractPlatformResourceNotFoundException; + +public class DocumentNotFoundException extends AbstractPlatformResourceNotFoundException { + + public DocumentNotFoundException(final String entityType, final Long entityId, final Long id) { + super("error.msg.document.id.invalid", "Document with identifier " + id + " does not exist for the " + entityType + + " with Identifier " + entityId, id); + } +} diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/exception/InvalidEntityTypeForDocumentManagementException.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/exception/InvalidEntityTypeForDocumentManagementException.java new file mode 100644 index 000000000..41feacc6f --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/exception/InvalidEntityTypeForDocumentManagementException.java @@ -0,0 +1,15 @@ +package org.mifosplatform.infrastructure.documentmanagement.exception; + +import org.mifosplatform.infrastructure.core.exception.AbstractPlatformResourceNotFoundException; + +/** + * A {@link RuntimeException} thrown when document management functionality is + * invoked for invalid Entity Types + */ +public class InvalidEntityTypeForDocumentManagementException extends AbstractPlatformResourceNotFoundException { + + public InvalidEntityTypeForDocumentManagementException(final String entityType) { + super("error.documentmanagement.entitytype.invalid", "Document Management is not support for the Entity Type: " + entityType, + entityType); + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/service/DocumentReadPlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/service/DocumentReadPlatformService.java new file mode 100644 index 000000000..982fa5a48 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/service/DocumentReadPlatformService.java @@ -0,0 +1,12 @@ +package org.mifosplatform.infrastructure.documentmanagement.service; + +import java.util.Collection; + +import org.mifosplatform.infrastructure.documentmanagement.data.DocumentData; + +public interface DocumentReadPlatformService { + + Collection retrieveAllDocuments(String entityType, Long entityId); + + DocumentData retrieveDocument(String entityType, Long entityId, Long documentId); +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/service/DocumentReadPlatformServiceImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/service/DocumentReadPlatformServiceImpl.java new file mode 100644 index 000000000..de1fe2886 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/service/DocumentReadPlatformServiceImpl.java @@ -0,0 +1,85 @@ +package org.mifosplatform.infrastructure.documentmanagement.service; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Collection; + +import org.mifosplatform.infrastructure.core.domain.JdbcSupport; +import org.mifosplatform.infrastructure.core.service.TenantAwareRoutingDataSource; +import org.mifosplatform.infrastructure.documentmanagement.data.DocumentData; +import org.mifosplatform.infrastructure.documentmanagement.exception.DocumentNotFoundException; +import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Service; + +@Service +public class DocumentReadPlatformServiceImpl implements DocumentReadPlatformService { + + private final JdbcTemplate jdbcTemplate; + private final PlatformSecurityContext context; + + @Autowired + public DocumentReadPlatformServiceImpl(final PlatformSecurityContext context, final TenantAwareRoutingDataSource dataSource) { + this.context = context; + this.jdbcTemplate = new JdbcTemplate(dataSource); + } + + @Override + public Collection retrieveAllDocuments(final String entityType, final Long entityId) { + + context.authenticatedUser(); + + // TODO verify if the entities are valid and a user + // has data + // scope for the particular entities + DocumentMapper mapper = new DocumentMapper(); + String sql = "select " + mapper.schema() + " order by d.id"; + return this.jdbcTemplate.query(sql, mapper, new Object[] { entityType, entityId }); + } + + @Override + public DocumentData retrieveDocument(final String entityType, final Long entityId, final Long documentId) { + + try { + context.authenticatedUser(); + + // TODO verify if the entities are valid and a + // user has data + // scope for the particular entities + DocumentMapper mapper = new DocumentMapper(); + String sql = "select " + mapper.schema() + " and d.id=? "; + return this.jdbcTemplate.queryForObject(sql, mapper, new Object[] { entityType, entityId, documentId }); + } catch (EmptyResultDataAccessException e) { + throw new DocumentNotFoundException(entityType, entityId, documentId); + } + } + + private static final class DocumentMapper implements RowMapper { + + public String schema() { + return "d.id as id, d.parent_entity_type as parentEntityType, d.parent_entity_id as parentEntityId, d.name as name, " + + " d.file_name as fileName, d.size as fileSize, d.type as fileType, " + + " d.description as description, d.location as location" + + " from m_document d where d.parent_entity_type=? and d.parent_entity_id=?"; + } + + @Override + public DocumentData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { + + final Long id = JdbcSupport.getLong(rs, "id"); + final Long parentEntityId = JdbcSupport.getLong(rs, "parentEntityId"); + final Long fileSize = JdbcSupport.getLong(rs, "fileSize"); + final String parentEntityType = rs.getString("parentEntityType"); + final String name = rs.getString("name"); + final String fileName = rs.getString("fileName"); + final String fileType = rs.getString("fileType"); + final String description = rs.getString("description"); + final String location = rs.getString("location"); + + return new DocumentData(id, parentEntityType, parentEntityId, name, fileName, fileSize, fileType, description, location); + } + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/service/DocumentWritePlatformService.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/service/DocumentWritePlatformService.java new file mode 100644 index 000000000..8d94dbac0 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/service/DocumentWritePlatformService.java @@ -0,0 +1,20 @@ +package org.mifosplatform.infrastructure.documentmanagement.service; + +import java.io.InputStream; + +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.mifosplatform.infrastructure.documentmanagement.command.DocumentCommand; +import org.springframework.security.access.prepost.PreAuthorize; + +public interface DocumentWritePlatformService { + + @PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'PORTFOLIO_MANAGEMENT_SUPER_USER', 'CREATE_m_guarantor_external')") + Long createDocument(DocumentCommand documentCommand, InputStream inputStream); + + @PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'PORTFOLIO_MANAGEMENT_SUPER_USER', 'UPDATE_m_guarantor_external')") + EntityIdentifier updateDocument(DocumentCommand documentCommand, InputStream inputStream); + + @PreAuthorize(value = "hasAnyRole('ALL_FUNCTIONS', 'PORTFOLIO_MANAGEMENT_SUPER_USER', 'DELETE_m_guarantor_external')") + EntityIdentifier deleteDocument(DocumentCommand documentCommand); + +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/service/DocumentWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/service/DocumentWritePlatformServiceJpaRepositoryImpl.java new file mode 100644 index 000000000..fb46a6804 --- /dev/null +++ b/mifosng-provider/src/main/java/org/mifosplatform/infrastructure/documentmanagement/service/DocumentWritePlatformServiceJpaRepositoryImpl.java @@ -0,0 +1,172 @@ +package org.mifosplatform.infrastructure.documentmanagement.service; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +import org.mifosplatform.infrastructure.core.data.EntityIdentifier; +import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException; +import org.mifosplatform.infrastructure.core.service.FileUtils; +import org.mifosplatform.infrastructure.documentmanagement.command.DocumentCommand; +import org.mifosplatform.infrastructure.documentmanagement.command.DocumentCommandValidator; +import org.mifosplatform.infrastructure.documentmanagement.domain.Document; +import org.mifosplatform.infrastructure.documentmanagement.domain.DocumentRepository; +import org.mifosplatform.infrastructure.documentmanagement.exception.DocumentManagementException; +import org.mifosplatform.infrastructure.documentmanagement.exception.DocumentNotFoundException; +import org.mifosplatform.infrastructure.documentmanagement.exception.InvalidEntityTypeForDocumentManagementException; +import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class DocumentWritePlatformServiceJpaRepositoryImpl implements DocumentWritePlatformService { + + private final static Logger logger = LoggerFactory.getLogger(DocumentWritePlatformServiceJpaRepositoryImpl.class); + + private final PlatformSecurityContext context; + private final DocumentRepository documentRepository; + + @Autowired + public DocumentWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final DocumentRepository documentRepository) { + this.context = context; + this.documentRepository = documentRepository; + } + + @Transactional + @Override + public Long createDocument(final DocumentCommand documentCommand, final InputStream inputStream) { + try { + context.authenticatedUser(); + + DocumentCommandValidator validator = new DocumentCommandValidator(documentCommand); + + validateParentEntityType(documentCommand); + + validator.validateForCreate(); + + String fileUploadLocation = FileUtils.generateFileParentDirectory(documentCommand.getParentEntityType(), + documentCommand.getParentEntityId()); + + /** Recursively create the directory if it does not exist **/ + if (!new File(fileUploadLocation).isDirectory()) { + new File(fileUploadLocation).mkdirs(); + } + + String fileLocation = FileUtils.saveToFileSystem(inputStream, fileUploadLocation, documentCommand.getFileName()); + + Document document = Document.createNew(documentCommand.getParentEntityType(), documentCommand.getParentEntityId(), + documentCommand.getName(), documentCommand.getFileName(), documentCommand.getSize(), documentCommand.getType(), + documentCommand.getDescription(), fileLocation); + + this.documentRepository.save(document); + + return document.getId(); + } catch (DataIntegrityViolationException dve) { + logger.error(dve.getMessage(), dve); + throw new PlatformDataIntegrityException("error.msg.document.unknown.data.integrity.issue", + "Unknown data integrity issue with resource."); + } catch (IOException ioe) { + logger.error(ioe.getMessage(), ioe); + throw new DocumentManagementException(documentCommand.getName()); + } + } + + @Transactional + @Override + public EntityIdentifier updateDocument(final DocumentCommand documentCommand, final InputStream inputStream) { + try { + context.authenticatedUser(); + + String oldLocation = null; + DocumentCommandValidator validator = new DocumentCommandValidator(documentCommand); + validator.validateForUpdate(); + // TODO check if entity id is valid and within data scope for the + // user + Document documentForUpdate = this.documentRepository.findOne(documentCommand.getId()); + if (documentForUpdate == null) { throw new DocumentNotFoundException(documentCommand.getParentEntityType(), + documentCommand.getParentEntityId(), documentCommand.getId()); } + oldLocation = documentForUpdate.getLocation(); + // if a new file is also passed in + if (inputStream != null && documentCommand.isFileNameChanged()) { + String fileUploadLocation = FileUtils.generateFileParentDirectory(documentCommand.getParentEntityType(), + documentCommand.getParentEntityId()); + + /** Recursively create the directory if it does not exist **/ + if (!new File(fileUploadLocation).isDirectory()) { + new File(fileUploadLocation).mkdirs(); + } + + // TODO replace file system appender with an Amazon S3 appender + String fileLocation = FileUtils.saveToFileSystem(inputStream, fileUploadLocation, documentCommand.getFileName()); + documentCommand.setLocation(fileLocation); + } + + documentForUpdate.update(documentCommand); + + if (inputStream != null && documentCommand.isFileNameChanged()) { + // delete previous file + deleteFile(documentCommand.getName(), oldLocation); + } + + this.documentRepository.saveAndFlush(documentForUpdate); + + return new EntityIdentifier(documentForUpdate.getId()); + } catch (DataIntegrityViolationException dve) { + logger.error(dve.getMessage(), dve); + throw new PlatformDataIntegrityException("error.msg.document.unknown.data.integrity.issue", + "Unknown data integrity issue with resource."); + } catch (IOException ioe) { + logger.error(ioe.getMessage(), ioe); + throw new DocumentManagementException(documentCommand.getName()); + } + } + + @Transactional + @Override + public EntityIdentifier deleteDocument(final DocumentCommand documentCommand) { + context.authenticatedUser(); + + validateParentEntityType(documentCommand); + // TODO: Check document is present under this entity Id + Document document = this.documentRepository.findOne(documentCommand.getId()); + if (document == null) { throw new DocumentNotFoundException(documentCommand.getParentEntityType(), + documentCommand.getParentEntityId(), documentCommand.getId()); } + + this.documentRepository.delete(document); + deleteFile(document.getName(), document.getLocation()); + return new EntityIdentifier(document.getId()); + } + + private void deleteFile(String documentName, String location) { + File fileToBeDeleted = new File(location); + boolean fileDeleted = fileToBeDeleted.delete(); + if (!fileDeleted) { throw new DocumentManagementException(documentName); } + } + + private void validateParentEntityType(DocumentCommand documentCommand) { + if (!checkValidEntityType(documentCommand.getParentEntityType())) { throw new InvalidEntityTypeForDocumentManagementException( + documentCommand.getParentEntityType()); } + } + + private static boolean checkValidEntityType(final String entityType) { + + for (DOCUMENT_MANAGEMENT_ENTITY entities : DOCUMENT_MANAGEMENT_ENTITY.values()) { + if (entities.name().equalsIgnoreCase(entityType)) { return true; } + } + return false; + } + + /*** Entities for document Management **/ + public static enum DOCUMENT_MANAGEMENT_ENTITY { + CLIENTS, CLIENT_IDENTIFIERS, STAFF, LOANS, SAVINGS; + + @Override + public String toString() { + return name().toString().toLowerCase(); + } + } +} \ No newline at end of file diff --git a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java index c1e7a8951..f00590664 100644 --- a/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java +++ b/mifosng-provider/src/main/java/org/mifosplatform/portfolio/client/service/ClientWritePlatformServiceJpaRepositoryImpl.java @@ -5,7 +5,6 @@ import java.io.IOException; import java.io.InputStream; import org.apache.commons.lang.StringUtils; -import org.mifosng.platform.exceptions.DocumentManagementException; import org.mifosplatform.infrastructure.codes.domain.CodeValue; import org.mifosplatform.infrastructure.codes.domain.CodeValueRepository; import org.mifosplatform.infrastructure.codes.exception.CodeValueNotFoundException; @@ -14,6 +13,7 @@ import org.mifosplatform.infrastructure.core.data.EntityIdentifier; import org.mifosplatform.infrastructure.core.domain.Base64EncodedImage; import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException; import org.mifosplatform.infrastructure.core.service.FileUtils; +import org.mifosplatform.infrastructure.documentmanagement.exception.DocumentManagementException; import org.mifosplatform.infrastructure.office.domain.Office; import org.mifosplatform.infrastructure.office.domain.OfficeRepository; import org.mifosplatform.infrastructure.office.exception.OfficeNotFoundException;